tty: move drivers/serial/ to drivers/tty/serial/
authorGreg Kroah-Hartman <gregkh@suse.de>
Thu, 13 Jan 2011 20:10:18 +0000 (12:10 -0800)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 13 Jan 2011 20:10:18 +0000 (12:10 -0800)
The serial drivers are really just tty drivers, so move them to
drivers/tty/ to make things a bit neater overall.

This is part of the tty/serial driver movement proceedure as proposed by
Arnd Bergmann and approved by everyone involved a number of months ago.

Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Cc: Geert Uytterhoeven <geert@linux-m68k.org>
Cc: Rogier Wolff <R.E.Wolff@bitwizard.nl>
Cc: Michael H. Warfield <mhw@wittsend.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
241 files changed:
drivers/Makefile
drivers/char/Kconfig
drivers/serial/21285.c [deleted file]
drivers/serial/68328serial.c [deleted file]
drivers/serial/68328serial.h [deleted file]
drivers/serial/68360serial.c [deleted file]
drivers/serial/8250.c [deleted file]
drivers/serial/8250.h [deleted file]
drivers/serial/8250_accent.c [deleted file]
drivers/serial/8250_acorn.c [deleted file]
drivers/serial/8250_boca.c [deleted file]
drivers/serial/8250_early.c [deleted file]
drivers/serial/8250_exar_st16c554.c [deleted file]
drivers/serial/8250_fourport.c [deleted file]
drivers/serial/8250_gsc.c [deleted file]
drivers/serial/8250_hp300.c [deleted file]
drivers/serial/8250_hub6.c [deleted file]
drivers/serial/8250_mca.c [deleted file]
drivers/serial/8250_pci.c [deleted file]
drivers/serial/8250_pnp.c [deleted file]
drivers/serial/Kconfig [deleted file]
drivers/serial/Makefile [deleted file]
drivers/serial/altera_jtaguart.c [deleted file]
drivers/serial/altera_uart.c [deleted file]
drivers/serial/amba-pl010.c [deleted file]
drivers/serial/amba-pl011.c [deleted file]
drivers/serial/apbuart.c [deleted file]
drivers/serial/apbuart.h [deleted file]
drivers/serial/atmel_serial.c [deleted file]
drivers/serial/bcm63xx_uart.c [deleted file]
drivers/serial/bfin_5xx.c [deleted file]
drivers/serial/bfin_sport_uart.c [deleted file]
drivers/serial/bfin_sport_uart.h [deleted file]
drivers/serial/clps711x.c [deleted file]
drivers/serial/cpm_uart/Makefile [deleted file]
drivers/serial/cpm_uart/cpm_uart.h [deleted file]
drivers/serial/cpm_uart/cpm_uart_core.c [deleted file]
drivers/serial/cpm_uart/cpm_uart_cpm1.c [deleted file]
drivers/serial/cpm_uart/cpm_uart_cpm1.h [deleted file]
drivers/serial/cpm_uart/cpm_uart_cpm2.c [deleted file]
drivers/serial/cpm_uart/cpm_uart_cpm2.h [deleted file]
drivers/serial/crisv10.c [deleted file]
drivers/serial/crisv10.h [deleted file]
drivers/serial/dz.c [deleted file]
drivers/serial/dz.h [deleted file]
drivers/serial/icom.c [deleted file]
drivers/serial/icom.h [deleted file]
drivers/serial/ifx6x60.c [deleted file]
drivers/serial/ifx6x60.h [deleted file]
drivers/serial/imx.c [deleted file]
drivers/serial/ioc3_serial.c [deleted file]
drivers/serial/ioc4_serial.c [deleted file]
drivers/serial/ip22zilog.c [deleted file]
drivers/serial/ip22zilog.h [deleted file]
drivers/serial/jsm/Makefile [deleted file]
drivers/serial/jsm/jsm.h [deleted file]
drivers/serial/jsm/jsm_driver.c [deleted file]
drivers/serial/jsm/jsm_neo.c [deleted file]
drivers/serial/jsm/jsm_tty.c [deleted file]
drivers/serial/kgdboc.c [deleted file]
drivers/serial/m32r_sio.c [deleted file]
drivers/serial/m32r_sio.h [deleted file]
drivers/serial/m32r_sio_reg.h [deleted file]
drivers/serial/max3100.c [deleted file]
drivers/serial/max3107-aava.c [deleted file]
drivers/serial/max3107.c [deleted file]
drivers/serial/max3107.h [deleted file]
drivers/serial/mcf.c [deleted file]
drivers/serial/mfd.c [deleted file]
drivers/serial/mpc52xx_uart.c [deleted file]
drivers/serial/mpsc.c [deleted file]
drivers/serial/mrst_max3110.c [deleted file]
drivers/serial/mrst_max3110.h [deleted file]
drivers/serial/msm_serial.c [deleted file]
drivers/serial/msm_serial.h [deleted file]
drivers/serial/mux.c [deleted file]
drivers/serial/netx-serial.c [deleted file]
drivers/serial/nwpserial.c [deleted file]
drivers/serial/of_serial.c [deleted file]
drivers/serial/omap-serial.c [deleted file]
drivers/serial/pch_uart.c [deleted file]
drivers/serial/pmac_zilog.c [deleted file]
drivers/serial/pmac_zilog.h [deleted file]
drivers/serial/pnx8xxx_uart.c [deleted file]
drivers/serial/pxa.c [deleted file]
drivers/serial/s3c2400.c [deleted file]
drivers/serial/s3c2410.c [deleted file]
drivers/serial/s3c2412.c [deleted file]
drivers/serial/s3c2440.c [deleted file]
drivers/serial/s3c24a0.c [deleted file]
drivers/serial/s3c6400.c [deleted file]
drivers/serial/s5pv210.c [deleted file]
drivers/serial/sa1100.c [deleted file]
drivers/serial/samsung.c [deleted file]
drivers/serial/samsung.h [deleted file]
drivers/serial/sb1250-duart.c [deleted file]
drivers/serial/sc26xx.c [deleted file]
drivers/serial/serial_core.c [deleted file]
drivers/serial/serial_cs.c [deleted file]
drivers/serial/serial_ks8695.c [deleted file]
drivers/serial/serial_lh7a40x.c [deleted file]
drivers/serial/serial_txx9.c [deleted file]
drivers/serial/sh-sci.c [deleted file]
drivers/serial/sh-sci.h [deleted file]
drivers/serial/sn_console.c [deleted file]
drivers/serial/suncore.c [deleted file]
drivers/serial/suncore.h [deleted file]
drivers/serial/sunhv.c [deleted file]
drivers/serial/sunsab.c [deleted file]
drivers/serial/sunsab.h [deleted file]
drivers/serial/sunsu.c [deleted file]
drivers/serial/sunzilog.c [deleted file]
drivers/serial/sunzilog.h [deleted file]
drivers/serial/timbuart.c [deleted file]
drivers/serial/timbuart.h [deleted file]
drivers/serial/uartlite.c [deleted file]
drivers/serial/ucc_uart.c [deleted file]
drivers/serial/vr41xx_siu.c [deleted file]
drivers/serial/vt8500_serial.c [deleted file]
drivers/serial/zs.c [deleted file]
drivers/serial/zs.h [deleted file]
drivers/tty/Makefile
drivers/tty/serial/21285.c [new file with mode: 0644]
drivers/tty/serial/68328serial.c [new file with mode: 0644]
drivers/tty/serial/68328serial.h [new file with mode: 0644]
drivers/tty/serial/68360serial.c [new file with mode: 0644]
drivers/tty/serial/8250.c [new file with mode: 0644]
drivers/tty/serial/8250.h [new file with mode: 0644]
drivers/tty/serial/8250_accent.c [new file with mode: 0644]
drivers/tty/serial/8250_acorn.c [new file with mode: 0644]
drivers/tty/serial/8250_boca.c [new file with mode: 0644]
drivers/tty/serial/8250_early.c [new file with mode: 0644]
drivers/tty/serial/8250_exar_st16c554.c [new file with mode: 0644]
drivers/tty/serial/8250_fourport.c [new file with mode: 0644]
drivers/tty/serial/8250_gsc.c [new file with mode: 0644]
drivers/tty/serial/8250_hp300.c [new file with mode: 0644]
drivers/tty/serial/8250_hub6.c [new file with mode: 0644]
drivers/tty/serial/8250_mca.c [new file with mode: 0644]
drivers/tty/serial/8250_pci.c [new file with mode: 0644]
drivers/tty/serial/8250_pnp.c [new file with mode: 0644]
drivers/tty/serial/Kconfig [new file with mode: 0644]
drivers/tty/serial/Makefile [new file with mode: 0644]
drivers/tty/serial/altera_jtaguart.c [new file with mode: 0644]
drivers/tty/serial/altera_uart.c [new file with mode: 0644]
drivers/tty/serial/amba-pl010.c [new file with mode: 0644]
drivers/tty/serial/amba-pl011.c [new file with mode: 0644]
drivers/tty/serial/apbuart.c [new file with mode: 0644]
drivers/tty/serial/apbuart.h [new file with mode: 0644]
drivers/tty/serial/atmel_serial.c [new file with mode: 0644]
drivers/tty/serial/bcm63xx_uart.c [new file with mode: 0644]
drivers/tty/serial/bfin_5xx.c [new file with mode: 0644]
drivers/tty/serial/bfin_sport_uart.c [new file with mode: 0644]
drivers/tty/serial/bfin_sport_uart.h [new file with mode: 0644]
drivers/tty/serial/clps711x.c [new file with mode: 0644]
drivers/tty/serial/cpm_uart/Makefile [new file with mode: 0644]
drivers/tty/serial/cpm_uart/cpm_uart.h [new file with mode: 0644]
drivers/tty/serial/cpm_uart/cpm_uart_core.c [new file with mode: 0644]
drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c [new file with mode: 0644]
drivers/tty/serial/cpm_uart/cpm_uart_cpm1.h [new file with mode: 0644]
drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c [new file with mode: 0644]
drivers/tty/serial/cpm_uart/cpm_uart_cpm2.h [new file with mode: 0644]
drivers/tty/serial/crisv10.c [new file with mode: 0644]
drivers/tty/serial/crisv10.h [new file with mode: 0644]
drivers/tty/serial/dz.c [new file with mode: 0644]
drivers/tty/serial/dz.h [new file with mode: 0644]
drivers/tty/serial/icom.c [new file with mode: 0644]
drivers/tty/serial/icom.h [new file with mode: 0644]
drivers/tty/serial/ifx6x60.c [new file with mode: 0644]
drivers/tty/serial/ifx6x60.h [new file with mode: 0644]
drivers/tty/serial/imx.c [new file with mode: 0644]
drivers/tty/serial/ioc3_serial.c [new file with mode: 0644]
drivers/tty/serial/ioc4_serial.c [new file with mode: 0644]
drivers/tty/serial/ip22zilog.c [new file with mode: 0644]
drivers/tty/serial/ip22zilog.h [new file with mode: 0644]
drivers/tty/serial/jsm/Makefile [new file with mode: 0644]
drivers/tty/serial/jsm/jsm.h [new file with mode: 0644]
drivers/tty/serial/jsm/jsm_driver.c [new file with mode: 0644]
drivers/tty/serial/jsm/jsm_neo.c [new file with mode: 0644]
drivers/tty/serial/jsm/jsm_tty.c [new file with mode: 0644]
drivers/tty/serial/kgdboc.c [new file with mode: 0644]
drivers/tty/serial/m32r_sio.c [new file with mode: 0644]
drivers/tty/serial/m32r_sio.h [new file with mode: 0644]
drivers/tty/serial/m32r_sio_reg.h [new file with mode: 0644]
drivers/tty/serial/max3100.c [new file with mode: 0644]
drivers/tty/serial/max3107-aava.c [new file with mode: 0644]
drivers/tty/serial/max3107.c [new file with mode: 0644]
drivers/tty/serial/max3107.h [new file with mode: 0644]
drivers/tty/serial/mcf.c [new file with mode: 0644]
drivers/tty/serial/mfd.c [new file with mode: 0644]
drivers/tty/serial/mpc52xx_uart.c [new file with mode: 0644]
drivers/tty/serial/mpsc.c [new file with mode: 0644]
drivers/tty/serial/mrst_max3110.c [new file with mode: 0644]
drivers/tty/serial/mrst_max3110.h [new file with mode: 0644]
drivers/tty/serial/msm_serial.c [new file with mode: 0644]
drivers/tty/serial/msm_serial.h [new file with mode: 0644]
drivers/tty/serial/mux.c [new file with mode: 0644]
drivers/tty/serial/netx-serial.c [new file with mode: 0644]
drivers/tty/serial/nwpserial.c [new file with mode: 0644]
drivers/tty/serial/of_serial.c [new file with mode: 0644]
drivers/tty/serial/omap-serial.c [new file with mode: 0644]
drivers/tty/serial/pch_uart.c [new file with mode: 0644]
drivers/tty/serial/pmac_zilog.c [new file with mode: 0644]
drivers/tty/serial/pmac_zilog.h [new file with mode: 0644]
drivers/tty/serial/pnx8xxx_uart.c [new file with mode: 0644]
drivers/tty/serial/pxa.c [new file with mode: 0644]
drivers/tty/serial/s3c2400.c [new file with mode: 0644]
drivers/tty/serial/s3c2410.c [new file with mode: 0644]
drivers/tty/serial/s3c2412.c [new file with mode: 0644]
drivers/tty/serial/s3c2440.c [new file with mode: 0644]
drivers/tty/serial/s3c24a0.c [new file with mode: 0644]
drivers/tty/serial/s3c6400.c [new file with mode: 0644]
drivers/tty/serial/s5pv210.c [new file with mode: 0644]
drivers/tty/serial/sa1100.c [new file with mode: 0644]
drivers/tty/serial/samsung.c [new file with mode: 0644]
drivers/tty/serial/samsung.h [new file with mode: 0644]
drivers/tty/serial/sb1250-duart.c [new file with mode: 0644]
drivers/tty/serial/sc26xx.c [new file with mode: 0644]
drivers/tty/serial/serial_core.c [new file with mode: 0644]
drivers/tty/serial/serial_cs.c [new file with mode: 0644]
drivers/tty/serial/serial_ks8695.c [new file with mode: 0644]
drivers/tty/serial/serial_lh7a40x.c [new file with mode: 0644]
drivers/tty/serial/serial_txx9.c [new file with mode: 0644]
drivers/tty/serial/sh-sci.c [new file with mode: 0644]
drivers/tty/serial/sh-sci.h [new file with mode: 0644]
drivers/tty/serial/sn_console.c [new file with mode: 0644]
drivers/tty/serial/suncore.c [new file with mode: 0644]
drivers/tty/serial/suncore.h [new file with mode: 0644]
drivers/tty/serial/sunhv.c [new file with mode: 0644]
drivers/tty/serial/sunsab.c [new file with mode: 0644]
drivers/tty/serial/sunsab.h [new file with mode: 0644]
drivers/tty/serial/sunsu.c [new file with mode: 0644]
drivers/tty/serial/sunzilog.c [new file with mode: 0644]
drivers/tty/serial/sunzilog.h [new file with mode: 0644]
drivers/tty/serial/timbuart.c [new file with mode: 0644]
drivers/tty/serial/timbuart.h [new file with mode: 0644]
drivers/tty/serial/uartlite.c [new file with mode: 0644]
drivers/tty/serial/ucc_uart.c [new file with mode: 0644]
drivers/tty/serial/vr41xx_siu.c [new file with mode: 0644]
drivers/tty/serial/vt8500_serial.c [new file with mode: 0644]
drivers/tty/serial/zs.c [new file with mode: 0644]
drivers/tty/serial/zs.h [new file with mode: 0644]

index ef5132469f587e3204e4f73f11b02b91e19ce9ef..1e2cda18c71814d05952e6bfa1a45027d4bee237 100644 (file)
@@ -24,7 +24,7 @@ obj-$(CONFIG_XEN)             += xen/
 # regulators early, since some subsystems rely on them to initialize
 obj-$(CONFIG_REGULATOR)                += regulator/
 
-# char/ comes before serial/ etc so that the VT console is the boot-time
+# tty/ comes before char/ so that the VT console is the boot-time
 # default.
 obj-y                          += tty/
 obj-y                          += char/
@@ -38,7 +38,6 @@ obj-$(CONFIG_CONNECTOR)               += connector/
 obj-$(CONFIG_FB_I810)           += video/i810/
 obj-$(CONFIG_FB_INTEL)          += video/intelfb/
 
-obj-y                          += serial/
 obj-$(CONFIG_PARPORT)          += parport/
 obj-y                          += base/ block/ misc/ mfd/ nfc/
 obj-$(CONFIG_NUBUS)            += nubus/
index 0f175a866ef026a847d3ed287723423d4f268048..ccac7d09072775afc2254ab40ea80526a56033db 100644 (file)
@@ -426,7 +426,7 @@ config SGI_MBCS
          If you have an SGI Altix with an attached SABrick
          say Y or M here, otherwise say N.
 
-source "drivers/serial/Kconfig"
+source "drivers/tty/serial/Kconfig"
 
 config UNIX98_PTYS
        bool "Unix98 PTY support" if EMBEDDED
diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c
deleted file mode 100644 (file)
index d89aa38..0000000
+++ /dev/null
@@ -1,513 +0,0 @@
-/*
- * linux/drivers/serial/21285.c
- *
- * Driver for the serial port on the 21285 StrongArm-110 core logic chip.
- *
- * Based on drivers/char/serial.c
- */
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/device.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-#include <asm/hardware/dec21285.h>
-#include <mach/hardware.h>
-
-#define BAUD_BASE              (mem_fclk_21285/64)
-
-#define SERIAL_21285_NAME      "ttyFB"
-#define SERIAL_21285_MAJOR     204
-#define SERIAL_21285_MINOR     4
-
-#define RXSTAT_DUMMY_READ      0x80000000
-#define RXSTAT_FRAME           (1 << 0)
-#define RXSTAT_PARITY          (1 << 1)
-#define RXSTAT_OVERRUN         (1 << 2)
-#define RXSTAT_ANYERR          (RXSTAT_FRAME|RXSTAT_PARITY|RXSTAT_OVERRUN)
-
-#define H_UBRLCR_BREAK         (1 << 0)
-#define H_UBRLCR_PARENB                (1 << 1)
-#define H_UBRLCR_PAREVN                (1 << 2)
-#define H_UBRLCR_STOPB         (1 << 3)
-#define H_UBRLCR_FIFO          (1 << 4)
-
-static const char serial21285_name[] = "Footbridge UART";
-
-#define tx_enabled(port)       ((port)->unused[0])
-#define rx_enabled(port)       ((port)->unused[1])
-
-/*
- * The documented expression for selecting the divisor is:
- *  BAUD_BASE / baud - 1
- * However, typically BAUD_BASE is not divisible by baud, so
- * we want to select the divisor that gives us the minimum
- * error.  Therefore, we want:
- *  int(BAUD_BASE / baud - 0.5) ->
- *  int(BAUD_BASE / baud - (baud >> 1) / baud) ->
- *  int((BAUD_BASE - (baud >> 1)) / baud)
- */
-
-static void serial21285_stop_tx(struct uart_port *port)
-{
-       if (tx_enabled(port)) {
-               disable_irq_nosync(IRQ_CONTX);
-               tx_enabled(port) = 0;
-       }
-}
-
-static void serial21285_start_tx(struct uart_port *port)
-{
-       if (!tx_enabled(port)) {
-               enable_irq(IRQ_CONTX);
-               tx_enabled(port) = 1;
-       }
-}
-
-static void serial21285_stop_rx(struct uart_port *port)
-{
-       if (rx_enabled(port)) {
-               disable_irq_nosync(IRQ_CONRX);
-               rx_enabled(port) = 0;
-       }
-}
-
-static void serial21285_enable_ms(struct uart_port *port)
-{
-}
-
-static irqreturn_t serial21285_rx_chars(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       struct tty_struct *tty = port->state->port.tty;
-       unsigned int status, ch, flag, rxs, max_count = 256;
-
-       status = *CSR_UARTFLG;
-       while (!(status & 0x10) && max_count--) {
-               ch = *CSR_UARTDR;
-               flag = TTY_NORMAL;
-               port->icount.rx++;
-
-               rxs = *CSR_RXSTAT | RXSTAT_DUMMY_READ;
-               if (unlikely(rxs & RXSTAT_ANYERR)) {
-                       if (rxs & RXSTAT_PARITY)
-                               port->icount.parity++;
-                       else if (rxs & RXSTAT_FRAME)
-                               port->icount.frame++;
-                       if (rxs & RXSTAT_OVERRUN)
-                               port->icount.overrun++;
-
-                       rxs &= port->read_status_mask;
-
-                       if (rxs & RXSTAT_PARITY)
-                               flag = TTY_PARITY;
-                       else if (rxs & RXSTAT_FRAME)
-                               flag = TTY_FRAME;
-               }
-
-               uart_insert_char(port, rxs, RXSTAT_OVERRUN, ch, flag);
-
-               status = *CSR_UARTFLG;
-       }
-       tty_flip_buffer_push(tty);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t serial21285_tx_chars(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       struct circ_buf *xmit = &port->state->xmit;
-       int count = 256;
-
-       if (port->x_char) {
-               *CSR_UARTDR = port->x_char;
-               port->icount.tx++;
-               port->x_char = 0;
-               goto out;
-       }
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               serial21285_stop_tx(port);
-               goto out;
-       }
-
-       do {
-               *CSR_UARTDR = xmit->buf[xmit->tail];
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (--count > 0 && !(*CSR_UARTFLG & 0x20));
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (uart_circ_empty(xmit))
-               serial21285_stop_tx(port);
-
- out:
-       return IRQ_HANDLED;
-}
-
-static unsigned int serial21285_tx_empty(struct uart_port *port)
-{
-       return (*CSR_UARTFLG & 8) ? 0 : TIOCSER_TEMT;
-}
-
-/* no modem control lines */
-static unsigned int serial21285_get_mctrl(struct uart_port *port)
-{
-       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
-}
-
-static void serial21285_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-}
-
-static void serial21285_break_ctl(struct uart_port *port, int break_state)
-{
-       unsigned long flags;
-       unsigned int h_lcr;
-
-       spin_lock_irqsave(&port->lock, flags);
-       h_lcr = *CSR_H_UBRLCR;
-       if (break_state)
-               h_lcr |= H_UBRLCR_BREAK;
-       else
-               h_lcr &= ~H_UBRLCR_BREAK;
-       *CSR_H_UBRLCR = h_lcr;
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static int serial21285_startup(struct uart_port *port)
-{
-       int ret;
-
-       tx_enabled(port) = 1;
-       rx_enabled(port) = 1;
-
-       ret = request_irq(IRQ_CONRX, serial21285_rx_chars, 0,
-                         serial21285_name, port);
-       if (ret == 0) {
-               ret = request_irq(IRQ_CONTX, serial21285_tx_chars, 0,
-                                 serial21285_name, port);
-               if (ret)
-                       free_irq(IRQ_CONRX, port);
-       }
-
-       return ret;
-}
-
-static void serial21285_shutdown(struct uart_port *port)
-{
-       free_irq(IRQ_CONTX, port);
-       free_irq(IRQ_CONRX, port);
-}
-
-static void
-serial21285_set_termios(struct uart_port *port, struct ktermios *termios,
-                       struct ktermios *old)
-{
-       unsigned long flags;
-       unsigned int baud, quot, h_lcr, b;
-
-       /*
-        * We don't support modem control lines.
-        */
-       termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR);
-       termios->c_cflag |= CLOCAL;
-
-       /*
-        * We don't support BREAK character recognition.
-        */
-       termios->c_iflag &= ~(IGNBRK | BRKINT);
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
-       quot = uart_get_divisor(port, baud);
-       b = port->uartclk / (16 * quot);
-       tty_termios_encode_baud_rate(termios, b, b);
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               h_lcr = 0x00;
-               break;
-       case CS6:
-               h_lcr = 0x20;
-               break;
-       case CS7:
-               h_lcr = 0x40;
-               break;
-       default: /* CS8 */
-               h_lcr = 0x60;
-               break;
-       }
-
-       if (termios->c_cflag & CSTOPB)
-               h_lcr |= H_UBRLCR_STOPB;
-       if (termios->c_cflag & PARENB) {
-               h_lcr |= H_UBRLCR_PARENB;
-               if (!(termios->c_cflag & PARODD))
-                       h_lcr |= H_UBRLCR_PAREVN;
-       }
-
-       if (port->fifosize)
-               h_lcr |= H_UBRLCR_FIFO;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       /*
-        * Which character status flags are we interested in?
-        */
-       port->read_status_mask = RXSTAT_OVERRUN;
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY;
-
-       /*
-        * Which character status flags should we ignore?
-        */
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY;
-       if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= RXSTAT_OVERRUN;
-
-       /*
-        * Ignore all characters if CREAD is not set.
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               port->ignore_status_mask |= RXSTAT_DUMMY_READ;
-
-       quot -= 1;
-
-       *CSR_UARTCON = 0;
-       *CSR_L_UBRLCR = quot & 0xff;
-       *CSR_M_UBRLCR = (quot >> 8) & 0x0f;
-       *CSR_H_UBRLCR = h_lcr;
-       *CSR_UARTCON = 1;
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *serial21285_type(struct uart_port *port)
-{
-       return port->type == PORT_21285 ? "DC21285" : NULL;
-}
-
-static void serial21285_release_port(struct uart_port *port)
-{
-       release_mem_region(port->mapbase, 32);
-}
-
-static int serial21285_request_port(struct uart_port *port)
-{
-       return request_mem_region(port->mapbase, 32, serial21285_name)
-                        != NULL ? 0 : -EBUSY;
-}
-
-static void serial21285_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE && serial21285_request_port(port) == 0)
-               port->type = PORT_21285;
-}
-
-/*
- * verify the new serial_struct (for TIOCSSERIAL).
- */
-static int serial21285_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       int ret = 0;
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_21285)
-               ret = -EINVAL;
-       if (ser->irq != NO_IRQ)
-               ret = -EINVAL;
-       if (ser->baud_base != port->uartclk / 16)
-               ret = -EINVAL;
-       return ret;
-}
-
-static struct uart_ops serial21285_ops = {
-       .tx_empty       = serial21285_tx_empty,
-       .get_mctrl      = serial21285_get_mctrl,
-       .set_mctrl      = serial21285_set_mctrl,
-       .stop_tx        = serial21285_stop_tx,
-       .start_tx       = serial21285_start_tx,
-       .stop_rx        = serial21285_stop_rx,
-       .enable_ms      = serial21285_enable_ms,
-       .break_ctl      = serial21285_break_ctl,
-       .startup        = serial21285_startup,
-       .shutdown       = serial21285_shutdown,
-       .set_termios    = serial21285_set_termios,
-       .type           = serial21285_type,
-       .release_port   = serial21285_release_port,
-       .request_port   = serial21285_request_port,
-       .config_port    = serial21285_config_port,
-       .verify_port    = serial21285_verify_port,
-};
-
-static struct uart_port serial21285_port = {
-       .mapbase        = 0x42000160,
-       .iotype         = UPIO_MEM,
-       .irq            = NO_IRQ,
-       .fifosize       = 16,
-       .ops            = &serial21285_ops,
-       .flags          = UPF_BOOT_AUTOCONF,
-};
-
-static void serial21285_setup_ports(void)
-{
-       serial21285_port.uartclk = mem_fclk_21285 / 4;
-}
-
-#ifdef CONFIG_SERIAL_21285_CONSOLE
-static void serial21285_console_putchar(struct uart_port *port, int ch)
-{
-       while (*CSR_UARTFLG & 0x20)
-               barrier();
-       *CSR_UARTDR = ch;
-}
-
-static void
-serial21285_console_write(struct console *co, const char *s,
-                         unsigned int count)
-{
-       uart_console_write(&serial21285_port, s, count, serial21285_console_putchar);
-}
-
-static void __init
-serial21285_get_options(struct uart_port *port, int *baud,
-                       int *parity, int *bits)
-{
-       if (*CSR_UARTCON == 1) {
-               unsigned int tmp;
-
-               tmp = *CSR_H_UBRLCR;
-               switch (tmp & 0x60) {
-               case 0x00:
-                       *bits = 5;
-                       break;
-               case 0x20:
-                       *bits = 6;
-                       break;
-               case 0x40:
-                       *bits = 7;
-                       break;
-               default:
-               case 0x60:
-                       *bits = 8;
-                       break;
-               }
-
-               if (tmp & H_UBRLCR_PARENB) {
-                       *parity = 'o';
-                       if (tmp & H_UBRLCR_PAREVN)
-                               *parity = 'e';
-               }
-
-               tmp = *CSR_L_UBRLCR | (*CSR_M_UBRLCR << 8);
-
-               *baud = port->uartclk / (16 * (tmp + 1));
-       }
-}
-
-static int __init serial21285_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port = &serial21285_port;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       if (machine_is_personal_server())
-               baud = 57600;
-
-       /*
-        * Check whether an invalid uart number has been specified, and
-        * if so, search for the first available port that does have
-        * console support.
-        */
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               serial21285_get_options(port, &baud, &parity, &bits);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver serial21285_reg;
-
-static struct console serial21285_console =
-{
-       .name           = SERIAL_21285_NAME,
-       .write          = serial21285_console_write,
-       .device         = uart_console_device,
-       .setup          = serial21285_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &serial21285_reg,
-};
-
-static int __init rs285_console_init(void)
-{
-       serial21285_setup_ports();
-       register_console(&serial21285_console);
-       return 0;
-}
-console_initcall(rs285_console_init);
-
-#define SERIAL_21285_CONSOLE   &serial21285_console
-#else
-#define SERIAL_21285_CONSOLE   NULL
-#endif
-
-static struct uart_driver serial21285_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "ttyFB",
-       .dev_name               = "ttyFB",
-       .major                  = SERIAL_21285_MAJOR,
-       .minor                  = SERIAL_21285_MINOR,
-       .nr                     = 1,
-       .cons                   = SERIAL_21285_CONSOLE,
-};
-
-static int __init serial21285_init(void)
-{
-       int ret;
-
-       printk(KERN_INFO "Serial: 21285 driver\n");
-
-       serial21285_setup_ports();
-
-       ret = uart_register_driver(&serial21285_reg);
-       if (ret == 0)
-               uart_add_one_port(&serial21285_reg, &serial21285_port);
-
-       return ret;
-}
-
-static void __exit serial21285_exit(void)
-{
-       uart_remove_one_port(&serial21285_reg, &serial21285_port);
-       uart_unregister_driver(&serial21285_reg);
-}
-
-module_init(serial21285_init);
-module_exit(serial21285_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Intel Footbridge (21285) serial driver");
-MODULE_ALIAS_CHARDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR);
diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c
deleted file mode 100644 (file)
index be0ebce..0000000
+++ /dev/null
@@ -1,1472 +0,0 @@
-/* 68328serial.c: Serial port driver for 68328 microcontroller
- *
- * Copyright (C) 1995       David S. Miller    <davem@caip.rutgers.edu>
- * Copyright (C) 1998       Kenneth Albanowski <kjahds@kjahds.com>
- * Copyright (C) 1998, 1999 D. Jeff Dionne     <jeff@uclinux.org>
- * Copyright (C) 1999       Vladimir Gurevich  <vgurevic@cisco.com>
- * Copyright (C) 2002-2003  David McCullough   <davidm@snapgear.com>
- * Copyright (C) 2002       Greg Ungerer       <gerg@snapgear.com>
- *
- * VZ Support/Fixes             Evan Stawnyczy <e@lineo.ca>
- * Multiple UART support        Daniel Potts <danielp@cse.unsw.edu.au>
- * Power management support     Daniel Potts <danielp@cse.unsw.edu.au>
- * VZ Second Serial Port enable Phil Wilshire
- * 2.4/2.5 port                 David McCullough
- */
-
-#include <asm/dbg.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.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/mm.h>
-#include <linux/kernel.h>
-#include <linux/console.h>
-#include <linux/reboot.h>
-#include <linux/keyboard.h>
-#include <linux/init.h>
-#include <linux/pm.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/gfp.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/delay.h>
-#include <asm/uaccess.h>
-
-/* (es) */
-/* note: perhaps we can murge these files, so that you can just
- *      define 1 of them, and they can sort that out for themselves
- */
-#if defined(CONFIG_M68EZ328)
-#include <asm/MC68EZ328.h>
-#else
-#if defined(CONFIG_M68VZ328)
-#include <asm/MC68VZ328.h>
-#else
-#include <asm/MC68328.h>
-#endif /* CONFIG_M68VZ328 */
-#endif /* CONFIG_M68EZ328 */
-
-#include "68328serial.h"
-
-/* Turn off usage of real serial interrupt code, to "support" Copilot */
-#ifdef CONFIG_XCOPILOT_BUGS
-#undef USE_INTS
-#else
-#define USE_INTS
-#endif
-
-static struct m68k_serial m68k_soft[NR_PORTS];
-
-static unsigned int uart_irqs[NR_PORTS] = UART_IRQ_DEFNS;
-
-/* multiple ports are contiguous in memory */
-m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR;
-
-struct tty_struct m68k_ttys;
-struct m68k_serial *m68k_consinfo = 0;
-
-#define M68K_CLOCK (16667000) /* FIXME: 16MHz is likely wrong */
-
-struct tty_driver *serial_driver;
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
-
-/* Debugging... DEBUG_INTR is bad to use when one of the zs
- * lines is your console ;(
- */
-#undef SERIAL_DEBUG_INTR
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-
-#define RS_ISR_PASS_LIMIT 256
-
-static void change_speed(struct m68k_serial *info);
-
-/*
- *     Setup for console. Argument comes from the boot command line.
- */
-
-/* note: this is messy, but it works, again, perhaps defined somewhere else?*/
-#ifdef CONFIG_M68VZ328
-#define CONSOLE_BAUD_RATE      19200
-#define DEFAULT_CBAUD          B19200
-#endif
-
-
-#ifndef CONSOLE_BAUD_RATE
-#define        CONSOLE_BAUD_RATE       9600
-#define        DEFAULT_CBAUD           B9600
-#endif
-
-
-static int m68328_console_initted = 0;
-static int m68328_console_baud    = CONSOLE_BAUD_RATE;
-static int m68328_console_cbaud   = DEFAULT_CBAUD;
-
-
-static inline int serial_paranoia_check(struct m68k_serial *info,
-                                       char *name, const char *routine)
-{
-#ifdef SERIAL_PARANOIA_CHECK
-       static const char *badmagic =
-               "Warning: bad magic number for serial struct %s in %s\n";
-       static const char *badinfo =
-               "Warning: null m68k_serial for %s in %s\n";
-
-       if (!info) {
-               printk(badinfo, name, routine);
-               return 1;
-       }
-       if (info->magic != SERIAL_MAGIC) {
-               printk(badmagic, name, routine);
-               return 1;
-       }
-#endif
-       return 0;
-}
-
-/*
- * This is used to figure out the divisor speeds and the timeouts
- */
-static int baud_table[] = {
-       0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-       9600, 19200, 38400, 57600, 115200, 0 };
-
-/* Sets or clears DTR/RTS on the requested line */
-static inline void m68k_rtsdtr(struct m68k_serial *ss, int set)
-{
-       if (set) {
-               /* set the RTS/CTS line */
-       } else {
-               /* clear it */
-       }
-       return;
-}
-
-/* Utility routines */
-static inline int get_baud(struct m68k_serial *ss)
-{
-       unsigned long result = 115200;
-       unsigned short int baud = uart_addr[ss->line].ubaud;
-       if (GET_FIELD(baud, UBAUD_PRESCALER) == 0x38) result = 38400;
-       result >>= GET_FIELD(baud, UBAUD_DIVIDE);
-
-       return result;
-}
-
-/*
- * ------------------------------------------------------------
- * rs_stop() and rs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter interrupts, as necessary.
- * ------------------------------------------------------------
- */
-static void rs_stop(struct tty_struct *tty)
-{
-       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-       m68328_uart *uart = &uart_addr[info->line];
-       unsigned long flags;
-
-       if (serial_paranoia_check(info, tty->name, "rs_stop"))
-               return;
-       
-       local_irq_save(flags);
-       uart->ustcnt &= ~USTCNT_TXEN;
-       local_irq_restore(flags);
-}
-
-static int rs_put_char(char ch)
-{
-        int flags, loops = 0;
-
-        local_irq_save(flags);
-
-       while (!(UTX & UTX_TX_AVAIL) && (loops < 1000)) {
-               loops++;
-               udelay(5);
-        }
-
-       UTX_TXDATA = ch;
-        udelay(5);
-        local_irq_restore(flags);
-        return 1;
-}
-
-static void rs_start(struct tty_struct *tty)
-{
-       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-       m68328_uart *uart = &uart_addr[info->line];
-       unsigned long flags;
-       
-       if (serial_paranoia_check(info, tty->name, "rs_start"))
-               return;
-       
-       local_irq_save(flags);
-       if (info->xmit_cnt && info->xmit_buf && !(uart->ustcnt & USTCNT_TXEN)) {
-#ifdef USE_INTS
-               uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK;
-#else
-               uart->ustcnt |= USTCNT_TXEN;
-#endif
-       }
-       local_irq_restore(flags);
-}
-
-/* Drop into either the boot monitor or kadb upon receiving a break
- * from keyboard/console input.
- */
-static void batten_down_hatches(void)
-{
-       /* Drop into the debugger */
-}
-
-static void status_handle(struct m68k_serial *info, unsigned short status)
-{
-#if 0
-       if(status & DCD) {
-               if((info->port.tty->termios->c_cflag & CRTSCTS) &&
-                  ((info->curregs[3] & AUTO_ENAB)==0)) {
-                       info->curregs[3] |= AUTO_ENAB;
-                       info->pendregs[3] |= AUTO_ENAB;
-                       write_zsreg(info->m68k_channel, 3, info->curregs[3]);
-               }
-       } else {
-               if((info->curregs[3] & AUTO_ENAB)) {
-                       info->curregs[3] &= ~AUTO_ENAB;
-                       info->pendregs[3] &= ~AUTO_ENAB;
-                       write_zsreg(info->m68k_channel, 3, info->curregs[3]);
-               }
-       }
-#endif
-       /* If this is console input and this is a
-        * 'break asserted' status change interrupt
-        * see if we can drop into the debugger
-        */
-       if((status & URX_BREAK) && info->break_abort)
-               batten_down_hatches();
-       return;
-}
-
-static void receive_chars(struct m68k_serial *info, unsigned short rx)
-{
-       struct tty_struct *tty = info->port.tty;
-       m68328_uart *uart = &uart_addr[info->line];
-       unsigned char ch, flag;
-
-       /*
-        * This do { } while() loop will get ALL chars out of Rx FIFO 
-         */
-#ifndef CONFIG_XCOPILOT_BUGS
-       do {
-#endif 
-               ch = GET_FIELD(rx, URX_RXDATA);
-       
-               if(info->is_cons) {
-                       if(URX_BREAK & rx) { /* whee, break received */
-                               status_handle(info, rx);
-                               return;
-#ifdef CONFIG_MAGIC_SYSRQ
-                       } else if (ch == 0x10) { /* ^P */
-                               show_state();
-                               show_free_areas();
-                               show_buffers();
-/*                             show_net_buffers(); */
-                               return;
-                       } else if (ch == 0x12) { /* ^R */
-                               emergency_restart();
-                               return;
-#endif /* CONFIG_MAGIC_SYSRQ */
-                       }
-               }
-
-               if(!tty)
-                       goto clear_and_exit;
-               
-               flag = TTY_NORMAL;
-
-               if(rx & URX_PARITY_ERROR) {
-                       flag = TTY_PARITY;
-                       status_handle(info, rx);
-               } else if(rx & URX_OVRUN) {
-                       flag = TTY_OVERRUN;
-                       status_handle(info, rx);
-               } else if(rx & URX_FRAME_ERROR) {
-                       flag = TTY_FRAME;
-                       status_handle(info, rx);
-               }
-               tty_insert_flip_char(tty, ch, flag);
-#ifndef CONFIG_XCOPILOT_BUGS
-       } while((rx = uart->urx.w) & URX_DATA_READY);
-#endif
-
-       tty_schedule_flip(tty);
-
-clear_and_exit:
-       return;
-}
-
-static void transmit_chars(struct m68k_serial *info)
-{
-       m68328_uart *uart = &uart_addr[info->line];
-
-       if (info->x_char) {
-               /* Send next char */
-               uart->utx.b.txdata = info->x_char;
-               info->x_char = 0;
-               goto clear_and_return;
-       }
-
-       if((info->xmit_cnt <= 0) || info->port.tty->stopped) {
-               /* That's peculiar... TX ints off */
-               uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
-               goto clear_and_return;
-       }
-
-       /* Send char */
-       uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
-       info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
-       info->xmit_cnt--;
-
-       if (info->xmit_cnt < WAKEUP_CHARS)
-               schedule_work(&info->tqueue);
-
-       if(info->xmit_cnt <= 0) {
-               /* All done for now... TX ints off */
-               uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
-               goto clear_and_return;
-       }
-
-clear_and_return:
-       /* Clear interrupt (should be auto)*/
-       return;
-}
-
-/*
- * This is the serial driver's generic interrupt routine
- */
-irqreturn_t rs_interrupt(int irq, void *dev_id)
-{
-       struct m68k_serial *info = dev_id;
-       m68328_uart *uart;
-       unsigned short rx;
-       unsigned short tx;
-
-       uart = &uart_addr[info->line];
-       rx = uart->urx.w;
-
-#ifdef USE_INTS
-       tx = uart->utx.w;
-
-       if (rx & URX_DATA_READY) receive_chars(info, rx);
-       if (tx & UTX_TX_AVAIL)   transmit_chars(info);
-#else
-       receive_chars(info, rx);                
-#endif
-       return IRQ_HANDLED;
-}
-
-static void do_softint(struct work_struct *work)
-{
-       struct m68k_serial      *info = container_of(work, struct m68k_serial, tqueue);
-       struct tty_struct       *tty;
-       
-       tty = info->port.tty;
-       if (!tty)
-               return;
-#if 0
-       if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
-               tty_wakeup(tty);
-       }
-#endif   
-}
-
-/*
- * This routine is called from the scheduler tqueue when the interrupt
- * routine has signalled that a hangup has occurred.  The path of
- * hangup processing is:
- *
- *     serial interrupt routine -> (scheduler tqueue) ->
- *     do_serial_hangup() -> tty->hangup() -> rs_hangup()
- * 
- */
-static void do_serial_hangup(struct work_struct *work)
-{
-       struct m68k_serial      *info = container_of(work, struct m68k_serial, tqueue_hangup);
-       struct tty_struct       *tty;
-       
-       tty = info->port.tty;
-       if (!tty)
-               return;
-
-       tty_hangup(tty);
-}
-
-
-static int startup(struct m68k_serial * info)
-{
-       m68328_uart *uart = &uart_addr[info->line];
-       unsigned long flags;
-       
-       if (info->flags & S_INITIALIZED)
-               return 0;
-
-       if (!info->xmit_buf) {
-               info->xmit_buf = (unsigned char *) __get_free_page(GFP_KERNEL);
-               if (!info->xmit_buf)
-                       return -ENOMEM;
-       }
-
-       local_irq_save(flags);
-
-       /*
-        * Clear the FIFO buffers and disable them
-        * (they will be reenabled in change_speed())
-        */
-
-       uart->ustcnt = USTCNT_UEN;
-       info->xmit_fifo_size = 1;
-       uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_TXEN;
-       (void)uart->urx.w;
-
-       /*
-        * Finally, enable sequencing and interrupts
-        */
-#ifdef USE_INTS
-       uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | 
-                 USTCNT_RX_INTR_MASK | USTCNT_TX_INTR_MASK;
-#else
-       uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK;
-#endif
-
-       if (info->port.tty)
-               clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
-       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
-       /*
-        * and set the speed of the serial port
-        */
-
-       change_speed(info);
-
-       info->flags |= S_INITIALIZED;
-       local_irq_restore(flags);
-       return 0;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void shutdown(struct m68k_serial * info)
-{
-       m68328_uart *uart = &uart_addr[info->line];
-       unsigned long   flags;
-
-       uart->ustcnt = 0; /* All off! */
-       if (!(info->flags & S_INITIALIZED))
-               return;
-
-       local_irq_save(flags);
-       
-       if (info->xmit_buf) {
-               free_page((unsigned long) info->xmit_buf);
-               info->xmit_buf = 0;
-       }
-
-       if (info->port.tty)
-               set_bit(TTY_IO_ERROR, &info->port.tty->flags);
-       
-       info->flags &= ~S_INITIALIZED;
-       local_irq_restore(flags);
-}
-
-struct {
-       int divisor, prescale;
-}
-#ifndef CONFIG_M68VZ328
- hw_baud_table[18] = {
-       {0,0}, /* 0 */
-       {0,0}, /* 50 */
-       {0,0}, /* 75 */
-       {0,0}, /* 110 */
-       {0,0}, /* 134 */
-       {0,0}, /* 150 */
-       {0,0}, /* 200 */
-       {7,0x26}, /* 300 */
-       {6,0x26}, /* 600 */
-       {5,0x26}, /* 1200 */
-       {0,0}, /* 1800 */
-       {4,0x26}, /* 2400 */
-       {3,0x26}, /* 4800 */
-       {2,0x26}, /* 9600 */
-       {1,0x26}, /* 19200 */
-       {0,0x26}, /* 38400 */
-       {1,0x38}, /* 57600 */
-       {0,0x38}, /* 115200 */
-};
-#else
- hw_baud_table[18] = {
-                 {0,0}, /* 0 */
-                 {0,0}, /* 50 */
-                 {0,0}, /* 75 */
-                 {0,0}, /* 110 */
-                 {0,0}, /* 134 */
-                 {0,0}, /* 150 */
-                 {0,0}, /* 200 */
-                 {0,0}, /* 300 */
-                 {7,0x26}, /* 600 */
-                 {6,0x26}, /* 1200 */
-                 {0,0}, /* 1800 */
-                 {5,0x26}, /* 2400 */
-                 {4,0x26}, /* 4800 */
-                 {3,0x26}, /* 9600 */
-                 {2,0x26}, /* 19200 */
-                 {1,0x26}, /* 38400 */
-                 {0,0x26}, /* 57600 */
-                 {1,0x38}, /* 115200 */
-}; 
-#endif
-/* rate = 1036800 / ((65 - prescale) * (1<<divider)) */
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void change_speed(struct m68k_serial *info)
-{
-       m68328_uart *uart = &uart_addr[info->line];
-       unsigned short port;
-       unsigned short ustcnt;
-       unsigned cflag;
-       int     i;
-
-       if (!info->port.tty || !info->port.tty->termios)
-               return;
-       cflag = info->port.tty->termios->c_cflag;
-       if (!(port = info->port))
-               return;
-
-       ustcnt = uart->ustcnt;
-       uart->ustcnt = ustcnt & ~USTCNT_TXEN;
-
-       i = cflag & CBAUD;
-        if (i & CBAUDEX) {
-                i = (i & ~CBAUDEX) + B38400;
-        }
-
-       info->baud = baud_table[i];
-       uart->ubaud = PUT_FIELD(UBAUD_DIVIDE,    hw_baud_table[i].divisor) | 
-               PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale);
-
-       ustcnt &= ~(USTCNT_PARITYEN | USTCNT_ODD_EVEN | USTCNT_STOP | USTCNT_8_7);
-       
-       if ((cflag & CSIZE) == CS8)
-               ustcnt |= USTCNT_8_7;
-               
-       if (cflag & CSTOPB)
-               ustcnt |= USTCNT_STOP;
-
-       if (cflag & PARENB)
-               ustcnt |= USTCNT_PARITYEN;
-       if (cflag & PARODD)
-               ustcnt |= USTCNT_ODD_EVEN;
-       
-#ifdef CONFIG_SERIAL_68328_RTS_CTS
-       if (cflag & CRTSCTS) {
-               uart->utx.w &= ~ UTX_NOCTS;
-       } else {
-               uart->utx.w |= UTX_NOCTS;
-       }
-#endif
-
-       ustcnt |= USTCNT_TXEN;
-       
-       uart->ustcnt = ustcnt;
-       return;
-}
-
-/*
- * Fair output driver allows a process to speak.
- */
-static void rs_fair_output(void)
-{
-       int left;               /* Output no more than that */
-       unsigned long flags;
-       struct m68k_serial *info = &m68k_soft[0];
-       char c;
-
-       if (info == 0) return;
-       if (info->xmit_buf == 0) return;
-
-       local_irq_save(flags);
-       left = info->xmit_cnt;
-       while (left != 0) {
-               c = info->xmit_buf[info->xmit_tail];
-               info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
-               info->xmit_cnt--;
-               local_irq_restore(flags);
-
-               rs_put_char(c);
-
-               local_irq_save(flags);
-               left = min(info->xmit_cnt, left-1);
-       }
-
-       /* Last character is being transmitted now (hopefully). */
-       udelay(5);
-
-       local_irq_restore(flags);
-       return;
-}
-
-/*
- * m68k_console_print is registered for printk.
- */
-void console_print_68328(const char *p)
-{
-       char c;
-       
-       while((c=*(p++)) != 0) {
-               if(c == '\n')
-                       rs_put_char('\r');
-               rs_put_char(c);
-       }
-
-       /* Comment this if you want to have a strict interrupt-driven output */
-       rs_fair_output();
-
-       return;
-}
-
-static void rs_set_ldisc(struct tty_struct *tty)
-{
-       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-
-       if (serial_paranoia_check(info, tty->name, "rs_set_ldisc"))
-               return;
-
-       info->is_cons = (tty->termios->c_line == N_TTY);
-       
-       printk("ttyS%d console mode %s\n", info->line, info->is_cons ? "on" : "off");
-}
-
-static void rs_flush_chars(struct tty_struct *tty)
-{
-       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-       m68328_uart *uart = &uart_addr[info->line];
-       unsigned long flags;
-
-       if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
-               return;
-#ifndef USE_INTS
-       for(;;) {
-#endif
-
-       /* Enable transmitter */
-       local_irq_save(flags);
-
-       if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
-                       !info->xmit_buf) {
-               local_irq_restore(flags);
-               return;
-       }
-
-#ifdef USE_INTS
-       uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK;
-#else
-       uart->ustcnt |= USTCNT_TXEN;
-#endif
-
-#ifdef USE_INTS
-       if (uart->utx.w & UTX_TX_AVAIL) {
-#else
-       if (1) {
-#endif
-               /* Send char */
-               uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
-               info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
-               info->xmit_cnt--;
-       }
-
-#ifndef USE_INTS
-       while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5);
-       }
-#endif
-       local_irq_restore(flags);
-}
-
-extern void console_printn(const char * b, int count);
-
-static int rs_write(struct tty_struct * tty,
-                   const unsigned char *buf, int count)
-{
-       int     c, total = 0;
-       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-       m68328_uart *uart = &uart_addr[info->line];
-       unsigned long flags;
-
-       if (serial_paranoia_check(info, tty->name, "rs_write"))
-               return 0;
-
-       if (!tty || !info->xmit_buf)
-               return 0;
-
-       local_save_flags(flags);
-       while (1) {
-               local_irq_disable();            
-               c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-                                  SERIAL_XMIT_SIZE - info->xmit_head));
-               local_irq_restore(flags);
-
-               if (c <= 0)
-                       break;
-
-               memcpy(info->xmit_buf + info->xmit_head, buf, c);
-
-               local_irq_disable();
-               info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
-               info->xmit_cnt += c;
-               local_irq_restore(flags);
-               buf += c;
-               count -= c;
-               total += c;
-       }
-
-       if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
-               /* Enable transmitter */
-               local_irq_disable();            
-#ifndef USE_INTS
-               while(info->xmit_cnt) {
-#endif
-
-               uart->ustcnt |= USTCNT_TXEN;
-#ifdef USE_INTS
-               uart->ustcnt |= USTCNT_TX_INTR_MASK;
-#else
-               while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5);
-#endif
-               if (uart->utx.w & UTX_TX_AVAIL) {
-                       uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
-                       info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
-                       info->xmit_cnt--;
-               }
-
-#ifndef USE_INTS
-               }
-#endif
-               local_irq_restore(flags);
-       }
-
-       return total;
-}
-
-static int rs_write_room(struct tty_struct *tty)
-{
-       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-       int     ret;
-                               
-       if (serial_paranoia_check(info, tty->name, "rs_write_room"))
-               return 0;
-       ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
-       if (ret < 0)
-               ret = 0;
-       return ret;
-}
-
-static int rs_chars_in_buffer(struct tty_struct *tty)
-{
-       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-                               
-       if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
-               return 0;
-       return info->xmit_cnt;
-}
-
-static void rs_flush_buffer(struct tty_struct *tty)
-{
-       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-       unsigned long flags;
-                               
-       if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
-               return;
-       local_irq_save(flags);
-       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-       local_irq_restore(flags);
-       tty_wakeup(tty);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_throttle()
- * 
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void rs_throttle(struct tty_struct * tty)
-{
-       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-
-       if (serial_paranoia_check(info, tty->name, "rs_throttle"))
-               return;
-       
-       if (I_IXOFF(tty))
-               info->x_char = STOP_CHAR(tty);
-
-       /* Turn off RTS line (do this atomic) */
-}
-
-static void rs_unthrottle(struct tty_struct * tty)
-{
-       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-
-       if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
-               return;
-       
-       if (I_IXOFF(tty)) {
-               if (info->x_char)
-                       info->x_char = 0;
-               else
-                       info->x_char = START_CHAR(tty);
-       }
-
-       /* Assert RTS line (do this atomic) */
-}
-
-/*
- * ------------------------------------------------------------
- * rs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-static int get_serial_info(struct m68k_serial * info,
-                          struct serial_struct * retinfo)
-{
-       struct serial_struct tmp;
-  
-       if (!retinfo)
-               return -EFAULT;
-       memset(&tmp, 0, sizeof(tmp));
-       tmp.type = info->type;
-       tmp.line = info->line;
-       tmp.port = info->port;
-       tmp.irq = info->irq;
-       tmp.flags = info->flags;
-       tmp.baud_base = info->baud_base;
-       tmp.close_delay = info->close_delay;
-       tmp.closing_wait = info->closing_wait;
-       tmp.custom_divisor = info->custom_divisor;
-       if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int set_serial_info(struct m68k_serial * info,
-                          struct serial_struct * new_info)
-{
-       struct serial_struct new_serial;
-       struct m68k_serial old_info;
-       int                     retval = 0;
-
-       if (!new_info)
-               return -EFAULT;
-       if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
-               return -EFAULT;
-       old_info = *info;
-
-       if (!capable(CAP_SYS_ADMIN)) {
-               if ((new_serial.baud_base != info->baud_base) ||
-                   (new_serial.type != info->type) ||
-                   (new_serial.close_delay != info->close_delay) ||
-                   ((new_serial.flags & ~S_USR_MASK) !=
-                    (info->flags & ~S_USR_MASK)))
-                       return -EPERM;
-               info->flags = ((info->flags & ~S_USR_MASK) |
-                              (new_serial.flags & S_USR_MASK));
-               info->custom_divisor = new_serial.custom_divisor;
-               goto check_and_exit;
-       }
-
-       if (info->count > 1)
-               return -EBUSY;
-
-       /*
-        * OK, past this point, all the error checking has been done.
-        * At this point, we start making changes.....
-        */
-
-       info->baud_base = new_serial.baud_base;
-       info->flags = ((info->flags & ~S_FLAGS) |
-                       (new_serial.flags & S_FLAGS));
-       info->type = new_serial.type;
-       info->close_delay = new_serial.close_delay;
-       info->closing_wait = new_serial.closing_wait;
-
-check_and_exit:
-       retval = startup(info);
-       return retval;
-}
-
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- *         is emptied.  On bus types like RS485, the transmitter must
- *         release the bus after transmitting. This must be done when
- *         the transmit shift register is empty, not be done when the
- *         transmit holding register is empty.  This functionality
- *         allows an RS485 driver to be written in user space. 
- */
-static int get_lsr_info(struct m68k_serial * info, unsigned int *value)
-{
-#ifdef CONFIG_SERIAL_68328_RTS_CTS
-       m68328_uart *uart = &uart_addr[info->line];
-#endif
-       unsigned char status;
-       unsigned long flags;
-
-       local_irq_save(flags);
-#ifdef CONFIG_SERIAL_68328_RTS_CTS
-       status = (uart->utx.w & UTX_CTS_STAT) ? 1 : 0;
-#else
-       status = 0;
-#endif
-       local_irq_restore(flags);
-       return put_user(status, value);
-}
-
-/*
- * This routine sends a break character out the serial port.
- */
-static void send_break(struct m68k_serial * info, unsigned int duration)
-{
-       m68328_uart *uart = &uart_addr[info->line];
-        unsigned long flags;
-        if (!info->port)
-                return;
-        local_irq_save(flags);
-#ifdef USE_INTS        
-       uart->utx.w |= UTX_SEND_BREAK;
-       msleep_interruptible(duration);
-       uart->utx.w &= ~UTX_SEND_BREAK;
-#endif         
-        local_irq_restore(flags);
-}
-
-static int rs_ioctl(struct tty_struct *tty, struct file * file,
-                   unsigned int cmd, unsigned long arg)
-{
-       int error;
-       struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
-       int retval;
-
-       if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
-               return -ENODEV;
-
-       if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
-           (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
-           (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
-               if (tty->flags & (1 << TTY_IO_ERROR))
-                   return -EIO;
-       }
-       
-       switch (cmd) {
-               case TCSBRK:    /* SVID version: non-zero arg --> no break */
-                       retval = tty_check_change(tty);
-                       if (retval)
-                               return retval;
-                       tty_wait_until_sent(tty, 0);
-                       if (!arg)
-                               send_break(info, 250);  /* 1/4 second */
-                       return 0;
-               case TCSBRKP:   /* support for POSIX tcsendbreak() */
-                       retval = tty_check_change(tty);
-                       if (retval)
-                               return retval;
-                       tty_wait_until_sent(tty, 0);
-                       send_break(info, arg ? arg*(100) : 250);
-                       return 0;
-               case TIOCGSERIAL:
-                       return get_serial_info(info,
-                                      (struct serial_struct *) arg);
-               case TIOCSSERIAL:
-                       return set_serial_info(info,
-                                              (struct serial_struct *) arg);
-               case TIOCSERGETLSR: /* Get line status register */
-                       return get_lsr_info(info, (unsigned int *) arg);
-               case TIOCSERGSTRUCT:
-                       if (copy_to_user((struct m68k_serial *) arg,
-                                   info, sizeof(struct m68k_serial)))
-                               return -EFAULT;
-                       return 0;
-               default:
-                       return -ENOIOCTLCMD;
-               }
-       return 0;
-}
-
-static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
-       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-
-       change_speed(info);
-
-       if ((old_termios->c_cflag & CRTSCTS) &&
-           !(tty->termios->c_cflag & CRTSCTS)) {
-               tty->hw_stopped = 0;
-               rs_start(tty);
-       }
-       
-}
-
-/*
- * ------------------------------------------------------------
- * rs_close()
- * 
- * This routine is called when the serial port gets closed.  First, we
- * wait for the last remaining data to be sent.  Then, we unlink its
- * S structure from the interrupt chain if necessary, and we free
- * that IRQ if nothing is left in the chain.
- * ------------------------------------------------------------
- */
-static void rs_close(struct tty_struct *tty, struct file * filp)
-{
-       struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
-       m68328_uart *uart = &uart_addr[info->line];
-       unsigned long flags;
-
-       if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
-               return;
-       
-       local_irq_save(flags);
-       
-       if (tty_hung_up_p(filp)) {
-               local_irq_restore(flags);
-               return;
-       }
-       
-       if ((tty->count == 1) && (info->count != 1)) {
-               /*
-                * Uh, oh.  tty->count is 1, which means that the tty
-                * structure will be freed.  Info->count should always
-                * be one in these conditions.  If it's greater than
-                * one, we've got real problems, since it means the
-                * serial port won't be shutdown.
-                */
-               printk("rs_close: bad serial port count; tty->count is 1, "
-                      "info->count is %d\n", info->count);
-               info->count = 1;
-       }
-       if (--info->count < 0) {
-               printk("rs_close: bad serial port count for ttyS%d: %d\n",
-                      info->line, info->count);
-               info->count = 0;
-       }
-       if (info->count) {
-               local_irq_restore(flags);
-               return;
-       }
-       info->flags |= S_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 (info->closing_wait != S_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, info->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.
-        */
-
-       uart->ustcnt &= ~USTCNT_RXEN;
-       uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK);
-
-       shutdown(info);
-       rs_flush_buffer(tty);
-               
-       tty_ldisc_flush(tty);
-       tty->closing = 0;
-       info->event = 0;
-       info->port.tty = NULL;
-#warning "This is not and has never been valid so fix it"      
-#if 0
-       if (tty->ldisc.num != ldiscs[N_TTY].num) {
-               if (tty->ldisc.close)
-                       (tty->ldisc.close)(tty);
-               tty->ldisc = ldiscs[N_TTY];
-               tty->termios->c_line = N_TTY;
-               if (tty->ldisc.open)
-                       (tty->ldisc.open)(tty);
-       }
-#endif 
-       if (info->blocked_open) {
-               if (info->close_delay) {
-                       msleep_interruptible(jiffies_to_msecs(info->close_delay));
-               }
-               wake_up_interruptible(&info->open_wait);
-       }
-       info->flags &= ~(S_NORMAL_ACTIVE|S_CLOSING);
-       wake_up_interruptible(&info->close_wait);
-       local_irq_restore(flags);
-}
-
-/*
- * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-void rs_hangup(struct tty_struct *tty)
-{
-       struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
-       
-       if (serial_paranoia_check(info, tty->name, "rs_hangup"))
-               return;
-       
-       rs_flush_buffer(tty);
-       shutdown(info);
-       info->event = 0;
-       info->count = 0;
-       info->flags &= ~S_NORMAL_ACTIVE;
-       info->port.tty = NULL;
-       wake_up_interruptible(&info->open_wait);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_open() and friends
- * ------------------------------------------------------------
- */
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
-                          struct m68k_serial *info)
-{
-       DECLARE_WAITQUEUE(wait, current);
-       int             retval;
-       int             do_clocal = 0;
-
-       /*
-        * If the device is in the middle of being closed, then block
-        * until it's done, and then try again.
-        */
-       if (info->flags & S_CLOSING) {
-               interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
-               if (info->flags & S_HUP_NOTIFY)
-                       return -EAGAIN;
-               else
-                       return -ERESTARTSYS;
-#else
-               return -EAGAIN;
-#endif
-       }
-       
-       /*
-        * 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))) {
-               info->flags |= S_NORMAL_ACTIVE;
-               return 0;
-       }
-
-       if (tty->termios->c_cflag & CLOCAL)
-               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, info->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(&info->open_wait, &wait);
-
-       info->count--;
-       info->blocked_open++;
-       while (1) {
-               local_irq_disable();
-               m68k_rtsdtr(info, 1);
-               local_irq_enable();
-               current->state = TASK_INTERRUPTIBLE;
-               if (tty_hung_up_p(filp) ||
-                   !(info->flags & S_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
-                       if (info->flags & S_HUP_NOTIFY)
-                               retval = -EAGAIN;
-                       else
-                               retval = -ERESTARTSYS;  
-#else
-                       retval = -EAGAIN;
-#endif
-                       break;
-               }
-               if (!(info->flags & S_CLOSING) && do_clocal)
-                       break;
-                if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-               tty_unlock();
-               schedule();
-               tty_lock();
-       }
-       current->state = TASK_RUNNING;
-       remove_wait_queue(&info->open_wait, &wait);
-       if (!tty_hung_up_p(filp))
-               info->count++;
-       info->blocked_open--;
-
-       if (retval)
-               return retval;
-       info->flags |= S_NORMAL_ACTIVE;
-       return 0;
-}      
-
-/*
- * This routine is called whenever a serial port is opened.  It
- * enables interrupts for a serial port, linking in its S structure into
- * the IRQ chain.   It also performs the serial-specific
- * initialization for the tty structure.
- */
-int rs_open(struct tty_struct *tty, struct file * filp)
-{
-       struct m68k_serial      *info;
-       int                     retval, line;
-
-       line = tty->index;
-       
-       if (line >= NR_PORTS || line < 0) /* we have exactly one */
-               return -ENODEV;
-
-       info = &m68k_soft[line];
-
-       if (serial_paranoia_check(info, tty->name, "rs_open"))
-               return -ENODEV;
-
-       info->count++;
-       tty->driver_data = info;
-       info->port.tty = tty;
-
-       /*
-        * Start up serial port
-        */
-       retval = startup(info);
-       if (retval)
-               return retval;
-
-       return block_til_ready(tty, filp, info);
-}
-
-/* Finally, routines used to initialize the serial driver. */
-
-static void show_serial_version(void)
-{
-       printk("MC68328 serial driver version 1.00\n");
-}
-
-static const struct tty_operations rs_ops = {
-       .open = rs_open,
-       .close = rs_close,
-       .write = rs_write,
-       .flush_chars = rs_flush_chars,
-       .write_room = rs_write_room,
-       .chars_in_buffer = rs_chars_in_buffer,
-       .flush_buffer = rs_flush_buffer,
-       .ioctl = rs_ioctl,
-       .throttle = rs_throttle,
-       .unthrottle = rs_unthrottle,
-       .set_termios = rs_set_termios,
-       .stop = rs_stop,
-       .start = rs_start,
-       .hangup = rs_hangup,
-       .set_ldisc = rs_set_ldisc,
-};
-
-/* rs_init inits the driver */
-static int __init
-rs68328_init(void)
-{
-       int flags, i;
-       struct m68k_serial *info;
-
-       serial_driver = alloc_tty_driver(NR_PORTS);
-       if (!serial_driver)
-               return -ENOMEM;
-
-       show_serial_version();
-
-       /* Initialize the tty_driver structure */
-       /* SPARC: Not all of this is exactly right for us. */
-       
-       serial_driver->name = "ttyS";
-       serial_driver->major = TTY_MAJOR;
-       serial_driver->minor_start = 64;
-       serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
-       serial_driver->subtype = SERIAL_TYPE_NORMAL;
-       serial_driver->init_termios = tty_std_termios;
-       serial_driver->init_termios.c_cflag = 
-                       m68328_console_cbaud | CS8 | CREAD | HUPCL | CLOCAL;
-       serial_driver->flags = TTY_DRIVER_REAL_RAW;
-       tty_set_operations(serial_driver, &rs_ops);
-
-       if (tty_register_driver(serial_driver)) {
-               put_tty_driver(serial_driver);
-               printk(KERN_ERR "Couldn't register serial driver\n");
-               return -ENOMEM;
-       }
-
-       local_irq_save(flags);
-
-       for(i=0;i<NR_PORTS;i++) {
-
-           info = &m68k_soft[i];
-           info->magic = SERIAL_MAGIC;
-           info->port = (int) &uart_addr[i];
-           info->port.tty = NULL;
-           info->irq = uart_irqs[i];
-           info->custom_divisor = 16;
-           info->close_delay = 50;
-           info->closing_wait = 3000;
-           info->x_char = 0;
-           info->event = 0;
-           info->count = 0;
-           info->blocked_open = 0;
-           INIT_WORK(&info->tqueue, do_softint);
-           INIT_WORK(&info->tqueue_hangup, do_serial_hangup);
-           init_waitqueue_head(&info->open_wait);
-           init_waitqueue_head(&info->close_wait);
-           info->line = i;
-           info->is_cons = 1; /* Means shortcuts work */
-           
-           printk("%s%d at 0x%08x (irq = %d)", serial_driver->name, info->line, 
-                  info->port, info->irq);
-           printk(" is a builtin MC68328 UART\n");
-           
-#ifdef CONFIG_M68VZ328
-               if (i > 0 )
-                       PJSEL &= 0xCF;  /* PSW enable second port output */
-#endif
-
-           if (request_irq(uart_irqs[i],
-                           rs_interrupt,
-                           IRQF_DISABLED,
-                           "M68328_UART", info))
-                panic("Unable to attach 68328 serial interrupt\n");
-       }
-       local_irq_restore(flags);
-       return 0;
-}
-
-module_init(rs68328_init);
-
-
-
-static void m68328_set_baud(void)
-{
-       unsigned short ustcnt;
-       int     i;
-
-       ustcnt = USTCNT;
-       USTCNT = ustcnt & ~USTCNT_TXEN;
-
-again:
-       for (i = 0; i < ARRAY_SIZE(baud_table); i++)
-               if (baud_table[i] == m68328_console_baud)
-                       break;
-       if (i >= ARRAY_SIZE(baud_table)) {
-               m68328_console_baud = 9600;
-               goto again;
-       }
-
-       UBAUD = PUT_FIELD(UBAUD_DIVIDE,    hw_baud_table[i].divisor) | 
-               PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale);
-       ustcnt &= ~(USTCNT_PARITYEN | USTCNT_ODD_EVEN | USTCNT_STOP | USTCNT_8_7);
-       ustcnt |= USTCNT_8_7;
-       ustcnt |= USTCNT_TXEN;
-       USTCNT = ustcnt;
-       m68328_console_initted = 1;
-       return;
-}
-
-
-int m68328_console_setup(struct console *cp, char *arg)
-{
-       int             i, n = CONSOLE_BAUD_RATE;
-
-       if (!cp)
-               return(-1);
-
-       if (arg)
-               n = simple_strtoul(arg,NULL,0);
-
-       for (i = 0; i < ARRAY_SIZE(baud_table); i++)
-               if (baud_table[i] == n)
-                       break;
-       if (i < ARRAY_SIZE(baud_table)) {
-               m68328_console_baud = n;
-               m68328_console_cbaud = 0;
-               if (i > 15) {
-                       m68328_console_cbaud |= CBAUDEX;
-                       i -= 15;
-               }
-               m68328_console_cbaud |= i;
-       }
-
-       m68328_set_baud(); /* make sure baud rate changes */
-       return(0);
-}
-
-
-static struct tty_driver *m68328_console_device(struct console *c, int *index)
-{
-       *index = c->index;
-       return serial_driver;
-}
-
-
-void m68328_console_write (struct console *co, const char *str,
-                          unsigned int count)
-{
-       if (!m68328_console_initted)
-               m68328_set_baud();
-    while (count--) {
-        if (*str == '\n')
-           rs_put_char('\r');
-        rs_put_char( *str++ );
-    }
-}
-
-
-static struct console m68328_driver = {
-       .name           = "ttyS",
-       .write          = m68328_console_write,
-       .device         = m68328_console_device,
-       .setup          = m68328_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-};
-
-
-static int __init m68328_console_init(void)
-{
-       register_console(&m68328_driver);
-       return 0;
-}
-
-console_initcall(m68328_console_init);
diff --git a/drivers/serial/68328serial.h b/drivers/serial/68328serial.h
deleted file mode 100644 (file)
index 664ceb0..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/* 68328serial.h: Definitions for the mc68328 serial driver.
- *
- * Copyright (C) 1995       David S. Miller    <davem@caip.rutgers.edu>
- * Copyright (C) 1998       Kenneth Albanowski <kjahds@kjahds.com>
- * Copyright (C) 1998, 1999 D. Jeff Dionne     <jeff@uclinux.org>
- * Copyright (C) 1999       Vladimir Gurevich  <vgurevic@cisco.com>
- *
- * VZ Support/Fixes             Evan Stawnyczy <e@lineo.ca>
- */
-
-#ifndef _MC683XX_SERIAL_H
-#define _MC683XX_SERIAL_H
-
-
-struct serial_struct {
-       int     type;
-       int     line;
-       int     port;
-       int     irq;
-       int     flags;
-       int     xmit_fifo_size;
-       int     custom_divisor;
-       int     baud_base;
-       unsigned short  close_delay;
-       char    reserved_char[2];
-       int     hub6;  /* FIXME: We don't have AT&T Hub6 boards! */
-       unsigned short  closing_wait; /* time to wait before closing */
-       unsigned short  closing_wait2; /* no longer used... */
-       int     reserved[4];
-};
-
-/*
- * For the close wait times, 0 means wait forever for serial port to
- * flush its output.  65535 means don't wait at all.
- */
-#define S_CLOSING_WAIT_INF     0
-#define S_CLOSING_WAIT_NONE    65535
-
-/*
- * Definitions for S_struct (and serial_struct) flags field
- */
-#define S_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes 
-                                  on the callout port */
-#define S_FOURPORT  0x0002     /* Set OU1, OUT2 per AST Fourport settings */
-#define S_SAK  0x0004  /* Secure Attention Key (Orange book) */
-#define S_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
-
-#define S_SPD_MASK     0x0030
-#define S_SPD_HI       0x0010  /* Use 56000 instead of 38400 bps */
-
-#define S_SPD_VHI      0x0020  /* Use 115200 instead of 38400 bps */
-#define S_SPD_CUST     0x0030  /* Use user-specified divisor */
-
-#define S_SKIP_TEST    0x0040 /* Skip UART test during autoconfiguration */
-#define S_AUTO_IRQ  0x0080 /* Do automatic IRQ during autoconfiguration */
-#define S_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
-#define S_PGRP_LOCKOUT    0x0200 /* Lock out cua opens based on pgrp */
-#define S_CALLOUT_NOHUP   0x0400 /* Don't do hangups for cua device */
-
-#define S_FLAGS        0x0FFF  /* Possible legal S flags */
-#define S_USR_MASK 0x0430      /* Legal flags that non-privileged
-                                * users can set or reset */
-
-/* Internal flags used only by kernel/chr_drv/serial.c */
-#define S_INITIALIZED  0x80000000 /* Serial port was initialized */
-#define S_CALLOUT_ACTIVE       0x40000000 /* Call out device is active */
-#define S_NORMAL_ACTIVE        0x20000000 /* Normal device is active */
-#define S_BOOT_AUTOCONF        0x10000000 /* Autoconfigure port on bootup */
-#define S_CLOSING              0x08000000 /* Serial port is closing */
-#define S_CTS_FLOW             0x04000000 /* Do CTS flow control */
-#define S_CHECK_CD             0x02000000 /* i.e., CLOCAL */
-
-/* Software state per channel */
-
-#ifdef __KERNEL__
-
-/*
- * I believe this is the optimal setting that reduces the number of interrupts.
- * At high speeds the output might become a little "bursted" (use USTCNT_TXHE
- * if that bothers you), but in most cases it will not, since we try to 
- * transmit characters every time rs_interrupt is called. Thus, quite often
- * you'll see that a receive interrupt occures before the transmit one.
- *                                  -- Vladimir Gurevich
- */
-#define USTCNT_TX_INTR_MASK (USTCNT_TXEE)
-
-/*
- * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special
- * "Old data interrupt" which occures whenever the data stay in the FIFO
- * longer than 30 bits time. This allows us to use FIFO without compromising
- * latency. '328 does not have this feature and without the real  328-based
- * board I would assume that RXRE is the safest setting.
- *
- * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of
- * interrupts. RXFE (receive queue full) causes the system to lose data
- * at least at 115200 baud
- *
- * If your board is busy doing other stuff, you might consider to use
- * RXRE (data ready intrrupt) instead.
- *
- * The other option is to make these INTR masks run-time configurable, so
- * that people can dynamically adapt them according to the current usage.
- *                                  -- Vladimir Gurevich
- */
-
-/* (es) */
-#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328)
-#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN)
-#elif defined(CONFIG_M68328)
-#define USTCNT_RX_INTR_MASK (USTCNT_RXRE)
-#else
-#error Please, define the Rx interrupt events for your CPU
-#endif
-/* (/es) */
-
-/*
- * This is our internal structure for each serial port's state.
- * 
- * Many fields are paralleled by the structure used by the serial_struct
- * structure.
- *
- * For definitions of the flags field, see tty.h
- */
-
-struct m68k_serial {
-       char soft_carrier;  /* Use soft carrier on this channel */
-       char break_abort;   /* Is serial console in, so process brk/abrt */
-       char is_cons;       /* Is this our console. */
-
-       /* We need to know the current clock divisor
-        * to read the bps rate the chip has currently
-        * loaded.
-        */
-       unsigned char clk_divisor;  /* May be 1, 16, 32, or 64 */
-       int baud;
-       int                     magic;
-       int                     baud_base;
-       int                     port;
-       int                     irq;
-       int                     flags;          /* defined in tty.h */
-       int                     type;           /* UART type */
-       struct tty_struct       *tty;
-       int                     read_status_mask;
-       int                     ignore_status_mask;
-       int                     timeout;
-       int                     xmit_fifo_size;
-       int                     custom_divisor;
-       int                     x_char; /* xon/xoff character */
-       int                     close_delay;
-       unsigned short          closing_wait;
-       unsigned short          closing_wait2;
-       unsigned long           event;
-       unsigned long           last_active;
-       int                     line;
-       int                     count;      /* # of fd on device */
-       int                     blocked_open; /* # of blocked opens */
-       unsigned char           *xmit_buf;
-       int                     xmit_head;
-       int                     xmit_tail;
-       int                     xmit_cnt;
-       struct work_struct      tqueue;
-       struct work_struct      tqueue_hangup;
-       wait_queue_head_t       open_wait;
-       wait_queue_head_t       close_wait;
-};
-
-
-#define SERIAL_MAGIC 0x5301
-
-/*
- * The size of the serial xmit buffer is 1 page, or 4096 bytes
- */
-#define SERIAL_XMIT_SIZE 4096
-
-/*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at rs interrupt time.
- */
-#define RS_EVENT_WRITE_WAKEUP  0
-
-/* 
- * Define the number of ports supported and their irqs.
- */
-#define NR_PORTS 1
-#define UART_IRQ_DEFNS {UART_IRQ_NUM}
-
-#endif /* __KERNEL__ */
-#endif /* !(_MC683XX_SERIAL_H) */
diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c
deleted file mode 100644 (file)
index 88b1335..0000000
+++ /dev/null
@@ -1,2978 +0,0 @@
-/*
- *  UART driver for 68360 CPM SCC or SMC
- *  Copyright (c) 2000 D. Jeff Dionne <jeff@uclinux.org>,
- *  Copyright (c) 2000 Michael Leslie <mleslie@lineo.ca>
- *  Copyright (c) 1997 Dan Malek <dmalek@jlc.net>
- *
- * I used the serial.c driver as the framework for this driver.
- * Give credit to those guys.
- * The original code was written for the MBX860 board.  I tried to make
- * it generic, but there may be some assumptions in the structures that
- * have to be fixed later.
- * To save porting time, I did not bother to change any object names
- * that are not accessed outside of this file.
- * It still needs lots of work........When it was easy, I included code
- * to support the SCCs, but this has never been tested, nor is it complete.
- * Only the SCCs support modem control, so that is not complete either.
- *
- * This module exports the following rs232 io functions:
- *
- *     int rs_360_init(void);
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/serialP.h> 
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <asm/irq.h>
-#include <asm/m68360.h>
-#include <asm/commproc.h>
-
-#ifdef CONFIG_KGDB
-extern void breakpoint(void);
-extern void set_debug_traps(void);
-extern int  kgdb_output_string (const char* s, unsigned int count);
-#endif
-
-
-/* #ifdef CONFIG_SERIAL_CONSOLE */ /* This seems to be a post 2.0 thing - mles */
-#include <linux/console.h>
-#include <linux/jiffies.h>
-
-/* this defines the index into rs_table for the port to use
- */
-#ifndef CONFIG_SERIAL_CONSOLE_PORT
-#define CONFIG_SERIAL_CONSOLE_PORT     1 /* ie SMC2 - note USE_SMC2 must be defined */
-#endif
-/* #endif */
-
-#if 0
-/* SCC2 for console
- */
-#undef CONFIG_SERIAL_CONSOLE_PORT
-#define CONFIG_SERIAL_CONSOLE_PORT     2
-#endif
-
-
-#define TX_WAKEUP      ASYNC_SHARE_IRQ
-
-static char *serial_name = "CPM UART driver";
-static char *serial_version = "0.03";
-
-static struct tty_driver *serial_driver;
-int serial_console_setup(struct console *co, char *options);
-
-/*
- * Serial driver configuration section.  Here are the various options:
- */
-#define SERIAL_PARANOIA_CHECK
-#define CONFIG_SERIAL_NOPAUSE_IO
-#define SERIAL_DO_RESTART
-
-/* Set of debugging defines */
-
-#undef SERIAL_DEBUG_INTR
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-
-#define _INLINE_ inline
-  
-#define DBG_CNT(s)
-
-/* We overload some of the items in the data structure to meet our
- * needs.  For example, the port address is the CPM parameter ram
- * offset for the SCC or SMC.  The maximum number of ports is 4 SCCs and
- * 2 SMCs.  The "hub6" field is used to indicate the channel number, with
- * a flag indicating SCC or SMC, and the number is used as an index into
- * the CPM parameter area for this device.
- * The "type" field is currently set to 0, for PORT_UNKNOWN.  It is
- * not currently used.  I should probably use it to indicate the port
- * type of SMC or SCC.
- * The SMCs do not support any modem control signals.
- */
-#define smc_scc_num    hub6
-#define NUM_IS_SCC     ((int)0x00010000)
-#define PORT_NUM(P)    ((P) & 0x0000ffff)
-
-
-#if defined (CONFIG_UCQUICC)
-
-volatile extern void *_periph_base;
-/* sipex transceiver
- *   mode bits for       are on pins
- *
- *    SCC2                d16..19
- *    SCC3                d20..23
- *    SCC4                d24..27
- */
-#define SIPEX_MODE(n,m) ((m & 0x0f)<<(16+4*(n-1)))
-
-static uint sipex_mode_bits = 0x00000000;
-
-#endif
-
-/* There is no `serial_state' defined back here in 2.0.
- * Try to get by with serial_struct
- */
-/* #define serial_state serial_struct */
-
-/* 2.4 -> 2.0 portability problem: async_icount in 2.4 has a few
- * extras: */
-
-#if 0
-struct async_icount_24 {
-       __u32   cts, dsr, rng, dcd, tx, rx;
-       __u32   frame, parity, overrun, brk;
-       __u32   buf_overrun;
-} icount;
-#endif
-
-#if 0
-
-struct serial_state {
-        int     magic;
-        int     baud_base;
-        unsigned long   port;
-        int     irq;
-        int     flags;
-        int     hub6;
-        int     type;
-        int     line;
-        int     revision;       /* Chip revision (950) */
-        int     xmit_fifo_size;
-        int     custom_divisor;
-        int     count;
-        u8      *iomem_base;
-        u16     iomem_reg_shift;
-        unsigned short  close_delay;
-        unsigned short  closing_wait; /* time to wait before closing */
-        struct async_icount_24     icount; 
-        int     io_type;
-        struct async_struct *info;
-};
-#endif
-
-#define SSTATE_MAGIC 0x5302
-
-
-
-/* SMC2 is sometimes used for low performance TDM interfaces.  Define
- * this as 1 if you want SMC2 as a serial port UART managed by this driver.
- * Define this as 0 if you wish to use SMC2 for something else.
- */
-#define USE_SMC2 1
-
-#if 0
-/* Define SCC to ttySx mapping. */
-#define SCC_NUM_BASE   (USE_SMC2 + 1)  /* SCC base tty "number" */
-
-/* Define which SCC is the first one to use for a serial port.  These
- * are 0-based numbers, i.e. this assumes the first SCC (SCC1) is used
- * for Ethernet, and the first available SCC for serial UART is SCC2.
- * NOTE:  IF YOU CHANGE THIS, you have to change the PROFF_xxx and
- * interrupt vectors in the table below to match.
- */
-#define SCC_IDX_BASE   1       /* table index */
-#endif
-
-
-/* Processors other than the 860 only get SMCs configured by default.
- * Either they don't have SCCs or they are allocated somewhere else.
- * Of course, there are now 860s without some SCCs, so we will need to
- * address that someday.
- * The Embedded Planet Multimedia I/O cards use TDM interfaces to the
- * stereo codec parts, and we use SMC2 to help support that.
- */
-static struct serial_state rs_table[] = {
-/*  type   line   PORT           IRQ       FLAGS  smc_scc_num (F.K.A. hub6) */
-       {  0,     0, PRSLOT_SMC1, CPMVEC_SMC1,   0,    0 }    /* SMC1 ttyS0 */
-#if USE_SMC2
-       ,{ 0,     0, PRSLOT_SMC2, CPMVEC_SMC2,   0,    1 }     /* SMC2 ttyS1 */
-#endif
-
-#if defined(CONFIG_SERIAL_68360_SCC)
-       ,{ 0,     0, PRSLOT_SCC2, CPMVEC_SCC2,   0, (NUM_IS_SCC | 1) }    /* SCC2 ttyS2 */
-       ,{ 0,     0, PRSLOT_SCC3, CPMVEC_SCC3,   0, (NUM_IS_SCC | 2) }    /* SCC3 ttyS3 */
-       ,{ 0,     0, PRSLOT_SCC4, CPMVEC_SCC4,   0, (NUM_IS_SCC | 3) }    /* SCC4 ttyS4 */
-#endif
-};
-
-#define NR_PORTS       (sizeof(rs_table)/sizeof(struct serial_state))
-
-/* The number of buffer descriptors and their sizes.
- */
-#define RX_NUM_FIFO    4
-#define RX_BUF_SIZE    32
-#define TX_NUM_FIFO    4
-#define TX_BUF_SIZE    32
-
-#define CONSOLE_NUM_FIFO 2
-#define CONSOLE_BUF_SIZE 4
-
-char *console_fifos[CONSOLE_NUM_FIFO * CONSOLE_BUF_SIZE];
-
-/* The async_struct in serial.h does not really give us what we
- * need, so define our own here.
- */
-typedef struct serial_info {
-       int                     magic;
-       int                     flags;
-
-       struct serial_state     *state;
-       /* struct serial_struct *state; */
-       /* struct async_struct  *state; */
-       
-       struct tty_struct       *tty;
-       int                     read_status_mask;
-       int                     ignore_status_mask;
-       int                     timeout;
-       int                     line;
-       int                     x_char; /* xon/xoff character */
-       int                     close_delay;
-       unsigned short          closing_wait;
-       unsigned short          closing_wait2;
-       unsigned long           event;
-       unsigned long           last_active;
-       int                     blocked_open; /* # of blocked opens */
-       struct work_struct      tqueue;
-       struct work_struct      tqueue_hangup;
-       wait_queue_head_t       open_wait; 
-       wait_queue_head_t       close_wait; 
-
-       
-/* CPM Buffer Descriptor pointers.
-       */
-       QUICC_BD                        *rx_bd_base;
-       QUICC_BD                        *rx_cur;
-       QUICC_BD                        *tx_bd_base;
-       QUICC_BD                        *tx_cur;
-} ser_info_t;
-
-
-/* since kmalloc_init() does not get called until much after this initialization: */
-static ser_info_t  quicc_ser_info[NR_PORTS];
-static char rx_buf_pool[NR_PORTS * RX_NUM_FIFO * RX_BUF_SIZE];
-static char tx_buf_pool[NR_PORTS * TX_NUM_FIFO * TX_BUF_SIZE];
-
-static void change_speed(ser_info_t *info);
-static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout);
-
-static inline int serial_paranoia_check(ser_info_t *info,
-                                       char *name, const char *routine)
-{
-#ifdef SERIAL_PARANOIA_CHECK
-       static const char *badmagic =
-               "Warning: bad magic number for serial struct (%s) in %s\n";
-       static const char *badinfo =
-               "Warning: null async_struct for (%s) in %s\n";
-
-       if (!info) {
-               printk(badinfo, name, routine);
-               return 1;
-       }
-       if (info->magic != SERIAL_MAGIC) {
-               printk(badmagic, name, routine);
-               return 1;
-       }
-#endif
-       return 0;
-}
-
-/*
- * This is used to figure out the divisor speeds and the timeouts,
- * indexed by the termio value.  The generic CPM functions are responsible
- * for setting and assigning baud rate generators for us.
- */
-static int baud_table[] = {
-       0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-       9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };
-
-/* This sucks. There is a better way: */
-#if defined(CONFIG_CONSOLE_9600)
-  #define CONSOLE_BAUDRATE 9600
-#elif defined(CONFIG_CONSOLE_19200)
-  #define CONSOLE_BAUDRATE 19200
-#elif defined(CONFIG_CONSOLE_115200)
-  #define CONSOLE_BAUDRATE 115200
-#else
-  #warning "console baud rate undefined"
-  #define CONSOLE_BAUDRATE 9600
-#endif
-
-/*
- * ------------------------------------------------------------
- * rs_stop() and rs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter interrupts, as necessary.
- * ------------------------------------------------------------
- */
-static void rs_360_stop(struct tty_struct *tty)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-       int     idx;
-       unsigned long flags;
-       volatile struct scc_regs *sccp;
-       volatile struct smc_regs *smcp;
-
-       if (serial_paranoia_check(info, tty->name, "rs_stop"))
-               return;
-       
-       local_irq_save(flags);
-       idx = PORT_NUM(info->state->smc_scc_num);
-       if (info->state->smc_scc_num & NUM_IS_SCC) {
-               sccp = &pquicc->scc_regs[idx];
-               sccp->scc_sccm &= ~UART_SCCM_TX;
-       } else {
-               /* smcp = &cpmp->cp_smc[idx]; */
-               smcp = &pquicc->smc_regs[idx];
-               smcp->smc_smcm &= ~SMCM_TX;
-       }
-       local_irq_restore(flags);
-}
-
-
-static void rs_360_start(struct tty_struct *tty)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-       int     idx;
-       unsigned long flags;
-       volatile struct scc_regs *sccp;
-       volatile struct smc_regs *smcp;
-
-       if (serial_paranoia_check(info, tty->name, "rs_stop"))
-               return;
-       
-       local_irq_save(flags);
-       idx = PORT_NUM(info->state->smc_scc_num);
-       if (info->state->smc_scc_num & NUM_IS_SCC) {
-               sccp = &pquicc->scc_regs[idx];
-               sccp->scc_sccm |= UART_SCCM_TX;
-       } else {
-               smcp = &pquicc->smc_regs[idx];
-               smcp->smc_smcm |= SMCM_TX;
-       }
-       local_irq_restore(flags);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Here starts the interrupt handling routines.  All of the following
- * subroutines are declared as inline and are folded into
- * rs_interrupt().  They were separated out for readability's sake.
- *
- * Note: rs_interrupt() is a "fast" interrupt, which means that it
- * runs with interrupts turned off.  People who may want to modify
- * rs_interrupt() should try to keep the interrupt handler as fast as
- * possible.  After you are done making modifications, it is not a bad
- * idea to do:
- * 
- * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
- *
- * and look at the resulting assemble code in serial.s.
- *
- *                             - Ted Ts'o (tytso@mit.edu), 7-Mar-93
- * -----------------------------------------------------------------------
- */
-
-static _INLINE_ void receive_chars(ser_info_t *info)
-{
-       struct tty_struct *tty = info->port.tty;
-       unsigned char ch, flag, *cp;
-       /*int   ignored = 0;*/
-       int     i;
-       ushort  status;
-        struct async_icount *icount; 
-       /* struct       async_icount_24 *icount; */
-       volatile QUICC_BD       *bdp;
-
-       icount = &info->state->icount;
-
-       /* Just loop through the closed BDs and copy the characters into
-        * the buffer.
-        */
-       bdp = info->rx_cur;
-       for (;;) {
-               if (bdp->status & BD_SC_EMPTY)  /* If this one is empty */
-                       break;                  /*   we are all done */
-
-               /* The read status mask tell us what we should do with
-                * incoming characters, especially if errors occur.
-                * One special case is the use of BD_SC_EMPTY.  If
-                * this is not set, we are supposed to be ignoring
-                * inputs.  In this case, just mark the buffer empty and
-                * continue.
-                */
-               if (!(info->read_status_mask & BD_SC_EMPTY)) {
-                       bdp->status |= BD_SC_EMPTY;
-                       bdp->status &=
-                               ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
-
-                       if (bdp->status & BD_SC_WRAP)
-                               bdp = info->rx_bd_base;
-                       else
-                               bdp++;
-                       continue;
-               }
-
-               /* Get the number of characters and the buffer pointer.
-               */
-               i = bdp->length;
-               /* cp = (unsigned char *)__va(bdp->buf); */
-               cp = (char *)bdp->buf;
-               status = bdp->status;
-
-               while (i-- > 0) {
-                       ch = *cp++;
-                       icount->rx++;
-
-#ifdef SERIAL_DEBUG_INTR
-                       printk("DR%02x:%02x...", ch, status);
-#endif
-                       flag = TTY_NORMAL;
-
-                       if (status & (BD_SC_BR | BD_SC_FR |
-                                      BD_SC_PR | BD_SC_OV)) {
-                               /*
-                                * For statistics only
-                                */
-                               if (status & BD_SC_BR)
-                                       icount->brk++;
-                               else if (status & BD_SC_PR)
-                                       icount->parity++;
-                               else if (status & BD_SC_FR)
-                                       icount->frame++;
-                               if (status & BD_SC_OV)
-                                       icount->overrun++;
-
-                               /*
-                                * Now check to see if character should be
-                                * ignored, and mask off conditions which
-                                * should be ignored.
-                               if (status & info->ignore_status_mask) {
-                                       if (++ignored > 100)
-                                               break;
-                                       continue;
-                               }
-                                */
-                               status &= info->read_status_mask;
-               
-                               if (status & (BD_SC_BR)) {
-#ifdef SERIAL_DEBUG_INTR
-                                       printk("handling break....");
-#endif
-                                       *tty->flip.flag_buf_ptr = TTY_BREAK;
-                                       if (info->flags & ASYNC_SAK)
-                                               do_SAK(tty);
-                               } else if (status & BD_SC_PR)
-                                       flag = TTY_PARITY;
-                               else if (status & BD_SC_FR)
-                                       flag = TTY_FRAME;
-                       }
-                       tty_insert_flip_char(tty, ch, flag);
-                       if (status & BD_SC_OV)
-                               /*
-                                * Overrun is special, since it's
-                                * reported immediately, and doesn't
-                                * affect the current character
-                                */
-                               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               }
-
-               /* This BD is ready to be used again.  Clear status.
-                * Get next BD.
-                */
-               bdp->status |= BD_SC_EMPTY;
-               bdp->status &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
-
-               if (bdp->status & BD_SC_WRAP)
-                       bdp = info->rx_bd_base;
-               else
-                       bdp++;
-       }
-
-       info->rx_cur = (QUICC_BD *)bdp;
-
-       tty_schedule_flip(tty);
-}
-
-static _INLINE_ void receive_break(ser_info_t *info)
-{
-       struct tty_struct *tty = info->port.tty;
-
-       info->state->icount.brk++;
-       /* Check to see if there is room in the tty buffer for
-        * the break.  If not, we exit now, losing the break.  FIXME
-        */
-       tty_insert_flip_char(tty, 0, TTY_BREAK);
-       tty_schedule_flip(tty);
-}
-
-static _INLINE_ void transmit_chars(ser_info_t *info)
-{
-
-       if ((info->flags & TX_WAKEUP) ||
-           (info->port.tty->flags & (1 << TTY_DO_WRITE_WAKEUP))) {
-               schedule_work(&info->tqueue);
-       }
-
-#ifdef SERIAL_DEBUG_INTR
-       printk("THRE...");
-#endif
-}
-
-#ifdef notdef
-       /* I need to do this for the SCCs, so it is left as a reminder.
-       */
-static _INLINE_ void check_modem_status(struct async_struct *info)
-{
-       int     status;
-       /* struct       async_icount *icount; */
-       struct  async_icount_24 *icount;
-       
-       status = serial_in(info, UART_MSR);
-
-       if (status & UART_MSR_ANY_DELTA) {
-               icount = &info->state->icount;
-               /* update input line counters */
-               if (status & UART_MSR_TERI)
-                       icount->rng++;
-               if (status & UART_MSR_DDSR)
-                       icount->dsr++;
-               if (status & UART_MSR_DDCD) {
-                       icount->dcd++;
-#ifdef CONFIG_HARD_PPS
-                       if ((info->flags & ASYNC_HARDPPS_CD) &&
-                           (status & UART_MSR_DCD))
-                               hardpps();
-#endif
-               }
-               if (status & UART_MSR_DCTS)
-                       icount->cts++;
-               wake_up_interruptible(&info->delta_msr_wait);
-       }
-
-       if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
-#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
-               printk("ttys%d CD now %s...", info->line,
-                      (status & UART_MSR_DCD) ? "on" : "off");
-#endif         
-               if (status & UART_MSR_DCD)
-                       wake_up_interruptible(&info->open_wait);
-               else {
-#ifdef SERIAL_DEBUG_OPEN
-                       printk("scheduling hangup...");
-#endif
-                       queue_task(&info->tqueue_hangup,
-                                          &tq_scheduler);
-               }
-       }
-       if (info->flags & ASYNC_CTS_FLOW) {
-               if (info->port.tty->hw_stopped) {
-                       if (status & UART_MSR_CTS) {
-#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
-                               printk("CTS tx start...");
-#endif
-                               info->port.tty->hw_stopped = 0;
-                               info->IER |= UART_IER_THRI;
-                               serial_out(info, UART_IER, info->IER);
-                               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-                               return;
-                       }
-               } else {
-                       if (!(status & UART_MSR_CTS)) {
-#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
-                               printk("CTS tx stop...");
-#endif
-                               info->port.tty->hw_stopped = 1;
-                               info->IER &= ~UART_IER_THRI;
-                               serial_out(info, UART_IER, info->IER);
-                       }
-               }
-       }
-}
-#endif
-
-/*
- * This is the serial driver's interrupt routine for a single port
- */
-/* static void rs_360_interrupt(void *dev_id) */ /* until and if we start servicing irqs here */
-static void rs_360_interrupt(int vec, void *dev_id)
-{
-       u_char  events;
-       int     idx;
-       ser_info_t *info;
-       volatile struct smc_regs *smcp;
-       volatile struct scc_regs *sccp;
-       
-       info = dev_id;
-
-       idx = PORT_NUM(info->state->smc_scc_num);
-       if (info->state->smc_scc_num & NUM_IS_SCC) {
-               sccp = &pquicc->scc_regs[idx];
-               events = sccp->scc_scce;
-               if (events & SCCM_RX)
-                       receive_chars(info);
-               if (events & SCCM_TX)
-                       transmit_chars(info);
-               sccp->scc_scce = events;
-       } else {
-               smcp = &pquicc->smc_regs[idx];
-               events = smcp->smc_smce;
-               if (events & SMCM_BRKE)
-                       receive_break(info);
-               if (events & SMCM_RX)
-                       receive_chars(info);
-               if (events & SMCM_TX)
-                       transmit_chars(info);
-               smcp->smc_smce = events;
-       }
-       
-#ifdef SERIAL_DEBUG_INTR
-       printk("rs_interrupt_single(%d, %x)...",
-                                       info->state->smc_scc_num, events);
-#endif
-#ifdef modem_control
-       check_modem_status(info);
-#endif
-       info->last_active = jiffies;
-#ifdef SERIAL_DEBUG_INTR
-       printk("end.\n");
-#endif
-}
-
-
-/*
- * -------------------------------------------------------------------
- * Here ends the serial interrupt routines.
- * -------------------------------------------------------------------
- */
-
-
-static void do_softint(void *private_)
-{
-       ser_info_t      *info = (ser_info_t *) private_;
-       struct tty_struct       *tty;
-       
-       tty = info->port.tty;
-       if (!tty)
-               return;
-
-       if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event))
-               tty_wakeup(tty);
-}
-
-
-/*
- * This routine is called from the scheduler tqueue when the interrupt
- * routine has signalled that a hangup has occurred.  The path of
- * hangup processing is:
- *
- *     serial interrupt routine -> (scheduler tqueue) ->
- *     do_serial_hangup() -> tty->hangup() -> rs_hangup()
- * 
- */
-static void do_serial_hangup(void *private_)
-{
-       struct async_struct     *info = (struct async_struct *) private_;
-       struct tty_struct       *tty;
-       
-       tty = info->port.tty;
-       if (!tty)
-               return;
-
-       tty_hangup(tty);
-}
-
-
-static int startup(ser_info_t *info)
-{
-       unsigned long flags;
-       int     retval=0;
-       int     idx;
-       /*struct serial_state *state = info->state;*/
-       volatile struct smc_regs *smcp;
-       volatile struct scc_regs *sccp;
-       volatile struct smc_uart_pram   *up;
-       volatile struct uart_pram           *scup;
-
-
-       local_irq_save(flags);
-
-       if (info->flags & ASYNC_INITIALIZED) {
-               goto errout;
-       }
-
-#ifdef maybe
-       if (!state->port || !state->type) {
-               if (info->port.tty)
-                       set_bit(TTY_IO_ERROR, &info->port.tty->flags);
-               goto errout;
-       }
-#endif
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("starting up ttys%d (irq %d)...", info->line, state->irq);
-#endif
-
-
-#ifdef modem_control
-       info->MCR = 0;
-       if (info->port.tty->termios->c_cflag & CBAUD)
-               info->MCR = UART_MCR_DTR | UART_MCR_RTS;
-#endif
-       
-       if (info->port.tty)
-               clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
-
-       /*
-        * and set the speed of the serial port
-        */
-       change_speed(info);
-
-       idx = PORT_NUM(info->state->smc_scc_num);
-       if (info->state->smc_scc_num & NUM_IS_SCC) {
-               sccp = &pquicc->scc_regs[idx];
-               scup = &pquicc->pram[info->state->port].scc.pscc.u;
-
-               scup->mrblr = RX_BUF_SIZE;
-               scup->max_idl = RX_BUF_SIZE;
-
-               sccp->scc_sccm |= (UART_SCCM_TX | UART_SCCM_RX);
-               sccp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-
-       } else {
-               smcp = &pquicc->smc_regs[idx];
-
-               /* Enable interrupts and I/O.
-               */
-               smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
-               smcp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN);
-
-               /* We can tune the buffer length and idle characters
-                * to take advantage of the entire incoming buffer size.
-                * If mrblr is something other than 1, maxidl has to be
-                * non-zero or we never get an interrupt.  The maxidl
-                * is the number of character times we wait after reception
-                * of the last character before we decide no more characters
-                * are coming.
-                */
-               /* up = (smc_uart_t *)&pquicc->cp_dparam[state->port]; */
-               /* holy unionized structures, Batman: */
-               up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u;
-
-               up->mrblr = RX_BUF_SIZE;
-               up->max_idl = RX_BUF_SIZE;
-
-               up->brkcr = 1;  /* number of break chars */
-       }
-
-       info->flags |= ASYNC_INITIALIZED;
-       local_irq_restore(flags);
-       return 0;
-       
-errout:
-       local_irq_restore(flags);
-       return retval;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void shutdown(ser_info_t *info)
-{
-       unsigned long   flags;
-       struct serial_state *state;
-       int             idx;
-       volatile struct smc_regs        *smcp;
-       volatile struct scc_regs        *sccp;
-
-       if (!(info->flags & ASYNC_INITIALIZED))
-               return;
-
-       state = info->state;
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("Shutting down serial port %d (irq %d)....", info->line,
-              state->irq);
-#endif
-       
-       local_irq_save(flags);
-
-       idx = PORT_NUM(state->smc_scc_num);
-       if (state->smc_scc_num & NUM_IS_SCC) {
-               sccp = &pquicc->scc_regs[idx];
-               sccp->scc_gsmr.w.low &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-#ifdef CONFIG_SERIAL_CONSOLE
-               /* We can't disable the transmitter if this is the
-                * system console.
-                */
-               if ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT)
-#endif
-               sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
-       } else {
-               smcp = &pquicc->smc_regs[idx];
-
-               /* Disable interrupts and I/O.
-                */
-               smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
-#ifdef CONFIG_SERIAL_CONSOLE
-               /* We can't disable the transmitter if this is the
-                * system console.
-                */
-               if ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT)
-#endif
-                       smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
-       }
-       
-       if (info->port.tty)
-               set_bit(TTY_IO_ERROR, &info->port.tty->flags);
-
-       info->flags &= ~ASYNC_INITIALIZED;
-       local_irq_restore(flags);
-}
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void change_speed(ser_info_t *info)
-{
-       int     baud_rate;
-       unsigned cflag, cval, scval, prev_mode;
-       int     i, bits, sbits, idx;
-       unsigned long   flags;
-       struct serial_state *state;
-       volatile struct smc_regs        *smcp;
-       volatile struct scc_regs        *sccp;
-
-       if (!info->port.tty || !info->port.tty->termios)
-               return;
-       cflag = info->port.tty->termios->c_cflag;
-
-       state = info->state;
-
-       /* Character length programmed into the mode register is the
-        * sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
-        * 1 or 2 stop bits, minus 1.
-        * The value 'bits' counts this for us.
-        */
-       cval = 0;
-       scval = 0;
-
-       /* byte size and parity */
-       switch (cflag & CSIZE) {
-             case CS5: bits = 5; break;
-             case CS6: bits = 6; break;
-             case CS7: bits = 7; break;
-             case CS8: bits = 8; break;
-             /* Never happens, but GCC is too dumb to figure it out */
-             default:  bits = 8; break;
-       }
-       sbits = bits - 5;
-
-       if (cflag & CSTOPB) {
-               cval |= SMCMR_SL;       /* Two stops */
-               scval |= SCU_PMSR_SL;
-               bits++;
-       }
-       if (cflag & PARENB) {
-               cval |= SMCMR_PEN;
-               scval |= SCU_PMSR_PEN;
-               bits++;
-       }
-       if (!(cflag & PARODD)) {
-               cval |= SMCMR_PM_EVEN;
-               scval |= (SCU_PMSR_REVP | SCU_PMSR_TEVP);
-       }
-
-       /* Determine divisor based on baud rate */
-       i = cflag & CBAUD;
-       if (i >= (sizeof(baud_table)/sizeof(int)))
-               baud_rate = 9600;
-       else
-               baud_rate = baud_table[i];
-
-       info->timeout = (TX_BUF_SIZE*HZ*bits);
-       info->timeout += HZ/50;         /* Add .02 seconds of slop */
-
-#ifdef modem_control
-       /* CTS flow control flag and modem status interrupts */
-       info->IER &= ~UART_IER_MSI;
-       if (info->flags & ASYNC_HARDPPS_CD)
-               info->IER |= UART_IER_MSI;
-       if (cflag & CRTSCTS) {
-               info->flags |= ASYNC_CTS_FLOW;
-               info->IER |= UART_IER_MSI;
-       } else
-               info->flags &= ~ASYNC_CTS_FLOW;
-       if (cflag & CLOCAL)
-               info->flags &= ~ASYNC_CHECK_CD;
-       else {
-               info->flags |= ASYNC_CHECK_CD;
-               info->IER |= UART_IER_MSI;
-       }
-       serial_out(info, UART_IER, info->IER);
-#endif
-
-       /*
-        * Set up parity check flag
-        */
-       info->read_status_mask = (BD_SC_EMPTY | BD_SC_OV);
-       if (I_INPCK(info->port.tty))
-               info->read_status_mask |= BD_SC_FR | BD_SC_PR;
-       if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
-               info->read_status_mask |= BD_SC_BR;
-       
-       /*
-        * Characters to ignore
-        */
-       info->ignore_status_mask = 0;
-       if (I_IGNPAR(info->port.tty))
-               info->ignore_status_mask |= BD_SC_PR | BD_SC_FR;
-       if (I_IGNBRK(info->port.tty)) {
-               info->ignore_status_mask |= BD_SC_BR;
-               /*
-                * If we're ignore parity and break indicators, ignore 
-                * overruns too.  (For real raw support).
-                */
-               if (I_IGNPAR(info->port.tty))
-                       info->ignore_status_mask |= BD_SC_OV;
-       }
-       /*
-        * !!! ignore all characters if CREAD is not set
-        */
-       if ((cflag & CREAD) == 0)
-        info->read_status_mask &= ~BD_SC_EMPTY;
-        local_irq_save(flags);
-
-        /* Start bit has not been added (so don't, because we would just
-         * subtract it later), and we need to add one for the number of
-         * stops bits (there is always at least one).
-         */
-        bits++;
-        idx = PORT_NUM(state->smc_scc_num);
-        if (state->smc_scc_num & NUM_IS_SCC) {
-         sccp = &pquicc->scc_regs[idx];
-         sccp->scc_psmr = (sbits << 12) | scval;
-     } else {
-         smcp = &pquicc->smc_regs[idx];
-
-               /* Set the mode register.  We want to keep a copy of the
-                * enables, because we want to put them back if they were
-                * present.
-                */
-               prev_mode = smcp->smc_smcmr;
-               smcp->smc_smcmr = smcr_mk_clen(bits) | cval |  SMCMR_SM_UART;
-               smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN));
-       }
-
-       m360_cpm_setbrg((state - rs_table), baud_rate);
-
-       local_irq_restore(flags);
-}
-
-static void rs_360_put_char(struct tty_struct *tty, unsigned char ch)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-       volatile QUICC_BD       *bdp;
-
-       if (serial_paranoia_check(info, tty->name, "rs_put_char"))
-               return 0;
-
-       if (!tty)
-               return 0;
-
-       bdp = info->tx_cur;
-       while (bdp->status & BD_SC_READY);
-
-       /* *((char *)__va(bdp->buf)) = ch; */
-       *((char *)bdp->buf) = ch;
-       bdp->length = 1;
-       bdp->status |= BD_SC_READY;
-
-       /* Get next BD.
-       */
-       if (bdp->status & BD_SC_WRAP)
-               bdp = info->tx_bd_base;
-       else
-               bdp++;
-
-       info->tx_cur = (QUICC_BD *)bdp;
-       return 1;
-
-}
-
-static int rs_360_write(struct tty_struct * tty,
-                   const unsigned char *buf, int count)
-{
-       int     c, ret = 0;
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-       volatile QUICC_BD *bdp;
-
-#ifdef CONFIG_KGDB
-       /* Try to let stub handle output. Returns true if it did. */ 
-       if (kgdb_output_string(buf, count))
-               return ret;
-#endif
-
-       if (serial_paranoia_check(info, tty->name, "rs_write"))
-               return 0;
-
-       if (!tty) 
-               return 0;
-
-       bdp = info->tx_cur;
-
-       while (1) {
-               c = min(count, TX_BUF_SIZE);
-
-               if (c <= 0)
-                       break;
-
-               if (bdp->status & BD_SC_READY) {
-                       info->flags |= TX_WAKEUP;
-                       break;
-               }
-
-               /* memcpy(__va(bdp->buf), buf, c); */
-               memcpy((void *)bdp->buf, buf, c);
-
-               bdp->length = c;
-               bdp->status |= BD_SC_READY;
-
-               buf += c;
-               count -= c;
-               ret += c;
-
-               /* Get next BD.
-               */
-               if (bdp->status & BD_SC_WRAP)
-                       bdp = info->tx_bd_base;
-               else
-                       bdp++;
-               info->tx_cur = (QUICC_BD *)bdp;
-       }
-       return ret;
-}
-
-static int rs_360_write_room(struct tty_struct *tty)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-       int     ret;
-
-       if (serial_paranoia_check(info, tty->name, "rs_write_room"))
-               return 0;
-
-       if ((info->tx_cur->status & BD_SC_READY) == 0) {
-               info->flags &= ~TX_WAKEUP;
-               ret = TX_BUF_SIZE;
-       }
-       else {
-               info->flags |= TX_WAKEUP;
-               ret = 0;
-       }
-       return ret;
-}
-
-/* I could track this with transmit counters....maybe later.
-*/
-static int rs_360_chars_in_buffer(struct tty_struct *tty)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-                               
-       if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
-               return 0;
-       return 0;
-}
-
-static void rs_360_flush_buffer(struct tty_struct *tty)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-                               
-       if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
-               return;
-
-       /* There is nothing to "flush", whatever we gave the CPM
-        * is on its way out.
-        */
-       tty_wakeup(tty);
-       info->flags &= ~TX_WAKEUP;
-}
-
-/*
- * This function is used to send a high-priority XON/XOFF character to
- * the device
- */
-static void rs_360_send_xchar(struct tty_struct *tty, char ch)
-{
-       volatile QUICC_BD       *bdp;
-
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-
-       if (serial_paranoia_check(info, tty->name, "rs_send_char"))
-               return;
-
-       bdp = info->tx_cur;
-       while (bdp->status & BD_SC_READY);
-
-       /* *((char *)__va(bdp->buf)) = ch; */
-       *((char *)bdp->buf) = ch;
-       bdp->length = 1;
-       bdp->status |= BD_SC_READY;
-
-       /* Get next BD.
-       */
-       if (bdp->status & BD_SC_WRAP)
-               bdp = info->tx_bd_base;
-       else
-               bdp++;
-
-       info->tx_cur = (QUICC_BD *)bdp;
-}
-
-/*
- * ------------------------------------------------------------
- * rs_throttle()
- * 
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void rs_360_throttle(struct tty_struct * tty)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-#ifdef SERIAL_DEBUG_THROTTLE
-       char    buf[64];
-       
-       printk("throttle %s: %d....\n", _tty_name(tty, buf),
-              tty->ldisc.chars_in_buffer(tty));
-#endif
-
-       if (serial_paranoia_check(info, tty->name, "rs_throttle"))
-               return;
-       
-       if (I_IXOFF(tty))
-               rs_360_send_xchar(tty, STOP_CHAR(tty));
-
-#ifdef modem_control
-       if (tty->termios->c_cflag & CRTSCTS)
-               info->MCR &= ~UART_MCR_RTS;
-
-       local_irq_disable();
-       serial_out(info, UART_MCR, info->MCR);
-       local_irq_enable();
-#endif
-}
-
-static void rs_360_unthrottle(struct tty_struct * tty)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-#ifdef SERIAL_DEBUG_THROTTLE
-       char    buf[64];
-       
-       printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
-              tty->ldisc.chars_in_buffer(tty));
-#endif
-
-       if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
-               return;
-       
-       if (I_IXOFF(tty)) {
-               if (info->x_char)
-                       info->x_char = 0;
-               else
-                       rs_360_send_xchar(tty, START_CHAR(tty));
-       }
-#ifdef modem_control
-       if (tty->termios->c_cflag & CRTSCTS)
-               info->MCR |= UART_MCR_RTS;
-       local_irq_disable();
-       serial_out(info, UART_MCR, info->MCR);
-       local_irq_enable();
-#endif
-}
-
-/*
- * ------------------------------------------------------------
- * rs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-#ifdef maybe
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- *         is emptied.  On bus types like RS485, the transmitter must
- *         release the bus after transmitting. This must be done when
- *         the transmit shift register is empty, not be done when the
- *         transmit holding register is empty.  This functionality
- *         allows an RS485 driver to be written in user space. 
- */
-static int get_lsr_info(struct async_struct * info, unsigned int *value)
-{
-       unsigned char status;
-       unsigned int result;
-
-       local_irq_disable();
-       status = serial_in(info, UART_LSR);
-       local_irq_enable();
-       result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
-       return put_user(result,value);
-}
-#endif
-
-static int rs_360_tiocmget(struct tty_struct *tty, struct file *file)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-       unsigned int result = 0;
-#ifdef modem_control
-       unsigned char control, status;
-
-       if (serial_paranoia_check(info, tty->name, __func__))
-               return -ENODEV;
-
-       if (tty->flags & (1 << TTY_IO_ERROR))
-               return -EIO;
-
-       control = info->MCR;
-       local_irq_disable();
-       status = serial_in(info, UART_MSR);
-       local_irq_enable();
-       result =  ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
-               | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
-#ifdef TIOCM_OUT1
-               | ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0)
-               | ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0)
-#endif
-               | ((status  & UART_MSR_DCD) ? TIOCM_CAR : 0)
-               | ((status  & UART_MSR_RI) ? TIOCM_RNG : 0)
-               | ((status  & UART_MSR_DSR) ? TIOCM_DSR : 0)
-               | ((status  & UART_MSR_CTS) ? TIOCM_CTS : 0);
-#endif
-       return result;
-}
-
-static int rs_360_tiocmset(struct tty_struct *tty, struct file *file,
-                          unsigned int set, unsigned int clear)
-{
-#ifdef modem_control
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-       unsigned int arg;
-
-       if (serial_paranoia_check(info, tty->name, __func__))
-               return -ENODEV;
-
-       if (tty->flags & (1 << TTY_IO_ERROR))
-               return -EIO;
-       /* FIXME: locking on info->mcr */
-       if (set & TIOCM_RTS)
-               info->mcr |= UART_MCR_RTS;
-       if (set & TIOCM_DTR)
-               info->mcr |= UART_MCR_DTR;
-       if (clear & TIOCM_RTS)
-               info->MCR &= ~UART_MCR_RTS;
-       if (clear & TIOCM_DTR)
-               info->MCR &= ~UART_MCR_DTR;
-
-#ifdef TIOCM_OUT1
-       if (set & TIOCM_OUT1)
-               info->MCR |= UART_MCR_OUT1;
-       if (set & TIOCM_OUT2)
-               info->MCR |= UART_MCR_OUT2;
-       if (clear & TIOCM_OUT1)
-               info->MCR &= ~UART_MCR_OUT1;
-       if (clear & TIOCM_OUT2)
-               info->MCR &= ~UART_MCR_OUT2;
-#endif
-
-       local_irq_disable();
-       serial_out(info, UART_MCR, info->MCR);
-       local_irq_enable();
-#endif
-       return 0;
-}
-
-/* Sending a break is a two step process on the SMC/SCC.  It is accomplished
- * by sending a STOP TRANSMIT command followed by a RESTART TRANSMIT
- * command.  We take advantage of the begin/end functions to make this
- * happen.
- */
-static ushort  smc_chan_map[] = {
-       CPM_CR_CH_SMC1,
-       CPM_CR_CH_SMC2
-};
-
-static ushort  scc_chan_map[] = {
-       CPM_CR_CH_SCC1,
-       CPM_CR_CH_SCC2,
-       CPM_CR_CH_SCC3,
-       CPM_CR_CH_SCC4
-};
-
-static void begin_break(ser_info_t *info)
-{
-       volatile QUICC *cp;
-       ushort  chan;
-       int     idx;
-
-       cp = pquicc;
-
-       idx = PORT_NUM(info->state->smc_scc_num);
-       if (info->state->smc_scc_num & NUM_IS_SCC)
-               chan = scc_chan_map[idx];
-       else
-               chan = smc_chan_map[idx];
-
-       cp->cp_cr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG;
-       while (cp->cp_cr & CPM_CR_FLG);
-}
-
-static void end_break(ser_info_t *info)
-{
-       volatile QUICC *cp;
-       ushort  chan;
-       int idx;
-
-       cp = pquicc;
-
-       idx = PORT_NUM(info->state->smc_scc_num);
-       if (info->state->smc_scc_num & NUM_IS_SCC)
-               chan = scc_chan_map[idx];
-       else
-               chan = smc_chan_map[idx];
-
-       cp->cp_cr = mk_cr_cmd(chan, CPM_CR_RESTART_TX) | CPM_CR_FLG;
-       while (cp->cp_cr & CPM_CR_FLG);
-}
-
-/*
- * This routine sends a break character out the serial port.
- */
-static void send_break(ser_info_t *info, unsigned int duration)
-{
-#ifdef SERIAL_DEBUG_SEND_BREAK
-       printk("rs_send_break(%d) jiff=%lu...", duration, jiffies);
-#endif
-       begin_break(info);
-       msleep_interruptible(duration);
-       end_break(info);
-#ifdef SERIAL_DEBUG_SEND_BREAK
-       printk("done jiffies=%lu\n", jiffies);
-#endif
-}
-
-
-/*
- * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
- * Return: write counters to the user passed counter struct
- * NB: both 1->0 and 0->1 transitions are counted except for
- *     RI where only 0->1 is counted.
- */
-static int rs_360_get_icount(struct tty_struct *tty,
-                               struct serial_icounter_struct *icount)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-       struct async_icount cnow;
-
-       local_irq_disable();
-       cnow = info->state->icount;
-       local_irq_enable();
-
-       icount->cts = cnow.cts;
-       icount->dsr = cnow.dsr;
-       icount->rng = cnow.rng;
-       icount->dcd = cnow.dcd;
-
-       return 0;
-}
-
-static int rs_360_ioctl(struct tty_struct *tty, struct file * file,
-                   unsigned int cmd, unsigned long arg)
-{
-       int error;
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-       int retval;
-       struct async_icount cnow; 
-       /* struct async_icount_24 cnow;*/       /* kernel counter temps */
-       struct serial_icounter_struct *p_cuser; /* user space */
-
-       if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
-               return -ENODEV;
-
-       if (cmd != TIOCMIWAIT) {
-               if (tty->flags & (1 << TTY_IO_ERROR))
-                   return -EIO;
-       }
-       
-       switch (cmd) {
-               case TCSBRK:    /* SVID version: non-zero arg --> no break */
-                       retval = tty_check_change(tty);
-                       if (retval)
-                               return retval;
-                       tty_wait_until_sent(tty, 0);
-                       if (signal_pending(current))
-                               return -EINTR;
-                       if (!arg) {
-                               send_break(info, 250);  /* 1/4 second */
-                               if (signal_pending(current))
-                                       return -EINTR;
-                       }
-                       return 0;
-               case TCSBRKP:   /* support for POSIX tcsendbreak() */
-                       retval = tty_check_change(tty);
-                       if (retval)
-                               return retval;
-                       tty_wait_until_sent(tty, 0);
-                       if (signal_pending(current))
-                               return -EINTR;
-                       send_break(info, arg ? arg*100 : 250);
-                       if (signal_pending(current))
-                               return -EINTR;
-                       return 0;
-               case TIOCSBRK:
-                       retval = tty_check_change(tty);
-                       if (retval)
-                               return retval;
-                       tty_wait_until_sent(tty, 0);
-                       begin_break(info);
-                       return 0;
-               case TIOCCBRK:
-                       retval = tty_check_change(tty);
-                       if (retval)
-                               return retval;
-                       end_break(info);
-                       return 0;
-#ifdef maybe
-               case TIOCSERGETLSR: /* Get line status register */
-                       return get_lsr_info(info, (unsigned int *) arg);
-#endif
-               /*
-                * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
-                * - mask passed in arg for lines of interest
-                *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
-                * Caller should use TIOCGICOUNT to see which one it was
-                */
-                case TIOCMIWAIT:
-#ifdef modem_control
-                       local_irq_disable();
-                       /* note the counters on entry */
-                       cprev = info->state->icount;
-                       local_irq_enable();
-                       while (1) {
-                               interruptible_sleep_on(&info->delta_msr_wait);
-                               /* see if a signal did it */
-                               if (signal_pending(current))
-                                       return -ERESTARTSYS;
-                               local_irq_disable();
-                               cnow = info->state->icount; /* atomic copy */
-                               local_irq_enable();
-                               if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 
-                                   cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
-                                       return -EIO; /* no change => error */
-                               if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
-                                    ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
-                                    ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
-                                    ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
-                                       return 0;
-                               }
-                               cprev = cnow;
-                       }
-                       /* NOTREACHED */
-#else
-                       return 0;
-#endif
-
-
-               default:
-                       return -ENOIOCTLCMD;
-               }
-       return 0;
-}
-
-/* FIX UP modem control here someday......
-*/
-static void rs_360_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-
-       change_speed(info);
-
-#ifdef modem_control
-       /* Handle transition to B0 status */
-       if ((old_termios->c_cflag & CBAUD) &&
-           !(tty->termios->c_cflag & CBAUD)) {
-               info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
-               local_irq_disable();
-               serial_out(info, UART_MCR, info->MCR);
-               local_irq_enable();
-       }
-       
-       /* Handle transition away from B0 status */
-       if (!(old_termios->c_cflag & CBAUD) &&
-           (tty->termios->c_cflag & CBAUD)) {
-               info->MCR |= UART_MCR_DTR;
-               if (!tty->hw_stopped ||
-                   !(tty->termios->c_cflag & CRTSCTS)) {
-                       info->MCR |= UART_MCR_RTS;
-               }
-               local_irq_disable();
-               serial_out(info, UART_MCR, info->MCR);
-               local_irq_enable();
-       }
-       
-       /* Handle turning off CRTSCTS */
-       if ((old_termios->c_cflag & CRTSCTS) &&
-           !(tty->termios->c_cflag & CRTSCTS)) {
-               tty->hw_stopped = 0;
-               rs_360_start(tty);
-       }
-#endif
-
-#if 0
-       /*
-        * No need to wake up processes in open wait, since they
-        * sample the CLOCAL flag once, and don't recheck it.
-        * XXX  It's not clear whether the current behavior is correct
-        * or not.  Hence, this may change.....
-        */
-       if (!(old_termios->c_cflag & CLOCAL) &&
-           (tty->termios->c_cflag & CLOCAL))
-               wake_up_interruptible(&info->open_wait);
-#endif
-}
-
-/*
- * ------------------------------------------------------------
- * rs_close()
- * 
- * This routine is called when the serial port gets closed.  First, we
- * wait for the last remaining data to be sent.  Then, we unlink its
- * async structure from the interrupt chain if necessary, and we free
- * that IRQ if nothing is left in the chain.
- * ------------------------------------------------------------
- */
-static void rs_360_close(struct tty_struct *tty, struct file * filp)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-       /* struct async_state *state; */
-       struct serial_state *state;
-       unsigned long   flags;
-       int             idx;
-       volatile struct smc_regs        *smcp;
-       volatile struct scc_regs        *sccp;
-
-       if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
-               return;
-
-       state = info->state;
-       
-       local_irq_save(flags);
-       
-       if (tty_hung_up_p(filp)) {
-               DBG_CNT("before DEC-hung");
-               local_irq_restore(flags);
-               return;
-       }
-       
-#ifdef SERIAL_DEBUG_OPEN
-       printk("rs_close ttys%d, count = %d\n", info->line, state->count);
-#endif
-       if ((tty->count == 1) && (state->count != 1)) {
-               /*
-                * Uh, oh.  tty->count is 1, which means that the tty
-                * structure will be freed.  state->count should always
-                * be one in these conditions.  If it's greater than
-                * one, we've got real problems, since it means the
-                * serial port won't be shutdown.
-                */
-               printk("rs_close: bad serial port count; tty->count is 1, "
-                      "state->count is %d\n", state->count);
-               state->count = 1;
-       }
-       if (--state->count < 0) {
-               printk("rs_close: bad serial port count for ttys%d: %d\n",
-                      info->line, state->count);
-               state->count = 0;
-       }
-       if (state->count) {
-               DBG_CNT("before DEC-2");
-               local_irq_restore(flags);
-               return;
-       }
-       info->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 (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, info->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.
-        */
-       info->read_status_mask &= ~BD_SC_EMPTY;
-       if (info->flags & ASYNC_INITIALIZED) {
-
-               idx = PORT_NUM(info->state->smc_scc_num);
-               if (info->state->smc_scc_num & NUM_IS_SCC) {
-                       sccp = &pquicc->scc_regs[idx];
-                       sccp->scc_sccm &= ~UART_SCCM_RX;
-                       sccp->scc_gsmr.w.low &= ~SCC_GSMRL_ENR;
-               } else {
-                       smcp = &pquicc->smc_regs[idx];
-                       smcp->smc_smcm &= ~SMCM_RX;
-                       smcp->smc_smcmr &= ~SMCMR_REN;
-               }
-               /*
-                * Before we drop DTR, make sure the UART transmitter
-                * has completely drained; this is especially
-                * important if there is a transmit FIFO!
-                */
-               rs_360_wait_until_sent(tty, info->timeout);
-       }
-       shutdown(info);
-       rs_360_flush_buffer(tty);
-       tty_ldisc_flush(tty);           
-       tty->closing = 0;
-       info->event = 0;
-       info->port.tty = NULL;
-       if (info->blocked_open) {
-               if (info->close_delay) {
-                       msleep_interruptible(jiffies_to_msecs(info->close_delay));
-               }
-               wake_up_interruptible(&info->open_wait);
-       }
-       info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-       wake_up_interruptible(&info->close_wait);
-       local_irq_restore(flags);
-}
-
-/*
- * rs_wait_until_sent() --- wait until the transmitter is empty
- */
-static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-       unsigned long orig_jiffies, char_time;
-       /*int lsr;*/
-       volatile QUICC_BD *bdp;
-       
-       if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
-               return;
-
-#ifdef maybe
-       if (info->state->type == PORT_UNKNOWN)
-               return;
-#endif
-
-       orig_jiffies = jiffies;
-       /*
-        * Set the check interval to be 1/5 of the estimated time to
-        * send a single character, and make it at least 1.  The check
-        * interval should also be less than the timeout.
-        * 
-        * Note: we have to use pretty tight timings here to satisfy
-        * the NIST-PCTS.
-        */
-       char_time = 1;
-       if (timeout)
-               char_time = min(char_time, (unsigned long)timeout);
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-       printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
-       printk("jiff=%lu...", jiffies);
-#endif
-
-       /* We go through the loop at least once because we can't tell
-        * exactly when the last character exits the shifter.  There can
-        * be at least two characters waiting to be sent after the buffers
-        * are empty.
-        */
-       do {
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-               printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
-#endif
-/*             current->counter = 0;    make us low-priority */
-               msleep_interruptible(jiffies_to_msecs(char_time));
-               if (signal_pending(current))
-                       break;
-               if (timeout && (time_after(jiffies, orig_jiffies + timeout)))
-                       break;
-               /* The 'tx_cur' is really the next buffer to send.  We
-                * have to back up to the previous BD and wait for it
-                * to go.  This isn't perfect, because all this indicates
-                * is the buffer is available.  There are still characters
-                * in the CPM FIFO.
-                */
-               bdp = info->tx_cur;
-               if (bdp == info->tx_bd_base)
-                       bdp += (TX_NUM_FIFO-1);
-               else
-                       bdp--;
-       } while (bdp->status & BD_SC_READY);
-       current->state = TASK_RUNNING;
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-       printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
-#endif
-}
-
-/*
- * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-static void rs_360_hangup(struct tty_struct *tty)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-       struct serial_state *state = info->state;
-       
-       if (serial_paranoia_check(info, tty->name, "rs_hangup"))
-               return;
-
-       state = info->state;
-       
-       rs_360_flush_buffer(tty);
-       shutdown(info);
-       info->event = 0;
-       state->count = 0;
-       info->flags &= ~ASYNC_NORMAL_ACTIVE;
-       info->port.tty = NULL;
-       wake_up_interruptible(&info->open_wait);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_open() and friends
- * ------------------------------------------------------------
- */
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
-                          ser_info_t *info)
-{
-#ifdef DO_THIS_LATER
-       DECLARE_WAITQUEUE(wait, current);
-#endif
-       struct serial_state *state = info->state;
-       int             retval;
-       int             do_clocal = 0;
-
-       /*
-        * 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) ||
-           (info->flags & ASYNC_CLOSING)) {
-               if (info->flags & ASYNC_CLOSING)
-                       interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
-               if (info->flags & ASYNC_HUP_NOTIFY)
-                       return -EAGAIN;
-               else
-                       return -ERESTARTSYS;
-#else
-               return -EAGAIN;
-#endif
-       }
-
-       /*
-        * If non-blocking mode is set, or the port is not enabled,
-        * then make the check up front and then exit.
-        * If this is an SMC port, we don't have modem control to wait
-        * for, so just get out here.
-        */
-       if ((filp->f_flags & O_NONBLOCK) ||
-           (tty->flags & (1 << TTY_IO_ERROR)) ||
-           !(info->state->smc_scc_num & NUM_IS_SCC)) {
-               info->flags |= ASYNC_NORMAL_ACTIVE;
-               return 0;
-       }
-
-       if (tty->termios->c_cflag & CLOCAL)
-               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, state->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;
-#ifdef DO_THIS_LATER
-       add_wait_queue(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
-       printk("block_til_ready before block: ttys%d, count = %d\n",
-              state->line, state->count);
-#endif
-       local_irq_disable();
-       if (!tty_hung_up_p(filp)) 
-               state->count--;
-       local_irq_enable();
-       info->blocked_open++;
-       while (1) {
-               local_irq_disable();
-               if (tty->termios->c_cflag & CBAUD)
-                       serial_out(info, UART_MCR,
-                                  serial_inp(info, UART_MCR) |
-                                  (UART_MCR_DTR | UART_MCR_RTS));
-               local_irq_enable();
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (tty_hung_up_p(filp) ||
-                   !(info->flags & ASYNC_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
-                       if (info->flags & ASYNC_HUP_NOTIFY)
-                               retval = -EAGAIN;
-                       else
-                               retval = -ERESTARTSYS;  
-#else
-                       retval = -EAGAIN;
-#endif
-                       break;
-               }
-               if (!(info->flags & ASYNC_CLOSING) &&
-                   (do_clocal || (serial_in(info, UART_MSR) &
-                                  UART_MSR_DCD)))
-                       break;
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-#ifdef SERIAL_DEBUG_OPEN
-               printk("block_til_ready blocking: ttys%d, count = %d\n",
-                      info->line, state->count);
-#endif
-               tty_unlock();
-               schedule();
-               tty_lock();
-       }
-       current->state = TASK_RUNNING;
-       remove_wait_queue(&info->open_wait, &wait);
-       if (!tty_hung_up_p(filp))
-               state->count++;
-       info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
-       printk("block_til_ready after blocking: ttys%d, count = %d\n",
-              info->line, state->count);
-#endif
-#endif /* DO_THIS_LATER */
-       if (retval)
-               return retval;
-       info->flags |= ASYNC_NORMAL_ACTIVE;
-       return 0;
-}
-
-static int get_async_struct(int line, ser_info_t **ret_info)
-{
-       struct serial_state *sstate;
-
-       sstate = rs_table + line;
-       if (sstate->info) {
-               sstate->count++;
-               *ret_info = (ser_info_t *)sstate->info;
-               return 0;
-       }
-       else {
-               return -ENOMEM;
-       }
-}
-
-/*
- * This routine is called whenever a serial port is opened.  It
- * enables interrupts for a serial port, linking in its async structure into
- * the IRQ chain.   It also performs the serial-specific
- * initialization for the tty structure.
- */
-static int rs_360_open(struct tty_struct *tty, struct file * filp)
-{
-       ser_info_t      *info;
-       int             retval, line;
-
-       line = tty->index;
-       if ((line < 0) || (line >= NR_PORTS))
-               return -ENODEV;
-       retval = get_async_struct(line, &info);
-       if (retval)
-               return retval;
-       if (serial_paranoia_check(info, tty->name, "rs_open"))
-               return -ENODEV;
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("rs_open %s, count = %d\n", tty->name, info->state->count);
-#endif
-       tty->driver_data = info;
-       info->port.tty = tty;
-
-       /*
-        * Start up serial port
-        */
-       retval = startup(info);
-       if (retval)
-               return retval;
-
-       retval = block_til_ready(tty, filp, info);
-       if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
-               printk("rs_open returning after block_til_ready with %d\n",
-                      retval);
-#endif
-               return retval;
-       }
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("rs_open %s successful...", tty->name);
-#endif
-       return 0;
-}
-
-/*
- * /proc fs routines....
- */
-
-static inline int line_info(char *buf, struct serial_state *state)
-{
-#ifdef notdef
-       struct async_struct *info = state->info, scr_info;
-       char    stat_buf[30], control, status;
-#endif
-       int     ret;
-
-       ret = sprintf(buf, "%d: uart:%s port:%X irq:%d",
-                     state->line,
-                     (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC",
-                     (unsigned int)(state->port), state->irq);
-
-       if (!state->port || (state->type == PORT_UNKNOWN)) {
-               ret += sprintf(buf+ret, "\n");
-               return ret;
-       }
-
-#ifdef notdef
-       /*
-        * Figure out the current RS-232 lines
-        */
-       if (!info) {
-               info = &scr_info;       /* This is just for serial_{in,out} */
-
-               info->magic = SERIAL_MAGIC;
-               info->port = state->port;
-               info->flags = state->flags;
-               info->quot = 0;
-               info->port.tty = NULL;
-       }
-       local_irq_disable();
-       status = serial_in(info, UART_MSR);
-       control = info ? info->MCR : serial_in(info, UART_MCR);
-       local_irq_enable();
-       
-       stat_buf[0] = 0;
-       stat_buf[1] = 0;
-       if (control & UART_MCR_RTS)
-               strcat(stat_buf, "|RTS");
-       if (status & UART_MSR_CTS)
-               strcat(stat_buf, "|CTS");
-       if (control & UART_MCR_DTR)
-               strcat(stat_buf, "|DTR");
-       if (status & UART_MSR_DSR)
-               strcat(stat_buf, "|DSR");
-       if (status & UART_MSR_DCD)
-               strcat(stat_buf, "|CD");
-       if (status & UART_MSR_RI)
-               strcat(stat_buf, "|RI");
-
-       if (info->quot) {
-               ret += sprintf(buf+ret, " baud:%d",
-                              state->baud_base / info->quot);
-       }
-
-       ret += sprintf(buf+ret, " tx:%d rx:%d",
-                     state->icount.tx, state->icount.rx);
-
-       if (state->icount.frame)
-               ret += sprintf(buf+ret, " fe:%d", state->icount.frame);
-       
-       if (state->icount.parity)
-               ret += sprintf(buf+ret, " pe:%d", state->icount.parity);
-       
-       if (state->icount.brk)
-               ret += sprintf(buf+ret, " brk:%d", state->icount.brk);  
-
-       if (state->icount.overrun)
-               ret += sprintf(buf+ret, " oe:%d", state->icount.overrun);
-
-       /*
-        * Last thing is the RS-232 status lines
-        */
-       ret += sprintf(buf+ret, " %s\n", stat_buf+1);
-#endif
-       return ret;
-}
-
-int rs_360_read_proc(char *page, char **start, off_t off, int count,
-                int *eof, void *data)
-{
-       int i, len = 0;
-       off_t   begin = 0;
-
-       len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
-       for (i = 0; i < NR_PORTS && len < 4000; i++) {
-               len += line_info(page + len, &rs_table[i]);
-               if (len+begin > off+count)
-                       goto done;
-               if (len+begin < off) {
-                       begin += len;
-                       len = 0;
-               }
-       }
-       *eof = 1;
-done:
-       if (off >= len+begin)
-               return 0;
-       *start = page + (begin-off);
-       return ((count < begin+len-off) ? count : begin+len-off);
-}
-
-/*
- * ---------------------------------------------------------------------
- * rs_init() and friends
- *
- * rs_init() is called at boot-time to initialize the serial driver.
- * ---------------------------------------------------------------------
- */
-
-/*
- * This routine prints out the appropriate serial driver version
- * number, and identifies which options were configured into this
- * driver.
- */
-static _INLINE_ void show_serial_version(void)
-{
-       printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
-}
-
-
-/*
- * The serial console driver used during boot.  Note that these names
- * clash with those found in "serial.c", so we currently can't support
- * the 16xxx uarts and these at the same time.  I will fix this to become
- * an indirect function call from tty_io.c (or something).
- */
-
-#ifdef CONFIG_SERIAL_CONSOLE
-
-/*
- * Print a string to the serial port trying not to disturb any possible
- * real use of the port...
- */
-static void my_console_write(int idx, const char *s,
-                               unsigned count)
-{
-       struct          serial_state    *ser;
-       ser_info_t              *info;
-       unsigned                i;
-       QUICC_BD                *bdp, *bdbase;
-       volatile struct smc_uart_pram   *up;
-       volatile        u_char          *cp;
-
-       ser = rs_table + idx;
-
-
-       /* If the port has been initialized for general use, we have
-        * to use the buffer descriptors allocated there.  Otherwise,
-        * we simply use the single buffer allocated.
-        */
-       if ((info = (ser_info_t *)ser->info) != NULL) {
-               bdp = info->tx_cur;
-               bdbase = info->tx_bd_base;
-       }
-       else {
-               /* Pointer to UART in parameter ram.
-               */
-               /* up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; */
-               up = &pquicc->pram[ser->port].scc.pothers.idma_smc.psmc.u;
-
-               /* Get the address of the host memory buffer.
-                */
-               bdp = bdbase = (QUICC_BD *)((uint)pquicc + (uint)up->tbase);
-       }
-
-       /*
-        * We need to gracefully shut down the transmitter, disable
-        * interrupts, then send our bytes out.
-        */
-
-       /*
-        * Now, do each character.  This is not as bad as it looks
-        * since this is a holding FIFO and not a transmitting FIFO.
-        * We could add the complexity of filling the entire transmit
-        * buffer, but we would just wait longer between accesses......
-        */
-       for (i = 0; i < count; i++, s++) {
-               /* Wait for transmitter fifo to empty.
-                * Ready indicates output is ready, and xmt is doing
-                * that, not that it is ready for us to send.
-                */
-               while (bdp->status & BD_SC_READY);
-
-               /* Send the character out.
-                */
-               cp = bdp->buf;
-               *cp = *s;
-               
-               bdp->length = 1;
-               bdp->status |= BD_SC_READY;
-
-               if (bdp->status & BD_SC_WRAP)
-                       bdp = bdbase;
-               else
-                       bdp++;
-
-               /* if a LF, also do CR... */
-               if (*s == 10) {
-                       while (bdp->status & BD_SC_READY);
-                       /* cp = __va(bdp->buf); */
-                       cp = bdp->buf;
-                       *cp = 13;
-                       bdp->length = 1;
-                       bdp->status |= BD_SC_READY;
-
-                       if (bdp->status & BD_SC_WRAP) {
-                               bdp = bdbase;
-                       }
-                       else {
-                               bdp++;
-                       }
-               }
-       }
-
-       /*
-        * Finally, Wait for transmitter & holding register to empty
-        *  and restore the IER
-        */
-       while (bdp->status & BD_SC_READY);
-
-       if (info)
-               info->tx_cur = (QUICC_BD *)bdp;
-}
-
-static void serial_console_write(struct console *c, const char *s,
-                               unsigned count)
-{
-#ifdef CONFIG_KGDB
-       /* Try to let stub handle output. Returns true if it did. */ 
-       if (kgdb_output_string(s, count))
-               return;
-#endif
-       my_console_write(c->index, s, count);
-}
-
-
-
-/*void console_print_68360(const char *p)
-{
-       const char *cp = p;
-       int i;
-
-       for (i=0;cp[i]!=0;i++);
-
-       serial_console_write (p, i);
-
-       //Comment this if you want to have a strict interrupt-driven output
-       //rs_fair_output();
-
-       return;
-}*/
-
-
-
-
-
-
-#ifdef CONFIG_XMON
-int
-xmon_360_write(const char *s, unsigned count)
-{
-       my_console_write(0, s, count);
-       return(count);
-}
-#endif
-
-#ifdef CONFIG_KGDB
-void
-putDebugChar(char ch)
-{
-       my_console_write(0, &ch, 1);
-}
-#endif
-
-/*
- * Receive character from the serial port.  This only works well
- * before the port is initialized for real use.
- */
-static int my_console_wait_key(int idx, int xmon, char *obuf)
-{
-       struct serial_state             *ser;
-       u_char                  c, *cp;
-       ser_info_t              *info;
-       QUICC_BD                *bdp;
-       volatile struct smc_uart_pram   *up;
-       int                             i;
-
-       ser = rs_table + idx;
-
-       /* Get the address of the host memory buffer.
-        * If the port has been initialized for general use, we must
-        * use information from the port structure.
-        */
-       if ((info = (ser_info_t *)ser->info))
-               bdp = info->rx_cur;
-       else
-               /* bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_rbase]; */
-               bdp = (QUICC_BD *)((uint)pquicc + (uint)up->tbase);
-
-       /* Pointer to UART in parameter ram.
-        */
-       /* up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; */
-       up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u;
-
-       /*
-        * We need to gracefully shut down the receiver, disable
-        * interrupts, then read the input.
-        * XMON just wants a poll.  If no character, return -1, else
-        * return the character.
-        */
-       if (!xmon) {
-               while (bdp->status & BD_SC_EMPTY);
-       }
-       else {
-               if (bdp->status & BD_SC_EMPTY)
-                       return -1;
-       }
-
-       cp = (char *)bdp->buf;
-
-       if (obuf) {
-               i = c = bdp->length;
-               while (i-- > 0)
-                       *obuf++ = *cp++;
-       }
-       else {
-               c = *cp;
-       }
-       bdp->status |= BD_SC_EMPTY;
-
-       if (info) {
-               if (bdp->status & BD_SC_WRAP) {
-                       bdp = info->rx_bd_base;
-               }
-               else {
-                       bdp++;
-               }
-               info->rx_cur = (QUICC_BD *)bdp;
-       }
-
-       return((int)c);
-}
-
-static int serial_console_wait_key(struct console *co)
-{
-       return(my_console_wait_key(co->index, 0, NULL));
-}
-
-#ifdef CONFIG_XMON
-int
-xmon_360_read_poll(void)
-{
-       return(my_console_wait_key(0, 1, NULL));
-}
-
-int
-xmon_360_read_char(void)
-{
-       return(my_console_wait_key(0, 0, NULL));
-}
-#endif
-
-#ifdef CONFIG_KGDB
-static char kgdb_buf[RX_BUF_SIZE], *kgdp;
-static int kgdb_chars;
-
-unsigned char
-getDebugChar(void)
-{
-       if (kgdb_chars <= 0) {
-               kgdb_chars = my_console_wait_key(0, 0, kgdb_buf);
-               kgdp = kgdb_buf;
-       }
-       kgdb_chars--;
-
-       return(*kgdp++);
-}
-
-void kgdb_interruptible(int state)
-{
-}
-void kgdb_map_scc(void)
-{
-       struct          serial_state *ser;
-       uint            mem_addr;
-       volatile        QUICC_BD                *bdp;
-       volatile        smc_uart_t      *up;
-
-       cpmp = (cpm360_t *)&(((immap_t *)IMAP_ADDR)->im_cpm);
-
-       /* To avoid data cache CPM DMA coherency problems, allocate a
-        * buffer in the CPM DPRAM.  This will work until the CPM and
-        * serial ports are initialized.  At that time a memory buffer
-        * will be allocated.
-        * The port is already initialized from the boot procedure, all
-        * we do here is give it a different buffer and make it a FIFO.
-        */
-
-       ser = rs_table;
-
-       /* Right now, assume we are using SMCs.
-       */
-       up = (smc_uart_t *)&cpmp->cp_dparam[ser->port];
-
-       /* Allocate space for an input FIFO, plus a few bytes for output.
-        * Allocate bytes to maintain word alignment.
-        */
-       mem_addr = (uint)(&cpmp->cp_dpmem[0x1000]);
-
-       /* Set the physical address of the host memory buffers in
-        * the buffer descriptors.
-        */
-       bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_rbase];
-       bdp->buf = mem_addr;
-
-       bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_tbase];
-       bdp->buf = mem_addr+RX_BUF_SIZE;
-
-       up->smc_mrblr = RX_BUF_SIZE;            /* receive buffer length */
-       up->smc_maxidl = RX_BUF_SIZE;
-}
-#endif
-
-static struct tty_struct *serial_console_device(struct console *c, int *index)
-{
-       *index = c->index;
-       return serial_driver;
-}
-
-
-struct console sercons = {
-       .name           = "ttyS",
-       .write          = serial_console_write,
-       .device         = serial_console_device,
-       .wait_key       = serial_console_wait_key,
-       .setup          = serial_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = CONFIG_SERIAL_CONSOLE_PORT, 
-};
-
-
-
-/*
- *     Register console.
- */
-long console_360_init(long kmem_start, long kmem_end)
-{
-       register_console(&sercons);
-       /*register_console (console_print_68360); - 2.0.38 only required a write
-      function pointer. */
-       return kmem_start;
-}
-
-#endif
-
-/* Index in baud rate table of the default console baud rate.
-*/
-static int     baud_idx;
-
-static const struct tty_operations rs_360_ops = {
-       .owner = THIS_MODULE,
-       .open = rs_360_open,
-       .close = rs_360_close,
-       .write = rs_360_write,
-       .put_char = rs_360_put_char,
-       .write_room = rs_360_write_room,
-       .chars_in_buffer = rs_360_chars_in_buffer,
-       .flush_buffer = rs_360_flush_buffer,
-       .ioctl = rs_360_ioctl,
-       .throttle = rs_360_throttle,
-       .unthrottle = rs_360_unthrottle,
-       /* .send_xchar = rs_360_send_xchar, */
-       .set_termios = rs_360_set_termios,
-       .stop = rs_360_stop,
-       .start = rs_360_start,
-       .hangup = rs_360_hangup,
-       /* .wait_until_sent = rs_360_wait_until_sent, */
-       /* .read_proc = rs_360_read_proc, */
-       .tiocmget = rs_360_tiocmget,
-       .tiocmset = rs_360_tiocmset,
-};
-
-static int __init rs_360_init(void)
-{
-       struct serial_state * state;
-       ser_info_t      *info;
-       void       *mem_addr;
-       uint            dp_addr, iobits;
-       int                 i, j, idx;
-       ushort          chan;
-       QUICC_BD        *bdp;
-       volatile        QUICC           *cp;
-       volatile        struct smc_regs *sp;
-       volatile        struct smc_uart_pram    *up;
-       volatile        struct scc_regs *scp;
-       volatile        struct uart_pram        *sup;
-       /* volatile     immap_t         *immap; */
-       
-       serial_driver = alloc_tty_driver(NR_PORTS);
-       if (!serial_driver)
-               return -1;
-
-       show_serial_version();
-
-       serial_driver->name = "ttyS";
-       serial_driver->major = TTY_MAJOR;
-       serial_driver->minor_start = 64;
-       serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
-       serial_driver->subtype = SERIAL_TYPE_NORMAL;
-       serial_driver->init_termios = tty_std_termios;
-       serial_driver->init_termios.c_cflag =
-               baud_idx | CS8 | CREAD | HUPCL | CLOCAL;
-       serial_driver->flags = TTY_DRIVER_REAL_RAW;
-       tty_set_operations(serial_driver, &rs_360_ops);
-       
-       if (tty_register_driver(serial_driver))
-               panic("Couldn't register serial driver\n");
-
-       cp = pquicc;    /* Get pointer to Communication Processor */
-       /* immap = (immap_t *)IMAP_ADDR; */     /* and to internal registers */
-
-
-       /* Configure SCC2, SCC3, and SCC4 instead of port A parallel I/O.
-        */
-       /* The "standard" configuration through the 860.
-       */
-/*     immap->im_ioport.iop_papar |= 0x00fc; */
-/*     immap->im_ioport.iop_padir &= ~0x00fc; */
-/*     immap->im_ioport.iop_paodr &= ~0x00fc; */
-       cp->pio_papar |= 0x00fc;
-       cp->pio_padir &= ~0x00fc;
-       /* cp->pio_paodr &= ~0x00fc; */
-
-
-       /* Since we don't yet do modem control, connect the port C pins
-        * as general purpose I/O.  This will assert CTS and CD for the
-        * SCC ports.
-        */
-       /* FIXME: see 360um p.7-365 and 860um p.34-12 
-        * I can't make sense of these bits - mleslie*/
-/*     immap->im_ioport.iop_pcdir |= 0x03c6; */
-/*     immap->im_ioport.iop_pcpar &= ~0x03c6; */
-
-/*     cp->pio_pcdir |= 0x03c6; */
-/*     cp->pio_pcpar &= ~0x03c6; */
-
-
-
-       /* Connect SCC2 and SCC3 to NMSI.  Connect BRG3 to SCC2 and
-        * BRG4 to SCC3.
-        */
-       cp->si_sicr &= ~0x00ffff00;
-       cp->si_sicr |=  0x001b1200;
-
-#ifdef CONFIG_PP04
-       /* Frequentis PP04 forced to RS-232 until we know better.
-        * Port C 12 and 13 low enables RS-232 on SCC3 and SCC4.
-        */
-       immap->im_ioport.iop_pcdir |= 0x000c;
-       immap->im_ioport.iop_pcpar &= ~0x000c;
-       immap->im_ioport.iop_pcdat &= ~0x000c;
-
-       /* This enables the TX driver.
-       */
-       cp->cp_pbpar &= ~0x6000;
-       cp->cp_pbdat &= ~0x6000;
-#endif
-
-       for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
-               state->magic = SSTATE_MAGIC;
-               state->line = i;
-               state->type = PORT_UNKNOWN;
-               state->custom_divisor = 0;
-               state->close_delay = 5*HZ/10;
-               state->closing_wait = 30*HZ;
-               state->icount.cts = state->icount.dsr = 
-                       state->icount.rng = state->icount.dcd = 0;
-               state->icount.rx = state->icount.tx = 0;
-               state->icount.frame = state->icount.parity = 0;
-               state->icount.overrun = state->icount.brk = 0;
-               printk(KERN_INFO "ttyS%d at irq 0x%02x is an %s\n",
-                      i, (unsigned int)(state->irq),
-                      (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC");
-
-#ifdef CONFIG_SERIAL_CONSOLE
-               /* If we just printed the message on the console port, and
-                * we are about to initialize it for general use, we have
-                * to wait a couple of character times for the CR/NL to
-                * make it out of the transmit buffer.
-                */
-               if (i == CONFIG_SERIAL_CONSOLE_PORT)
-                       mdelay(8);
-
-
-/*             idx = PORT_NUM(info->state->smc_scc_num); */
-/*             if (info->state->smc_scc_num & NUM_IS_SCC) */
-/*                     chan = scc_chan_map[idx]; */
-/*             else */
-/*                     chan = smc_chan_map[idx]; */
-
-/*             cp->cp_cr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG; */
-/*             while (cp->cp_cr & CPM_CR_FLG); */
-
-#endif
-               /* info = kmalloc(sizeof(ser_info_t), GFP_KERNEL); */
-               info = &quicc_ser_info[i];
-               if (info) {
-                       memset (info, 0, sizeof(ser_info_t));
-                       info->magic = SERIAL_MAGIC;
-                       info->line = i;
-                       info->flags = state->flags;
-                       INIT_WORK(&info->tqueue, do_softint, info);
-                       INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info);
-                       init_waitqueue_head(&info->open_wait);
-                       init_waitqueue_head(&info->close_wait);
-                       info->state = state;
-                       state->info = (struct async_struct *)info;
-
-                       /* We need to allocate a transmit and receive buffer
-                        * descriptors from dual port ram, and a character
-                        * buffer area from host mem.
-                        */
-                       dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * RX_NUM_FIFO);
-
-                       /* Allocate space for FIFOs in the host memory.
-                        *  (for now this is from a static array of buffers :(
-                        */
-                       /* mem_addr = m360_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE); */
-                       /* mem_addr = kmalloc (RX_NUM_FIFO * RX_BUF_SIZE, GFP_BUFFER); */
-                       mem_addr = &rx_buf_pool[i * RX_NUM_FIFO * RX_BUF_SIZE];
-
-                       /* Set the physical address of the host memory
-                        * buffers in the buffer descriptors, and the
-                        * virtual address for us to work with.
-                        */
-                       bdp = (QUICC_BD *)((uint)pquicc + dp_addr);
-                       info->rx_cur = info->rx_bd_base = bdp;
-
-                       /* initialize rx buffer descriptors */
-                       for (j=0; j<(RX_NUM_FIFO-1); j++) {
-                               bdp->buf = &rx_buf_pool[(i * RX_NUM_FIFO + j ) * RX_BUF_SIZE];
-                               bdp->status = BD_SC_EMPTY | BD_SC_INTRPT;
-                               mem_addr += RX_BUF_SIZE;
-                               bdp++;
-                       }
-                       bdp->buf = &rx_buf_pool[(i * RX_NUM_FIFO + j ) * RX_BUF_SIZE];
-                       bdp->status = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
-
-
-                       idx = PORT_NUM(info->state->smc_scc_num);
-                       if (info->state->smc_scc_num & NUM_IS_SCC) {
-
-#if defined (CONFIG_UCQUICC) && 1
-                               /* set the transceiver mode to RS232 */
-                               sipex_mode_bits &= ~(uint)SIPEX_MODE(idx,0x0f); /* clear current mode */
-                               sipex_mode_bits |= (uint)SIPEX_MODE(idx,0x02);
-                               *(uint *)_periph_base = sipex_mode_bits;
-                               /* printk ("sipex bits = 0x%08x\n", sipex_mode_bits); */
-#endif
-                       }
-
-                       dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * TX_NUM_FIFO);
-
-                       /* Allocate space for FIFOs in the host memory.
-                       */
-                       /* mem_addr = m360_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE); */
-                       /* mem_addr = kmalloc (TX_NUM_FIFO * TX_BUF_SIZE, GFP_BUFFER); */
-                       mem_addr = &tx_buf_pool[i * TX_NUM_FIFO * TX_BUF_SIZE];
-
-                       /* Set the physical address of the host memory
-                        * buffers in the buffer descriptors, and the
-                        * virtual address for us to work with.
-                        */
-                       /* bdp = (QUICC_BD *)&cp->cp_dpmem[dp_addr]; */
-                       bdp = (QUICC_BD *)((uint)pquicc + dp_addr);
-                       info->tx_cur = info->tx_bd_base = (QUICC_BD *)bdp;
-
-                       /* initialize tx buffer descriptors */
-                       for (j=0; j<(TX_NUM_FIFO-1); j++) {
-                               bdp->buf = &tx_buf_pool[(i * TX_NUM_FIFO + j ) * TX_BUF_SIZE];
-                               bdp->status = BD_SC_INTRPT;
-                               mem_addr += TX_BUF_SIZE;
-                               bdp++;
-                       }
-                       bdp->buf = &tx_buf_pool[(i * TX_NUM_FIFO + j ) * TX_BUF_SIZE];
-                       bdp->status = (BD_SC_WRAP | BD_SC_INTRPT);
-
-                       if (info->state->smc_scc_num & NUM_IS_SCC) {
-                               scp = &pquicc->scc_regs[idx];
-                               sup = &pquicc->pram[info->state->port].scc.pscc.u;
-                               sup->rbase = dp_addr;
-                               sup->tbase = dp_addr;
-
-                               /* Set up the uart parameters in the
-                                * parameter ram.
-                                */
-                               sup->rfcr = SMC_EB;
-                               sup->tfcr = SMC_EB;
-
-                               /* Set this to 1 for now, so we get single
-                                * character interrupts.  Using idle character
-                                * time requires some additional tuning.
-                                */
-                               sup->mrblr = 1;
-                               sup->max_idl = 0;
-                               sup->brkcr = 1;
-                               sup->parec = 0;
-                               sup->frmer = 0;
-                               sup->nosec = 0;
-                               sup->brkec = 0;
-                               sup->uaddr1 = 0;
-                               sup->uaddr2 = 0;
-                               sup->toseq = 0;
-                               {
-                                       int i;
-                                       for (i=0;i<8;i++)
-                                               sup->cc[i] = 0x8000;
-                               }
-                               sup->rccm = 0xc0ff;
-
-                               /* Send the CPM an initialize command.
-                               */
-                               chan = scc_chan_map[idx];
-
-                               /* execute the INIT RX & TX PARAMS command for this channel. */
-                               cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG;
-                               while (cp->cp_cr & CPM_CR_FLG);
-
-                               /* Set UART mode, 8 bit, no parity, one stop.
-                                * Enable receive and transmit.
-                                */
-                               scp->scc_gsmr.w.high = 0;
-                               scp->scc_gsmr.w.low = 
-                                       (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
-
-                               /* Disable all interrupts and clear all pending
-                                * events.
-                                */
-                               scp->scc_sccm = 0;
-                               scp->scc_scce = 0xffff;
-                               scp->scc_dsr = 0x7e7e;
-                               scp->scc_psmr = 0x3000;
-
-                               /* If the port is the console, enable Rx and Tx.
-                               */
-#ifdef CONFIG_SERIAL_CONSOLE
-                               if (i == CONFIG_SERIAL_CONSOLE_PORT)
-                                       scp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-#endif
-                       }
-                       else {
-                               /* Configure SMCs Tx/Rx instead of port B
-                                * parallel I/O.
-                                */
-                               up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u;
-                               up->rbase = dp_addr;
-
-                               iobits = 0xc0 << (idx * 4);
-                               cp->pip_pbpar |= iobits;
-                               cp->pip_pbdir &= ~iobits;
-                               cp->pip_pbodr &= ~iobits;
-
-
-                               /* Connect the baud rate generator to the
-                                * SMC based upon index in rs_table.  Also
-                                * make sure it is connected to NMSI.
-                                */
-                               cp->si_simode &= ~(0xffff << (idx * 16));
-                               cp->si_simode |= (i << ((idx * 16) + 12));
-
-                               up->tbase = dp_addr;
-
-                               /* Set up the uart parameters in the
-                                * parameter ram.
-                                */
-                               up->rfcr = SMC_EB;
-                               up->tfcr = SMC_EB;
-
-                               /* Set this to 1 for now, so we get single
-                                * character interrupts.  Using idle character
-                                * time requires some additional tuning.
-                                */
-                               up->mrblr = 1;
-                               up->max_idl = 0;
-                               up->brkcr = 1;
-
-                               /* Send the CPM an initialize command.
-                               */
-                               chan = smc_chan_map[idx];
-
-                               cp->cp_cr = mk_cr_cmd(chan,
-                                                                         CPM_CR_INIT_TRX) | CPM_CR_FLG;
-#ifdef CONFIG_SERIAL_CONSOLE
-                               if (i == CONFIG_SERIAL_CONSOLE_PORT)
-                                       printk("");
-#endif
-                               while (cp->cp_cr & CPM_CR_FLG);
-
-                               /* Set UART mode, 8 bit, no parity, one stop.
-                                * Enable receive and transmit.
-                                */
-                               sp = &cp->smc_regs[idx];
-                               sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART;
-
-                               /* Disable all interrupts and clear all pending
-                                * events.
-                                */
-                               sp->smc_smcm = 0;
-                               sp->smc_smce = 0xff;
-
-                               /* If the port is the console, enable Rx and Tx.
-                               */
-#ifdef CONFIG_SERIAL_CONSOLE
-                               if (i == CONFIG_SERIAL_CONSOLE_PORT)
-                                       sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
-#endif
-                       }
-
-                       /* Install interrupt handler.
-                       */
-                       /* cpm_install_handler(IRQ_MACHSPEC | state->irq, rs_360_interrupt, info);  */
-                       /*request_irq(IRQ_MACHSPEC | state->irq, rs_360_interrupt, */
-                       request_irq(state->irq, rs_360_interrupt,
-                                               IRQ_FLG_LOCK, "ttyS", (void *)info);
-
-                       /* Set up the baud rate generator.
-                       */
-                       m360_cpm_setbrg(i, baud_table[baud_idx]);
-
-               }
-       }
-
-       return 0;
-}
-module_init(rs_360_init);
-
-/* This must always be called before the rs_360_init() function, otherwise
- * it blows away the port control information.
- */
-//static int __init serial_console_setup( struct console *co, char *options)
-int serial_console_setup( struct console *co, char *options)
-{
-       struct          serial_state    *ser;
-       uint            mem_addr, dp_addr, bidx, idx, iobits;
-       ushort          chan;
-       QUICC_BD        *bdp;
-       volatile        QUICC                   *cp;
-       volatile        struct smc_regs *sp;
-       volatile        struct scc_regs *scp;
-       volatile        struct smc_uart_pram    *up;
-       volatile        struct uart_pram                *sup;
-
-/* mleslie TODO:
- * add something to the 68k bootloader to store a desired initial console baud rate */
-
-/*     bd_t                                            *bd; */ /* a board info struct used by EPPC-bug */
-/*     bd = (bd_t *)__res; */
-
-       for (bidx = 0; bidx < (sizeof(baud_table) / sizeof(int)); bidx++)
-        /* if (bd->bi_baudrate == baud_table[bidx]) */
-               if (CONSOLE_BAUDRATE == baud_table[bidx])
-                       break;
-
-       /* co->cflag = CREAD|CLOCAL|bidx|CS8; */
-       baud_idx = bidx;
-
-       ser = rs_table + CONFIG_SERIAL_CONSOLE_PORT;
-
-       cp = pquicc;    /* Get pointer to Communication Processor */
-
-       idx = PORT_NUM(ser->smc_scc_num);
-       if (ser->smc_scc_num & NUM_IS_SCC) {
-
-               /* TODO: need to set up SCC pin assignment etc. here */
-               
-       }
-       else {
-               iobits = 0xc0 << (idx * 4);
-               cp->pip_pbpar |= iobits;
-               cp->pip_pbdir &= ~iobits;
-               cp->pip_pbodr &= ~iobits;
-
-               /* Connect the baud rate generator to the
-                * SMC based upon index in rs_table.  Also
-                * make sure it is connected to NMSI.
-                */
-               cp->si_simode &= ~(0xffff << (idx * 16));
-               cp->si_simode |= (idx << ((idx * 16) + 12));
-       }
-
-       /* When we get here, the CPM has been reset, so we need
-        * to configure the port.
-        * We need to allocate a transmit and receive buffer descriptor
-        * from dual port ram, and a character buffer area from host mem.
-        */
-
-       /* Allocate space for two buffer descriptors in the DP ram.
-       */
-       dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * CONSOLE_NUM_FIFO);
-
-       /* Allocate space for two 2 byte FIFOs in the host memory.
-        */
-       /* mem_addr = m360_cpm_hostalloc(8); */
-       mem_addr = (uint)console_fifos;
-
-
-       /* Set the physical address of the host memory buffers in
-        * the buffer descriptors.
-        */
-       /* bdp = (QUICC_BD *)&cp->cp_dpmem[dp_addr]; */
-       bdp = (QUICC_BD *)((uint)pquicc + dp_addr);
-       bdp->buf = (char *)mem_addr;
-       (bdp+1)->buf = (char *)(mem_addr+4);
-
-       /* For the receive, set empty and wrap.
-        * For transmit, set wrap.
-        */
-       bdp->status = BD_SC_EMPTY | BD_SC_WRAP;
-       (bdp+1)->status = BD_SC_WRAP;
-
-       /* Set up the uart parameters in the parameter ram.
-        */
-       if (ser->smc_scc_num & NUM_IS_SCC) {
-               scp = &cp->scc_regs[idx];
-               /* sup = (scc_uart_t *)&cp->cp_dparam[ser->port]; */
-               sup = &pquicc->pram[ser->port].scc.pscc.u;
-
-               sup->rbase = dp_addr;
-               sup->tbase = dp_addr + sizeof(QUICC_BD);
-
-               /* Set up the uart parameters in the
-                * parameter ram.
-                */
-               sup->rfcr = SMC_EB;
-               sup->tfcr = SMC_EB;
-
-               /* Set this to 1 for now, so we get single
-                * character interrupts.  Using idle character
-                * time requires some additional tuning.
-                */
-               sup->mrblr = 1;
-               sup->max_idl = 0;
-               sup->brkcr = 1;
-               sup->parec = 0;
-               sup->frmer = 0;
-               sup->nosec = 0;
-               sup->brkec = 0;
-               sup->uaddr1 = 0;
-               sup->uaddr2 = 0;
-               sup->toseq = 0;
-               {
-                       int i;
-                       for (i=0;i<8;i++)
-                               sup->cc[i] = 0x8000;
-               }
-               sup->rccm = 0xc0ff;
-
-               /* Send the CPM an initialize command.
-               */
-               chan = scc_chan_map[idx];
-
-               cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG;
-               while (cp->cp_cr & CPM_CR_FLG);
-
-               /* Set UART mode, 8 bit, no parity, one stop.
-                * Enable receive and transmit.
-                */
-               scp->scc_gsmr.w.high = 0;
-               scp->scc_gsmr.w.low = 
-                       (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
-
-               /* Disable all interrupts and clear all pending
-                * events.
-                */
-               scp->scc_sccm = 0;
-               scp->scc_scce = 0xffff;
-               scp->scc_dsr = 0x7e7e;
-               scp->scc_psmr = 0x3000;
-
-               scp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-
-       }
-       else {
-               /* up = (smc_uart_t *)&cp->cp_dparam[ser->port]; */
-               up = &pquicc->pram[ser->port].scc.pothers.idma_smc.psmc.u;
-
-               up->rbase = dp_addr;    /* Base of receive buffer desc. */
-               up->tbase = dp_addr+sizeof(QUICC_BD);   /* Base of xmt buffer desc. */
-               up->rfcr = SMC_EB;
-               up->tfcr = SMC_EB;
-
-               /* Set this to 1 for now, so we get single character interrupts.
-               */
-               up->mrblr = 1;          /* receive buffer length */
-               up->max_idl = 0;                /* wait forever for next char */
-
-               /* Send the CPM an initialize command.
-               */
-               chan = smc_chan_map[idx];
-               cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG;
-               while (cp->cp_cr & CPM_CR_FLG);
-
-               /* Set UART mode, 8 bit, no parity, one stop.
-                * Enable receive and transmit.
-                */
-               sp = &cp->smc_regs[idx];
-               sp->smc_smcmr = smcr_mk_clen(9) |  SMCMR_SM_UART;
-
-               /* And finally, enable Rx and Tx.
-               */
-               sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
-       }
-
-       /* Set up the baud rate generator.
-       */
-       /* m360_cpm_setbrg((ser - rs_table), bd->bi_baudrate); */
-       m360_cpm_setbrg((ser - rs_table), CONSOLE_BAUDRATE);
-
-       return 0;
-}
-
-/*
- * Local variables:
- *  c-indent-level: 4
- *  c-basic-offset: 4
- *  tab-width: 4
- * End:
- */
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
deleted file mode 100644 (file)
index b25e6e4..0000000
+++ /dev/null
@@ -1,3377 +0,0 @@
-/*
- *  linux/drivers/char/8250.c
- *
- *  Driver for 8250/16550-type serial ports
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *
- *  Copyright (C) 2001 Russell King.
- *
- * 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.
- *
- * A note about mapbase / membase
- *
- *  mapbase is the physical address of the IO port.
- *  membase is an 'ioremapped' cookie.
- */
-
-#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/tty.h>
-#include <linux/ratelimit.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_reg.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/serial_8250.h>
-#include <linux/nmi.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "8250.h"
-
-#ifdef CONFIG_SPARC
-#include "suncore.h"
-#endif
-
-/*
- * Configuration:
- *   share_irqs - whether we pass IRQF_SHARED to request_irq().  This option
- *                is unsafe when used on edge-triggered interrupts.
- */
-static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
-
-static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
-
-static struct uart_driver serial8250_reg;
-
-static int serial_index(struct uart_port *port)
-{
-       return (serial8250_reg.minor - 64) + port->line;
-}
-
-static unsigned int skip_txen_test; /* force skip of txen test at init time */
-
-/*
- * Debugging.
- */
-#if 0
-#define DEBUG_AUTOCONF(fmt...) printk(fmt)
-#else
-#define DEBUG_AUTOCONF(fmt...) do { } while (0)
-#endif
-
-#if 0
-#define DEBUG_INTR(fmt...)     printk(fmt)
-#else
-#define DEBUG_INTR(fmt...)     do { } while (0)
-#endif
-
-#define PASS_LIMIT     256
-
-#define BOTH_EMPTY     (UART_LSR_TEMT | UART_LSR_THRE)
-
-
-/*
- * We default to IRQ0 for the "no irq" hack.   Some
- * machine types want others as well - they're free
- * to redefine this in their header file.
- */
-#define is_real_interrupt(irq) ((irq) != 0)
-
-#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
-#define CONFIG_SERIAL_DETECT_IRQ 1
-#endif
-#ifdef CONFIG_SERIAL_8250_MANY_PORTS
-#define CONFIG_SERIAL_MANY_PORTS 1
-#endif
-
-/*
- * HUB6 is always on.  This will be removed once the header
- * files have been cleaned.
- */
-#define CONFIG_HUB6 1
-
-#include <asm/serial.h>
-/*
- * SERIAL_PORT_DFNS tells us about built-in ports that have no
- * standard enumeration mechanism.   Platforms that can find all
- * serial ports via mechanisms like ACPI or PCI need not supply it.
- */
-#ifndef SERIAL_PORT_DFNS
-#define SERIAL_PORT_DFNS
-#endif
-
-static const struct old_serial_port old_serial_port[] = {
-       SERIAL_PORT_DFNS /* defined in asm/serial.h */
-};
-
-#define UART_NR        CONFIG_SERIAL_8250_NR_UARTS
-
-#ifdef CONFIG_SERIAL_8250_RSA
-
-#define PORT_RSA_MAX 4
-static unsigned long probe_rsa[PORT_RSA_MAX];
-static unsigned int probe_rsa_count;
-#endif /* CONFIG_SERIAL_8250_RSA  */
-
-struct uart_8250_port {
-       struct uart_port        port;
-       struct timer_list       timer;          /* "no irq" timer */
-       struct list_head        list;           /* ports on this IRQ */
-       unsigned short          capabilities;   /* port capabilities */
-       unsigned short          bugs;           /* port bugs */
-       unsigned int            tx_loadsz;      /* transmit fifo load size */
-       unsigned char           acr;
-       unsigned char           ier;
-       unsigned char           lcr;
-       unsigned char           mcr;
-       unsigned char           mcr_mask;       /* mask of user bits */
-       unsigned char           mcr_force;      /* mask of forced bits */
-       unsigned char           cur_iotype;     /* Running I/O type */
-
-       /*
-        * Some bits in registers are cleared on a read, so they must
-        * be saved whenever the register is read but the bits will not
-        * be immediately processed.
-        */
-#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
-       unsigned char           lsr_saved_flags;
-#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
-       unsigned char           msr_saved_flags;
-};
-
-struct irq_info {
-       struct                  hlist_node node;
-       int                     irq;
-       spinlock_t              lock;   /* Protects list not the hash */
-       struct list_head        *head;
-};
-
-#define NR_IRQ_HASH            32      /* Can be adjusted later */
-static struct hlist_head irq_lists[NR_IRQ_HASH];
-static DEFINE_MUTEX(hash_mutex);       /* Used to walk the hash */
-
-/*
- * Here we define the default xmit fifo size used for each type of UART.
- */
-static const struct serial8250_config uart_config[] = {
-       [PORT_UNKNOWN] = {
-               .name           = "unknown",
-               .fifo_size      = 1,
-               .tx_loadsz      = 1,
-       },
-       [PORT_8250] = {
-               .name           = "8250",
-               .fifo_size      = 1,
-               .tx_loadsz      = 1,
-       },
-       [PORT_16450] = {
-               .name           = "16450",
-               .fifo_size      = 1,
-               .tx_loadsz      = 1,
-       },
-       [PORT_16550] = {
-               .name           = "16550",
-               .fifo_size      = 1,
-               .tx_loadsz      = 1,
-       },
-       [PORT_16550A] = {
-               .name           = "16550A",
-               .fifo_size      = 16,
-               .tx_loadsz      = 16,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
-               .flags          = UART_CAP_FIFO,
-       },
-       [PORT_CIRRUS] = {
-               .name           = "Cirrus",
-               .fifo_size      = 1,
-               .tx_loadsz      = 1,
-       },
-       [PORT_16650] = {
-               .name           = "ST16650",
-               .fifo_size      = 1,
-               .tx_loadsz      = 1,
-               .flags          = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
-       },
-       [PORT_16650V2] = {
-               .name           = "ST16650V2",
-               .fifo_size      = 32,
-               .tx_loadsz      = 16,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 |
-                                 UART_FCR_T_TRIG_00,
-               .flags          = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
-       },
-       [PORT_16750] = {
-               .name           = "TI16750",
-               .fifo_size      = 64,
-               .tx_loadsz      = 64,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 |
-                                 UART_FCR7_64BYTE,
-               .flags          = UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_AFE,
-       },
-       [PORT_STARTECH] = {
-               .name           = "Startech",
-               .fifo_size      = 1,
-               .tx_loadsz      = 1,
-       },
-       [PORT_16C950] = {
-               .name           = "16C950/954",
-               .fifo_size      = 128,
-               .tx_loadsz      = 128,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
-               .flags          = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
-       },
-       [PORT_16654] = {
-               .name           = "ST16654",
-               .fifo_size      = 64,
-               .tx_loadsz      = 32,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 |
-                                 UART_FCR_T_TRIG_10,
-               .flags          = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
-       },
-       [PORT_16850] = {
-               .name           = "XR16850",
-               .fifo_size      = 128,
-               .tx_loadsz      = 128,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
-               .flags          = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
-       },
-       [PORT_RSA] = {
-               .name           = "RSA",
-               .fifo_size      = 2048,
-               .tx_loadsz      = 2048,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11,
-               .flags          = UART_CAP_FIFO,
-       },
-       [PORT_NS16550A] = {
-               .name           = "NS16550A",
-               .fifo_size      = 16,
-               .tx_loadsz      = 16,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
-               .flags          = UART_CAP_FIFO | UART_NATSEMI,
-       },
-       [PORT_XSCALE] = {
-               .name           = "XScale",
-               .fifo_size      = 32,
-               .tx_loadsz      = 32,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
-               .flags          = UART_CAP_FIFO | UART_CAP_UUE,
-       },
-       [PORT_RM9000] = {
-               .name           = "RM9000",
-               .fifo_size      = 16,
-               .tx_loadsz      = 16,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
-               .flags          = UART_CAP_FIFO,
-       },
-       [PORT_OCTEON] = {
-               .name           = "OCTEON",
-               .fifo_size      = 64,
-               .tx_loadsz      = 64,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
-               .flags          = UART_CAP_FIFO,
-       },
-       [PORT_AR7] = {
-               .name           = "AR7",
-               .fifo_size      = 16,
-               .tx_loadsz      = 16,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00,
-               .flags          = UART_CAP_FIFO | UART_CAP_AFE,
-       },
-       [PORT_U6_16550A] = {
-               .name           = "U6_16550A",
-               .fifo_size      = 64,
-               .tx_loadsz      = 64,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
-               .flags          = UART_CAP_FIFO | UART_CAP_AFE,
-       },
-};
-
-#if defined(CONFIG_MIPS_ALCHEMY)
-
-/* Au1x00 UART hardware has a weird register layout */
-static const u8 au_io_in_map[] = {
-       [UART_RX]  = 0,
-       [UART_IER] = 2,
-       [UART_IIR] = 3,
-       [UART_LCR] = 5,
-       [UART_MCR] = 6,
-       [UART_LSR] = 7,
-       [UART_MSR] = 8,
-};
-
-static const u8 au_io_out_map[] = {
-       [UART_TX]  = 1,
-       [UART_IER] = 2,
-       [UART_FCR] = 4,
-       [UART_LCR] = 5,
-       [UART_MCR] = 6,
-};
-
-/* sane hardware needs no mapping */
-static inline int map_8250_in_reg(struct uart_port *p, int offset)
-{
-       if (p->iotype != UPIO_AU)
-               return offset;
-       return au_io_in_map[offset];
-}
-
-static inline int map_8250_out_reg(struct uart_port *p, int offset)
-{
-       if (p->iotype != UPIO_AU)
-               return offset;
-       return au_io_out_map[offset];
-}
-
-#elif defined(CONFIG_SERIAL_8250_RM9K)
-
-static const u8
-       regmap_in[8] = {
-               [UART_RX]       = 0x00,
-               [UART_IER]      = 0x0c,
-               [UART_IIR]      = 0x14,
-               [UART_LCR]      = 0x1c,
-               [UART_MCR]      = 0x20,
-               [UART_LSR]      = 0x24,
-               [UART_MSR]      = 0x28,
-               [UART_SCR]      = 0x2c
-       },
-       regmap_out[8] = {
-               [UART_TX]       = 0x04,
-               [UART_IER]      = 0x0c,
-               [UART_FCR]      = 0x18,
-               [UART_LCR]      = 0x1c,
-               [UART_MCR]      = 0x20,
-               [UART_LSR]      = 0x24,
-               [UART_MSR]      = 0x28,
-               [UART_SCR]      = 0x2c
-       };
-
-static inline int map_8250_in_reg(struct uart_port *p, int offset)
-{
-       if (p->iotype != UPIO_RM9000)
-               return offset;
-       return regmap_in[offset];
-}
-
-static inline int map_8250_out_reg(struct uart_port *p, int offset)
-{
-       if (p->iotype != UPIO_RM9000)
-               return offset;
-       return regmap_out[offset];
-}
-
-#else
-
-/* sane hardware needs no mapping */
-#define map_8250_in_reg(up, offset) (offset)
-#define map_8250_out_reg(up, offset) (offset)
-
-#endif
-
-static unsigned int hub6_serial_in(struct uart_port *p, int offset)
-{
-       offset = map_8250_in_reg(p, offset) << p->regshift;
-       outb(p->hub6 - 1 + offset, p->iobase);
-       return inb(p->iobase + 1);
-}
-
-static void hub6_serial_out(struct uart_port *p, int offset, int value)
-{
-       offset = map_8250_out_reg(p, offset) << p->regshift;
-       outb(p->hub6 - 1 + offset, p->iobase);
-       outb(value, p->iobase + 1);
-}
-
-static unsigned int mem_serial_in(struct uart_port *p, int offset)
-{
-       offset = map_8250_in_reg(p, offset) << p->regshift;
-       return readb(p->membase + offset);
-}
-
-static void mem_serial_out(struct uart_port *p, int offset, int value)
-{
-       offset = map_8250_out_reg(p, offset) << p->regshift;
-       writeb(value, p->membase + offset);
-}
-
-static void mem32_serial_out(struct uart_port *p, int offset, int value)
-{
-       offset = map_8250_out_reg(p, offset) << p->regshift;
-       writel(value, p->membase + offset);
-}
-
-static unsigned int mem32_serial_in(struct uart_port *p, int offset)
-{
-       offset = map_8250_in_reg(p, offset) << p->regshift;
-       return readl(p->membase + offset);
-}
-
-static unsigned int au_serial_in(struct uart_port *p, int offset)
-{
-       offset = map_8250_in_reg(p, offset) << p->regshift;
-       return __raw_readl(p->membase + offset);
-}
-
-static void au_serial_out(struct uart_port *p, int offset, int value)
-{
-       offset = map_8250_out_reg(p, offset) << p->regshift;
-       __raw_writel(value, p->membase + offset);
-}
-
-static unsigned int tsi_serial_in(struct uart_port *p, int offset)
-{
-       unsigned int tmp;
-       offset = map_8250_in_reg(p, offset) << p->regshift;
-       if (offset == UART_IIR) {
-               tmp = readl(p->membase + (UART_IIR & ~3));
-               return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */
-       } else
-               return readb(p->membase + offset);
-}
-
-static void tsi_serial_out(struct uart_port *p, int offset, int value)
-{
-       offset = map_8250_out_reg(p, offset) << p->regshift;
-       if (!((offset == UART_IER) && (value & UART_IER_UUE)))
-               writeb(value, p->membase + offset);
-}
-
-/* Save the LCR value so it can be re-written when a Busy Detect IRQ occurs. */
-static inline void dwapb_save_out_value(struct uart_port *p, int offset,
-                                       int value)
-{
-       struct uart_8250_port *up =
-               container_of(p, struct uart_8250_port, port);
-
-       if (offset == UART_LCR)
-               up->lcr = value;
-}
-
-/* Read the IER to ensure any interrupt is cleared before returning from ISR. */
-static inline void dwapb_check_clear_ier(struct uart_port *p, int offset)
-{
-       if (offset == UART_TX || offset == UART_IER)
-               p->serial_in(p, UART_IER);
-}
-
-static void dwapb_serial_out(struct uart_port *p, int offset, int value)
-{
-       int save_offset = offset;
-       offset = map_8250_out_reg(p, offset) << p->regshift;
-       dwapb_save_out_value(p, save_offset, value);
-       writeb(value, p->membase + offset);
-       dwapb_check_clear_ier(p, save_offset);
-}
-
-static void dwapb32_serial_out(struct uart_port *p, int offset, int value)
-{
-       int save_offset = offset;
-       offset = map_8250_out_reg(p, offset) << p->regshift;
-       dwapb_save_out_value(p, save_offset, value);
-       writel(value, p->membase + offset);
-       dwapb_check_clear_ier(p, save_offset);
-}
-
-static unsigned int io_serial_in(struct uart_port *p, int offset)
-{
-       offset = map_8250_in_reg(p, offset) << p->regshift;
-       return inb(p->iobase + offset);
-}
-
-static void io_serial_out(struct uart_port *p, int offset, int value)
-{
-       offset = map_8250_out_reg(p, offset) << p->regshift;
-       outb(value, p->iobase + offset);
-}
-
-static void set_io_from_upio(struct uart_port *p)
-{
-       struct uart_8250_port *up =
-               container_of(p, struct uart_8250_port, port);
-       switch (p->iotype) {
-       case UPIO_HUB6:
-               p->serial_in = hub6_serial_in;
-               p->serial_out = hub6_serial_out;
-               break;
-
-       case UPIO_MEM:
-               p->serial_in = mem_serial_in;
-               p->serial_out = mem_serial_out;
-               break;
-
-       case UPIO_RM9000:
-       case UPIO_MEM32:
-               p->serial_in = mem32_serial_in;
-               p->serial_out = mem32_serial_out;
-               break;
-
-       case UPIO_AU:
-               p->serial_in = au_serial_in;
-               p->serial_out = au_serial_out;
-               break;
-
-       case UPIO_TSI:
-               p->serial_in = tsi_serial_in;
-               p->serial_out = tsi_serial_out;
-               break;
-
-       case UPIO_DWAPB:
-               p->serial_in = mem_serial_in;
-               p->serial_out = dwapb_serial_out;
-               break;
-
-       case UPIO_DWAPB32:
-               p->serial_in = mem32_serial_in;
-               p->serial_out = dwapb32_serial_out;
-               break;
-
-       default:
-               p->serial_in = io_serial_in;
-               p->serial_out = io_serial_out;
-               break;
-       }
-       /* Remember loaded iotype */
-       up->cur_iotype = p->iotype;
-}
-
-static void
-serial_out_sync(struct uart_8250_port *up, int offset, int value)
-{
-       struct uart_port *p = &up->port;
-       switch (p->iotype) {
-       case UPIO_MEM:
-       case UPIO_MEM32:
-       case UPIO_AU:
-       case UPIO_DWAPB:
-       case UPIO_DWAPB32:
-               p->serial_out(p, offset, value);
-               p->serial_in(p, UART_LCR);      /* safe, no side-effects */
-               break;
-       default:
-               p->serial_out(p, offset, value);
-       }
-}
-
-#define serial_in(up, offset)          \
-       (up->port.serial_in(&(up)->port, (offset)))
-#define serial_out(up, offset, value)  \
-       (up->port.serial_out(&(up)->port, (offset), (value)))
-/*
- * We used to support using pause I/O for certain machines.  We
- * haven't supported this for a while, but just in case it's badly
- * needed for certain old 386 machines, I've left these #define's
- * in....
- */
-#define serial_inp(up, offset)         serial_in(up, offset)
-#define serial_outp(up, offset, value) serial_out(up, offset, value)
-
-/* Uart divisor latch read */
-static inline int _serial_dl_read(struct uart_8250_port *up)
-{
-       return serial_inp(up, UART_DLL) | serial_inp(up, UART_DLM) << 8;
-}
-
-/* Uart divisor latch write */
-static inline void _serial_dl_write(struct uart_8250_port *up, int value)
-{
-       serial_outp(up, UART_DLL, value & 0xff);
-       serial_outp(up, UART_DLM, value >> 8 & 0xff);
-}
-
-#if defined(CONFIG_MIPS_ALCHEMY)
-/* Au1x00 haven't got a standard divisor latch */
-static int serial_dl_read(struct uart_8250_port *up)
-{
-       if (up->port.iotype == UPIO_AU)
-               return __raw_readl(up->port.membase + 0x28);
-       else
-               return _serial_dl_read(up);
-}
-
-static void serial_dl_write(struct uart_8250_port *up, int value)
-{
-       if (up->port.iotype == UPIO_AU)
-               __raw_writel(value, up->port.membase + 0x28);
-       else
-               _serial_dl_write(up, value);
-}
-#elif defined(CONFIG_SERIAL_8250_RM9K)
-static int serial_dl_read(struct uart_8250_port *up)
-{
-       return  (up->port.iotype == UPIO_RM9000) ?
-               (((__raw_readl(up->port.membase + 0x10) << 8) |
-               (__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff) :
-               _serial_dl_read(up);
-}
-
-static void serial_dl_write(struct uart_8250_port *up, int value)
-{
-       if (up->port.iotype == UPIO_RM9000) {
-               __raw_writel(value, up->port.membase + 0x08);
-               __raw_writel(value >> 8, up->port.membase + 0x10);
-       } else {
-               _serial_dl_write(up, value);
-       }
-}
-#else
-#define serial_dl_read(up) _serial_dl_read(up)
-#define serial_dl_write(up, value) _serial_dl_write(up, value)
-#endif
-
-/*
- * For the 16C950
- */
-static void serial_icr_write(struct uart_8250_port *up, int offset, int value)
-{
-       serial_out(up, UART_SCR, offset);
-       serial_out(up, UART_ICR, value);
-}
-
-static unsigned int serial_icr_read(struct uart_8250_port *up, int offset)
-{
-       unsigned int value;
-
-       serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD);
-       serial_out(up, UART_SCR, offset);
-       value = serial_in(up, UART_ICR);
-       serial_icr_write(up, UART_ACR, up->acr);
-
-       return value;
-}
-
-/*
- * FIFO support.
- */
-static void serial8250_clear_fifos(struct uart_8250_port *p)
-{
-       if (p->capabilities & UART_CAP_FIFO) {
-               serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO);
-               serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO |
-                              UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
-               serial_outp(p, UART_FCR, 0);
-       }
-}
-
-/*
- * IER sleep support.  UARTs which have EFRs need the "extended
- * capability" bit enabled.  Note that on XR16C850s, we need to
- * reset LCR to write to IER.
- */
-static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
-{
-       if (p->capabilities & UART_CAP_SLEEP) {
-               if (p->capabilities & UART_CAP_EFR) {
-                       serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_B);
-                       serial_outp(p, UART_EFR, UART_EFR_ECB);
-                       serial_outp(p, UART_LCR, 0);
-               }
-               serial_outp(p, UART_IER, sleep ? UART_IERX_SLEEP : 0);
-               if (p->capabilities & UART_CAP_EFR) {
-                       serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_B);
-                       serial_outp(p, UART_EFR, 0);
-                       serial_outp(p, UART_LCR, 0);
-               }
-       }
-}
-
-#ifdef CONFIG_SERIAL_8250_RSA
-/*
- * Attempts to turn on the RSA FIFO.  Returns zero on failure.
- * We set the port uart clock rate if we succeed.
- */
-static int __enable_rsa(struct uart_8250_port *up)
-{
-       unsigned char mode;
-       int result;
-
-       mode = serial_inp(up, UART_RSA_MSR);
-       result = mode & UART_RSA_MSR_FIFO;
-
-       if (!result) {
-               serial_outp(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
-               mode = serial_inp(up, UART_RSA_MSR);
-               result = mode & UART_RSA_MSR_FIFO;
-       }
-
-       if (result)
-               up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16;
-
-       return result;
-}
-
-static void enable_rsa(struct uart_8250_port *up)
-{
-       if (up->port.type == PORT_RSA) {
-               if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) {
-                       spin_lock_irq(&up->port.lock);
-                       __enable_rsa(up);
-                       spin_unlock_irq(&up->port.lock);
-               }
-               if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16)
-                       serial_outp(up, UART_RSA_FRR, 0);
-       }
-}
-
-/*
- * Attempts to turn off the RSA FIFO.  Returns zero on failure.
- * It is unknown why interrupts were disabled in here.  However,
- * the caller is expected to preserve this behaviour by grabbing
- * the spinlock before calling this function.
- */
-static void disable_rsa(struct uart_8250_port *up)
-{
-       unsigned char mode;
-       int result;
-
-       if (up->port.type == PORT_RSA &&
-           up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) {
-               spin_lock_irq(&up->port.lock);
-
-               mode = serial_inp(up, UART_RSA_MSR);
-               result = !(mode & UART_RSA_MSR_FIFO);
-
-               if (!result) {
-                       serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
-                       mode = serial_inp(up, UART_RSA_MSR);
-                       result = !(mode & UART_RSA_MSR_FIFO);
-               }
-
-               if (result)
-                       up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16;
-               spin_unlock_irq(&up->port.lock);
-       }
-}
-#endif /* CONFIG_SERIAL_8250_RSA */
-
-/*
- * This is a quickie test to see how big the FIFO is.
- * It doesn't work at all the time, more's the pity.
- */
-static int size_fifo(struct uart_8250_port *up)
-{
-       unsigned char old_fcr, old_mcr, old_lcr;
-       unsigned short old_dl;
-       int count;
-
-       old_lcr = serial_inp(up, UART_LCR);
-       serial_outp(up, UART_LCR, 0);
-       old_fcr = serial_inp(up, UART_FCR);
-       old_mcr = serial_inp(up, UART_MCR);
-       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
-                   UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
-       serial_outp(up, UART_MCR, UART_MCR_LOOP);
-       serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A);
-       old_dl = serial_dl_read(up);
-       serial_dl_write(up, 0x0001);
-       serial_outp(up, UART_LCR, 0x03);
-       for (count = 0; count < 256; count++)
-               serial_outp(up, UART_TX, count);
-       mdelay(20);/* FIXME - schedule_timeout */
-       for (count = 0; (serial_inp(up, UART_LSR) & UART_LSR_DR) &&
-            (count < 256); count++)
-               serial_inp(up, UART_RX);
-       serial_outp(up, UART_FCR, old_fcr);
-       serial_outp(up, UART_MCR, old_mcr);
-       serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A);
-       serial_dl_write(up, old_dl);
-       serial_outp(up, UART_LCR, old_lcr);
-
-       return count;
-}
-
-/*
- * Read UART ID using the divisor method - set DLL and DLM to zero
- * and the revision will be in DLL and device type in DLM.  We
- * preserve the device state across this.
- */
-static unsigned int autoconfig_read_divisor_id(struct uart_8250_port *p)
-{
-       unsigned char old_dll, old_dlm, old_lcr;
-       unsigned int id;
-
-       old_lcr = serial_inp(p, UART_LCR);
-       serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_A);
-
-       old_dll = serial_inp(p, UART_DLL);
-       old_dlm = serial_inp(p, UART_DLM);
-
-       serial_outp(p, UART_DLL, 0);
-       serial_outp(p, UART_DLM, 0);
-
-       id = serial_inp(p, UART_DLL) | serial_inp(p, UART_DLM) << 8;
-
-       serial_outp(p, UART_DLL, old_dll);
-       serial_outp(p, UART_DLM, old_dlm);
-       serial_outp(p, UART_LCR, old_lcr);
-
-       return id;
-}
-
-/*
- * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's.
- * When this function is called we know it is at least a StarTech
- * 16650 V2, but it might be one of several StarTech UARTs, or one of
- * its clones.  (We treat the broken original StarTech 16650 V1 as a
- * 16550, and why not?  Startech doesn't seem to even acknowledge its
- * existence.)
- *
- * What evil have men's minds wrought...
- */
-static void autoconfig_has_efr(struct uart_8250_port *up)
-{
-       unsigned int id1, id2, id3, rev;
-
-       /*
-        * Everything with an EFR has SLEEP
-        */
-       up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP;
-
-       /*
-        * First we check to see if it's an Oxford Semiconductor UART.
-        *
-        * If we have to do this here because some non-National
-        * Semiconductor clone chips lock up if you try writing to the
-        * LSR register (which serial_icr_read does)
-        */
-
-       /*
-        * Check for Oxford Semiconductor 16C950.
-        *
-        * EFR [4] must be set else this test fails.
-        *
-        * This shouldn't be necessary, but Mike Hudson (Exoray@isys.ca)
-        * claims that it's needed for 952 dual UART's (which are not
-        * recommended for new designs).
-        */
-       up->acr = 0;
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-       serial_out(up, UART_EFR, UART_EFR_ECB);
-       serial_out(up, UART_LCR, 0x00);
-       id1 = serial_icr_read(up, UART_ID1);
-       id2 = serial_icr_read(up, UART_ID2);
-       id3 = serial_icr_read(up, UART_ID3);
-       rev = serial_icr_read(up, UART_REV);
-
-       DEBUG_AUTOCONF("950id=%02x:%02x:%02x:%02x ", id1, id2, id3, rev);
-
-       if (id1 == 0x16 && id2 == 0xC9 &&
-           (id3 == 0x50 || id3 == 0x52 || id3 == 0x54)) {
-               up->port.type = PORT_16C950;
-
-               /*
-                * Enable work around for the Oxford Semiconductor 952 rev B
-                * chip which causes it to seriously miscalculate baud rates
-                * when DLL is 0.
-                */
-               if (id3 == 0x52 && rev == 0x01)
-                       up->bugs |= UART_BUG_QUOT;
-               return;
-       }
-
-       /*
-        * We check for a XR16C850 by setting DLL and DLM to 0, and then
-        * reading back DLL and DLM.  The chip type depends on the DLM
-        * value read back:
-        *  0x10 - XR16C850 and the DLL contains the chip revision.
-        *  0x12 - XR16C2850.
-        *  0x14 - XR16C854.
-        */
-       id1 = autoconfig_read_divisor_id(up);
-       DEBUG_AUTOCONF("850id=%04x ", id1);
-
-       id2 = id1 >> 8;
-       if (id2 == 0x10 || id2 == 0x12 || id2 == 0x14) {
-               up->port.type = PORT_16850;
-               return;
-       }
-
-       /*
-        * It wasn't an XR16C850.
-        *
-        * We distinguish between the '654 and the '650 by counting
-        * how many bytes are in the FIFO.  I'm using this for now,
-        * since that's the technique that was sent to me in the
-        * serial driver update, but I'm not convinced this works.
-        * I've had problems doing this in the past.  -TYT
-        */
-       if (size_fifo(up) == 64)
-               up->port.type = PORT_16654;
-       else
-               up->port.type = PORT_16650V2;
-}
-
-/*
- * We detected a chip without a FIFO.  Only two fall into
- * this category - the original 8250 and the 16450.  The
- * 16450 has a scratch register (accessible with LCR=0)
- */
-static void autoconfig_8250(struct uart_8250_port *up)
-{
-       unsigned char scratch, status1, status2;
-
-       up->port.type = PORT_8250;
-
-       scratch = serial_in(up, UART_SCR);
-       serial_outp(up, UART_SCR, 0xa5);
-       status1 = serial_in(up, UART_SCR);
-       serial_outp(up, UART_SCR, 0x5a);
-       status2 = serial_in(up, UART_SCR);
-       serial_outp(up, UART_SCR, scratch);
-
-       if (status1 == 0xa5 && status2 == 0x5a)
-               up->port.type = PORT_16450;
-}
-
-static int broken_efr(struct uart_8250_port *up)
-{
-       /*
-        * Exar ST16C2550 "A2" devices incorrectly detect as
-        * having an EFR, and report an ID of 0x0201.  See
-        * http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-11/4812.html 
-        */
-       if (autoconfig_read_divisor_id(up) == 0x0201 && size_fifo(up) == 16)
-               return 1;
-
-       return 0;
-}
-
-/*
- * We know that the chip has FIFOs.  Does it have an EFR?  The
- * EFR is located in the same register position as the IIR and
- * we know the top two bits of the IIR are currently set.  The
- * EFR should contain zero.  Try to read the EFR.
- */
-static void autoconfig_16550a(struct uart_8250_port *up)
-{
-       unsigned char status1, status2;
-       unsigned int iersave;
-
-       up->port.type = PORT_16550A;
-       up->capabilities |= UART_CAP_FIFO;
-
-       /*
-        * Check for presence of the EFR when DLAB is set.
-        * Only ST16C650V1 UARTs pass this test.
-        */
-       serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A);
-       if (serial_in(up, UART_EFR) == 0) {
-               serial_outp(up, UART_EFR, 0xA8);
-               if (serial_in(up, UART_EFR) != 0) {
-                       DEBUG_AUTOCONF("EFRv1 ");
-                       up->port.type = PORT_16650;
-                       up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP;
-               } else {
-                       DEBUG_AUTOCONF("Motorola 8xxx DUART ");
-               }
-               serial_outp(up, UART_EFR, 0);
-               return;
-       }
-
-       /*
-        * Maybe it requires 0xbf to be written to the LCR.
-        * (other ST16C650V2 UARTs, TI16C752A, etc)
-        */
-       serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
-       if (serial_in(up, UART_EFR) == 0 && !broken_efr(up)) {
-               DEBUG_AUTOCONF("EFRv2 ");
-               autoconfig_has_efr(up);
-               return;
-       }
-
-       /*
-        * Check for a National Semiconductor SuperIO chip.
-        * Attempt to switch to bank 2, read the value of the LOOP bit
-        * from EXCR1. Switch back to bank 0, change it in MCR. Then
-        * switch back to bank 2, read it from EXCR1 again and check
-        * it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2
-        */
-       serial_outp(up, UART_LCR, 0);
-       status1 = serial_in(up, UART_MCR);
-       serial_outp(up, UART_LCR, 0xE0);
-       status2 = serial_in(up, 0x02); /* EXCR1 */
-
-       if (!((status2 ^ status1) & UART_MCR_LOOP)) {
-               serial_outp(up, UART_LCR, 0);
-               serial_outp(up, UART_MCR, status1 ^ UART_MCR_LOOP);
-               serial_outp(up, UART_LCR, 0xE0);
-               status2 = serial_in(up, 0x02); /* EXCR1 */
-               serial_outp(up, UART_LCR, 0);
-               serial_outp(up, UART_MCR, status1);
-
-               if ((status2 ^ status1) & UART_MCR_LOOP) {
-                       unsigned short quot;
-
-                       serial_outp(up, UART_LCR, 0xE0);
-
-                       quot = serial_dl_read(up);
-                       quot <<= 3;
-
-                       status1 = serial_in(up, 0x04); /* EXCR2 */
-                       status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
-                       status1 |= 0x10;  /* 1.625 divisor for baud_base --> 921600 */
-                       serial_outp(up, 0x04, status1);
-
-                       serial_dl_write(up, quot);
-
-                       serial_outp(up, UART_LCR, 0);
-
-                       up->port.uartclk = 921600*16;
-                       up->port.type = PORT_NS16550A;
-                       up->capabilities |= UART_NATSEMI;
-                       return;
-               }
-       }
-
-       /*
-        * No EFR.  Try to detect a TI16750, which only sets bit 5 of
-        * the IIR when 64 byte FIFO mode is enabled when DLAB is set.
-        * Try setting it with and without DLAB set.  Cheap clones
-        * set bit 5 without DLAB set.
-        */
-       serial_outp(up, UART_LCR, 0);
-       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
-       status1 = serial_in(up, UART_IIR) >> 5;
-       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-       serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A);
-       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
-       status2 = serial_in(up, UART_IIR) >> 5;
-       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-       serial_outp(up, UART_LCR, 0);
-
-       DEBUG_AUTOCONF("iir1=%d iir2=%d ", status1, status2);
-
-       if (status1 == 6 && status2 == 7) {
-               up->port.type = PORT_16750;
-               up->capabilities |= UART_CAP_AFE | UART_CAP_SLEEP;
-               return;
-       }
-
-       /*
-        * Try writing and reading the UART_IER_UUE bit (b6).
-        * If it works, this is probably one of the Xscale platform's
-        * internal UARTs.
-        * We're going to explicitly set the UUE bit to 0 before
-        * trying to write and read a 1 just to make sure it's not
-        * already a 1 and maybe locked there before we even start start.
-        */
-       iersave = serial_in(up, UART_IER);
-       serial_outp(up, UART_IER, iersave & ~UART_IER_UUE);
-       if (!(serial_in(up, UART_IER) & UART_IER_UUE)) {
-               /*
-                * OK it's in a known zero state, try writing and reading
-                * without disturbing the current state of the other bits.
-                */
-               serial_outp(up, UART_IER, iersave | UART_IER_UUE);
-               if (serial_in(up, UART_IER) & UART_IER_UUE) {
-                       /*
-                        * It's an Xscale.
-                        * We'll leave the UART_IER_UUE bit set to 1 (enabled).
-                        */
-                       DEBUG_AUTOCONF("Xscale ");
-                       up->port.type = PORT_XSCALE;
-                       up->capabilities |= UART_CAP_UUE;
-                       return;
-               }
-       } else {
-               /*
-                * If we got here we couldn't force the IER_UUE bit to 0.
-                * Log it and continue.
-                */
-               DEBUG_AUTOCONF("Couldn't force IER_UUE to 0 ");
-       }
-       serial_outp(up, UART_IER, iersave);
-
-       /*
-        * We distinguish between 16550A and U6 16550A by counting
-        * how many bytes are in the FIFO.
-        */
-       if (up->port.type == PORT_16550A && size_fifo(up) == 64) {
-               up->port.type = PORT_U6_16550A;
-               up->capabilities |= UART_CAP_AFE;
-       }
-}
-
-/*
- * This routine is called by rs_init() to initialize a specific serial
- * port.  It determines what type of UART chip this serial port is
- * using: 8250, 16450, 16550, 16550A.  The important question is
- * whether or not this UART is a 16550A or not, since this will
- * determine whether or not we can use its FIFO features or not.
- */
-static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
-{
-       unsigned char status1, scratch, scratch2, scratch3;
-       unsigned char save_lcr, save_mcr;
-       unsigned long flags;
-
-       if (!up->port.iobase && !up->port.mapbase && !up->port.membase)
-               return;
-
-       DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04lx, 0x%p): ",
-                      serial_index(&up->port), up->port.iobase, up->port.membase);
-
-       /*
-        * We really do need global IRQs disabled here - we're going to
-        * be frobbing the chips IRQ enable register to see if it exists.
-        */
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       up->capabilities = 0;
-       up->bugs = 0;
-
-       if (!(up->port.flags & UPF_BUGGY_UART)) {
-               /*
-                * Do a simple existence test first; if we fail this,
-                * there's no point trying anything else.
-                *
-                * 0x80 is used as a nonsense port to prevent against
-                * false positives due to ISA bus float.  The
-                * assumption is that 0x80 is a non-existent port;
-                * which should be safe since include/asm/io.h also
-                * makes this assumption.
-                *
-                * Note: this is safe as long as MCR bit 4 is clear
-                * and the device is in "PC" mode.
-                */
-               scratch = serial_inp(up, UART_IER);
-               serial_outp(up, UART_IER, 0);
-#ifdef __i386__
-               outb(0xff, 0x080);
-#endif
-               /*
-                * Mask out IER[7:4] bits for test as some UARTs (e.g. TL
-                * 16C754B) allow only to modify them if an EFR bit is set.
-                */
-               scratch2 = serial_inp(up, UART_IER) & 0x0f;
-               serial_outp(up, UART_IER, 0x0F);
-#ifdef __i386__
-               outb(0, 0x080);
-#endif
-               scratch3 = serial_inp(up, UART_IER) & 0x0f;
-               serial_outp(up, UART_IER, scratch);
-               if (scratch2 != 0 || scratch3 != 0x0F) {
-                       /*
-                        * We failed; there's nothing here
-                        */
-                       DEBUG_AUTOCONF("IER test failed (%02x, %02x) ",
-                                      scratch2, scratch3);
-                       goto out;
-               }
-       }
-
-       save_mcr = serial_in(up, UART_MCR);
-       save_lcr = serial_in(up, UART_LCR);
-
-       /*
-        * Check to see if a UART is really there.  Certain broken
-        * internal modems based on the Rockwell chipset fail this
-        * test, because they apparently don't implement the loopback
-        * test mode.  So this test is skipped on the COM 1 through
-        * COM 4 ports.  This *should* be safe, since no board
-        * manufacturer would be stupid enough to design a board
-        * that conflicts with COM 1-4 --- we hope!
-        */
-       if (!(up->port.flags & UPF_SKIP_TEST)) {
-               serial_outp(up, UART_MCR, UART_MCR_LOOP | 0x0A);
-               status1 = serial_inp(up, UART_MSR) & 0xF0;
-               serial_outp(up, UART_MCR, save_mcr);
-               if (status1 != 0x90) {
-                       DEBUG_AUTOCONF("LOOP test failed (%02x) ",
-                                      status1);
-                       goto out;
-               }
-       }
-
-       /*
-        * We're pretty sure there's a port here.  Lets find out what
-        * type of port it is.  The IIR top two bits allows us to find
-        * out if it's 8250 or 16450, 16550, 16550A or later.  This
-        * determines what we test for next.
-        *
-        * We also initialise the EFR (if any) to zero for later.  The
-        * EFR occupies the same register location as the FCR and IIR.
-        */
-       serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
-       serial_outp(up, UART_EFR, 0);
-       serial_outp(up, UART_LCR, 0);
-
-       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-       scratch = serial_in(up, UART_IIR) >> 6;
-
-       DEBUG_AUTOCONF("iir=%d ", scratch);
-
-       switch (scratch) {
-       case 0:
-               autoconfig_8250(up);
-               break;
-       case 1:
-               up->port.type = PORT_UNKNOWN;
-               break;
-       case 2:
-               up->port.type = PORT_16550;
-               break;
-       case 3:
-               autoconfig_16550a(up);
-               break;
-       }
-
-#ifdef CONFIG_SERIAL_8250_RSA
-       /*
-        * Only probe for RSA ports if we got the region.
-        */
-       if (up->port.type == PORT_16550A && probeflags & PROBE_RSA) {
-               int i;
-
-               for (i = 0 ; i < probe_rsa_count; ++i) {
-                       if (probe_rsa[i] == up->port.iobase &&
-                           __enable_rsa(up)) {
-                               up->port.type = PORT_RSA;
-                               break;
-                       }
-               }
-       }
-#endif
-
-       serial_outp(up, UART_LCR, save_lcr);
-
-       if (up->capabilities != uart_config[up->port.type].flags) {
-               printk(KERN_WARNING
-                      "ttyS%d: detected caps %08x should be %08x\n",
-                      serial_index(&up->port), up->capabilities,
-                      uart_config[up->port.type].flags);
-       }
-
-       up->port.fifosize = uart_config[up->port.type].fifo_size;
-       up->capabilities = uart_config[up->port.type].flags;
-       up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
-
-       if (up->port.type == PORT_UNKNOWN)
-               goto out;
-
-       /*
-        * Reset the UART.
-        */
-#ifdef CONFIG_SERIAL_8250_RSA
-       if (up->port.type == PORT_RSA)
-               serial_outp(up, UART_RSA_FRR, 0);
-#endif
-       serial_outp(up, UART_MCR, save_mcr);
-       serial8250_clear_fifos(up);
-       serial_in(up, UART_RX);
-       if (up->capabilities & UART_CAP_UUE)
-               serial_outp(up, UART_IER, UART_IER_UUE);
-       else
-               serial_outp(up, UART_IER, 0);
-
- out:
-       spin_unlock_irqrestore(&up->port.lock, flags);
-       DEBUG_AUTOCONF("type=%s\n", uart_config[up->port.type].name);
-}
-
-static void autoconfig_irq(struct uart_8250_port *up)
-{
-       unsigned char save_mcr, save_ier;
-       unsigned char save_ICP = 0;
-       unsigned int ICP = 0;
-       unsigned long irqs;
-       int irq;
-
-       if (up->port.flags & UPF_FOURPORT) {
-               ICP = (up->port.iobase & 0xfe0) | 0x1f;
-               save_ICP = inb_p(ICP);
-               outb_p(0x80, ICP);
-               (void) inb_p(ICP);
-       }
-
-       /* forget possible initially masked and pending IRQ */
-       probe_irq_off(probe_irq_on());
-       save_mcr = serial_inp(up, UART_MCR);
-       save_ier = serial_inp(up, UART_IER);
-       serial_outp(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2);
-
-       irqs = probe_irq_on();
-       serial_outp(up, UART_MCR, 0);
-       udelay(10);
-       if (up->port.flags & UPF_FOURPORT) {
-               serial_outp(up, UART_MCR,
-                           UART_MCR_DTR | UART_MCR_RTS);
-       } else {
-               serial_outp(up, UART_MCR,
-                           UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
-       }
-       serial_outp(up, UART_IER, 0x0f);        /* enable all intrs */
-       (void)serial_inp(up, UART_LSR);
-       (void)serial_inp(up, UART_RX);
-       (void)serial_inp(up, UART_IIR);
-       (void)serial_inp(up, UART_MSR);
-       serial_outp(up, UART_TX, 0xFF);
-       udelay(20);
-       irq = probe_irq_off(irqs);
-
-       serial_outp(up, UART_MCR, save_mcr);
-       serial_outp(up, UART_IER, save_ier);
-
-       if (up->port.flags & UPF_FOURPORT)
-               outb_p(save_ICP, ICP);
-
-       up->port.irq = (irq > 0) ? irq : 0;
-}
-
-static inline void __stop_tx(struct uart_8250_port *p)
-{
-       if (p->ier & UART_IER_THRI) {
-               p->ier &= ~UART_IER_THRI;
-               serial_out(p, UART_IER, p->ier);
-       }
-}
-
-static void serial8250_stop_tx(struct uart_port *port)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-
-       __stop_tx(up);
-
-       /*
-        * We really want to stop the transmitter from sending.
-        */
-       if (up->port.type == PORT_16C950) {
-               up->acr |= UART_ACR_TXDIS;
-               serial_icr_write(up, UART_ACR, up->acr);
-       }
-}
-
-static void transmit_chars(struct uart_8250_port *up);
-
-static void serial8250_start_tx(struct uart_port *port)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-
-       if (!(up->ier & UART_IER_THRI)) {
-               up->ier |= UART_IER_THRI;
-               serial_out(up, UART_IER, up->ier);
-
-               if (up->bugs & UART_BUG_TXEN) {
-                       unsigned char lsr;
-                       lsr = serial_in(up, UART_LSR);
-                       up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
-                       if ((up->port.type == PORT_RM9000) ?
-                               (lsr & UART_LSR_THRE) :
-                               (lsr & UART_LSR_TEMT))
-                               transmit_chars(up);
-               }
-       }
-
-       /*
-        * Re-enable the transmitter if we disabled it.
-        */
-       if (up->port.type == PORT_16C950 && up->acr & UART_ACR_TXDIS) {
-               up->acr &= ~UART_ACR_TXDIS;
-               serial_icr_write(up, UART_ACR, up->acr);
-       }
-}
-
-static void serial8250_stop_rx(struct uart_port *port)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-
-       up->ier &= ~UART_IER_RLSI;
-       up->port.read_status_mask &= ~UART_LSR_DR;
-       serial_out(up, UART_IER, up->ier);
-}
-
-static void serial8250_enable_ms(struct uart_port *port)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-
-       /* no MSR capabilities */
-       if (up->bugs & UART_BUG_NOMSR)
-               return;
-
-       up->ier |= UART_IER_MSI;
-       serial_out(up, UART_IER, up->ier);
-}
-
-static void
-receive_chars(struct uart_8250_port *up, unsigned int *status)
-{
-       struct tty_struct *tty = up->port.state->port.tty;
-       unsigned char ch, lsr = *status;
-       int max_count = 256;
-       char flag;
-
-       do {
-               if (likely(lsr & UART_LSR_DR))
-                       ch = serial_inp(up, UART_RX);
-               else
-                       /*
-                        * Intel 82571 has a Serial Over Lan device that will
-                        * set UART_LSR_BI without setting UART_LSR_DR when
-                        * it receives a break. To avoid reading from the
-                        * receive buffer without UART_LSR_DR bit set, we
-                        * just force the read character to be 0
-                        */
-                       ch = 0;
-
-               flag = TTY_NORMAL;
-               up->port.icount.rx++;
-
-               lsr |= up->lsr_saved_flags;
-               up->lsr_saved_flags = 0;
-
-               if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
-                       /*
-                        * For statistics only
-                        */
-                       if (lsr & UART_LSR_BI) {
-                               lsr &= ~(UART_LSR_FE | UART_LSR_PE);
-                               up->port.icount.brk++;
-                               /*
-                                * We do the SysRQ and SAK checking
-                                * here because otherwise the break
-                                * may get masked by ignore_status_mask
-                                * or read_status_mask.
-                                */
-                               if (uart_handle_break(&up->port))
-                                       goto ignore_char;
-                       } else if (lsr & UART_LSR_PE)
-                               up->port.icount.parity++;
-                       else if (lsr & UART_LSR_FE)
-                               up->port.icount.frame++;
-                       if (lsr & UART_LSR_OE)
-                               up->port.icount.overrun++;
-
-                       /*
-                        * Mask off conditions which should be ignored.
-                        */
-                       lsr &= up->port.read_status_mask;
-
-                       if (lsr & UART_LSR_BI) {
-                               DEBUG_INTR("handling break....");
-                               flag = TTY_BREAK;
-                       } else if (lsr & UART_LSR_PE)
-                               flag = TTY_PARITY;
-                       else if (lsr & UART_LSR_FE)
-                               flag = TTY_FRAME;
-               }
-               if (uart_handle_sysrq_char(&up->port, ch))
-                       goto ignore_char;
-
-               uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);
-
-ignore_char:
-               lsr = serial_inp(up, UART_LSR);
-       } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0));
-       spin_unlock(&up->port.lock);
-       tty_flip_buffer_push(tty);
-       spin_lock(&up->port.lock);
-       *status = lsr;
-}
-
-static void transmit_chars(struct uart_8250_port *up)
-{
-       struct circ_buf *xmit = &up->port.state->xmit;
-       int count;
-
-       if (up->port.x_char) {
-               serial_outp(up, UART_TX, up->port.x_char);
-               up->port.icount.tx++;
-               up->port.x_char = 0;
-               return;
-       }
-       if (uart_tx_stopped(&up->port)) {
-               serial8250_stop_tx(&up->port);
-               return;
-       }
-       if (uart_circ_empty(xmit)) {
-               __stop_tx(up);
-               return;
-       }
-
-       count = up->tx_loadsz;
-       do {
-               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               up->port.icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (--count > 0);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&up->port);
-
-       DEBUG_INTR("THRE...");
-
-       if (uart_circ_empty(xmit))
-               __stop_tx(up);
-}
-
-static unsigned int check_modem_status(struct uart_8250_port *up)
-{
-       unsigned int status = serial_in(up, UART_MSR);
-
-       status |= up->msr_saved_flags;
-       up->msr_saved_flags = 0;
-       if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&
-           up->port.state != NULL) {
-               if (status & UART_MSR_TERI)
-                       up->port.icount.rng++;
-               if (status & UART_MSR_DDSR)
-                       up->port.icount.dsr++;
-               if (status & UART_MSR_DDCD)
-                       uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
-               if (status & UART_MSR_DCTS)
-                       uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
-
-               wake_up_interruptible(&up->port.state->port.delta_msr_wait);
-       }
-
-       return status;
-}
-
-/*
- * This handles the interrupt from one port.
- */
-static void serial8250_handle_port(struct uart_8250_port *up)
-{
-       unsigned int status;
-       unsigned long flags;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       status = serial_inp(up, UART_LSR);
-
-       DEBUG_INTR("status = %x...", status);
-
-       if (status & (UART_LSR_DR | UART_LSR_BI))
-               receive_chars(up, &status);
-       check_modem_status(up);
-       if (status & UART_LSR_THRE)
-               transmit_chars(up);
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-/*
- * This is the serial driver's interrupt routine.
- *
- * Arjan thinks the old way was overly complex, so it got simplified.
- * Alan disagrees, saying that need the complexity to handle the weird
- * nature of ISA shared interrupts.  (This is a special exception.)
- *
- * In order to handle ISA shared interrupts properly, we need to check
- * that all ports have been serviced, and therefore the ISA interrupt
- * line has been de-asserted.
- *
- * This means we need to loop through all ports. checking that they
- * don't have an interrupt pending.
- */
-static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
-{
-       struct irq_info *i = dev_id;
-       struct list_head *l, *end = NULL;
-       int pass_counter = 0, handled = 0;
-
-       DEBUG_INTR("serial8250_interrupt(%d)...", irq);
-
-       spin_lock(&i->lock);
-
-       l = i->head;
-       do {
-               struct uart_8250_port *up;
-               unsigned int iir;
-
-               up = list_entry(l, struct uart_8250_port, list);
-
-               iir = serial_in(up, UART_IIR);
-               if (!(iir & UART_IIR_NO_INT)) {
-                       serial8250_handle_port(up);
-
-                       handled = 1;
-
-                       end = NULL;
-               } else if ((up->port.iotype == UPIO_DWAPB ||
-                           up->port.iotype == UPIO_DWAPB32) &&
-                         (iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
-                       /* The DesignWare APB UART has an Busy Detect (0x07)
-                        * interrupt meaning an LCR write attempt occured while the
-                        * UART was busy. The interrupt must be cleared by reading
-                        * the UART status register (USR) and the LCR re-written. */
-                       unsigned int status;
-                       status = *(volatile u32 *)up->port.private_data;
-                       serial_out(up, UART_LCR, up->lcr);
-
-                       handled = 1;
-
-                       end = NULL;
-               } else if (end == NULL)
-                       end = l;
-
-               l = l->next;
-
-               if (l == i->head && pass_counter++ > PASS_LIMIT) {
-                       /* If we hit this, we're dead. */
-                       printk_ratelimited(KERN_ERR
-                               "serial8250: too much work for irq%d\n", irq);
-                       break;
-               }
-       } while (l != end);
-
-       spin_unlock(&i->lock);
-
-       DEBUG_INTR("end.\n");
-
-       return IRQ_RETVAL(handled);
-}
-
-/*
- * To support ISA shared interrupts, we need to have one interrupt
- * handler that ensures that the IRQ line has been deasserted
- * before returning.  Failing to do this will result in the IRQ
- * line being stuck active, and, since ISA irqs are edge triggered,
- * no more IRQs will be seen.
- */
-static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up)
-{
-       spin_lock_irq(&i->lock);
-
-       if (!list_empty(i->head)) {
-               if (i->head == &up->list)
-                       i->head = i->head->next;
-               list_del(&up->list);
-       } else {
-               BUG_ON(i->head != &up->list);
-               i->head = NULL;
-       }
-       spin_unlock_irq(&i->lock);
-       /* List empty so throw away the hash node */
-       if (i->head == NULL) {
-               hlist_del(&i->node);
-               kfree(i);
-       }
-}
-
-static int serial_link_irq_chain(struct uart_8250_port *up)
-{
-       struct hlist_head *h;
-       struct hlist_node *n;
-       struct irq_info *i;
-       int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0;
-
-       mutex_lock(&hash_mutex);
-
-       h = &irq_lists[up->port.irq % NR_IRQ_HASH];
-
-       hlist_for_each(n, h) {
-               i = hlist_entry(n, struct irq_info, node);
-               if (i->irq == up->port.irq)
-                       break;
-       }
-
-       if (n == NULL) {
-               i = kzalloc(sizeof(struct irq_info), GFP_KERNEL);
-               if (i == NULL) {
-                       mutex_unlock(&hash_mutex);
-                       return -ENOMEM;
-               }
-               spin_lock_init(&i->lock);
-               i->irq = up->port.irq;
-               hlist_add_head(&i->node, h);
-       }
-       mutex_unlock(&hash_mutex);
-
-       spin_lock_irq(&i->lock);
-
-       if (i->head) {
-               list_add(&up->list, i->head);
-               spin_unlock_irq(&i->lock);
-
-               ret = 0;
-       } else {
-               INIT_LIST_HEAD(&up->list);
-               i->head = &up->list;
-               spin_unlock_irq(&i->lock);
-               irq_flags |= up->port.irqflags;
-               ret = request_irq(up->port.irq, serial8250_interrupt,
-                                 irq_flags, "serial", i);
-               if (ret < 0)
-                       serial_do_unlink(i, up);
-       }
-
-       return ret;
-}
-
-static void serial_unlink_irq_chain(struct uart_8250_port *up)
-{
-       struct irq_info *i;
-       struct hlist_node *n;
-       struct hlist_head *h;
-
-       mutex_lock(&hash_mutex);
-
-       h = &irq_lists[up->port.irq % NR_IRQ_HASH];
-
-       hlist_for_each(n, h) {
-               i = hlist_entry(n, struct irq_info, node);
-               if (i->irq == up->port.irq)
-                       break;
-       }
-
-       BUG_ON(n == NULL);
-       BUG_ON(i->head == NULL);
-
-       if (list_empty(i->head))
-               free_irq(up->port.irq, i);
-
-       serial_do_unlink(i, up);
-       mutex_unlock(&hash_mutex);
-}
-
-/*
- * This function is used to handle ports that do not have an
- * interrupt.  This doesn't work very well for 16450's, but gives
- * barely passable results for a 16550A.  (Although at the expense
- * of much CPU overhead).
- */
-static void serial8250_timeout(unsigned long data)
-{
-       struct uart_8250_port *up = (struct uart_8250_port *)data;
-       unsigned int iir;
-
-       iir = serial_in(up, UART_IIR);
-       if (!(iir & UART_IIR_NO_INT))
-               serial8250_handle_port(up);
-       mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port));
-}
-
-static void serial8250_backup_timeout(unsigned long data)
-{
-       struct uart_8250_port *up = (struct uart_8250_port *)data;
-       unsigned int iir, ier = 0, lsr;
-       unsigned long flags;
-
-       /*
-        * Must disable interrupts or else we risk racing with the interrupt
-        * based handler.
-        */
-       if (is_real_interrupt(up->port.irq)) {
-               ier = serial_in(up, UART_IER);
-               serial_out(up, UART_IER, 0);
-       }
-
-       iir = serial_in(up, UART_IIR);
-
-       /*
-        * This should be a safe test for anyone who doesn't trust the
-        * IIR bits on their UART, but it's specifically designed for
-        * the "Diva" UART used on the management processor on many HP
-        * ia64 and parisc boxes.
-        */
-       spin_lock_irqsave(&up->port.lock, flags);
-       lsr = serial_in(up, UART_LSR);
-       up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
-       spin_unlock_irqrestore(&up->port.lock, flags);
-       if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) &&
-           (!uart_circ_empty(&up->port.state->xmit) || up->port.x_char) &&
-           (lsr & UART_LSR_THRE)) {
-               iir &= ~(UART_IIR_ID | UART_IIR_NO_INT);
-               iir |= UART_IIR_THRI;
-       }
-
-       if (!(iir & UART_IIR_NO_INT))
-               serial8250_handle_port(up);
-
-       if (is_real_interrupt(up->port.irq))
-               serial_out(up, UART_IER, ier);
-
-       /* Standard timer interval plus 0.2s to keep the port running */
-       mod_timer(&up->timer,
-               jiffies + uart_poll_timeout(&up->port) + HZ / 5);
-}
-
-static unsigned int serial8250_tx_empty(struct uart_port *port)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-       unsigned long flags;
-       unsigned int lsr;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       lsr = serial_in(up, UART_LSR);
-       up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0;
-}
-
-static unsigned int serial8250_get_mctrl(struct uart_port *port)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-       unsigned int status;
-       unsigned int ret;
-
-       status = check_modem_status(up);
-
-       ret = 0;
-       if (status & UART_MSR_DCD)
-               ret |= TIOCM_CAR;
-       if (status & UART_MSR_RI)
-               ret |= TIOCM_RNG;
-       if (status & UART_MSR_DSR)
-               ret |= TIOCM_DSR;
-       if (status & UART_MSR_CTS)
-               ret |= TIOCM_CTS;
-       return ret;
-}
-
-static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-       unsigned char mcr = 0;
-
-       if (mctrl & TIOCM_RTS)
-               mcr |= UART_MCR_RTS;
-       if (mctrl & TIOCM_DTR)
-               mcr |= UART_MCR_DTR;
-       if (mctrl & TIOCM_OUT1)
-               mcr |= UART_MCR_OUT1;
-       if (mctrl & TIOCM_OUT2)
-               mcr |= UART_MCR_OUT2;
-       if (mctrl & TIOCM_LOOP)
-               mcr |= UART_MCR_LOOP;
-
-       mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr;
-
-       serial_out(up, UART_MCR, mcr);
-}
-
-static void serial8250_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-       unsigned long flags;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       if (break_state == -1)
-               up->lcr |= UART_LCR_SBC;
-       else
-               up->lcr &= ~UART_LCR_SBC;
-       serial_out(up, UART_LCR, up->lcr);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-/*
- *     Wait for transmitter & holding register to empty
- */
-static void wait_for_xmitr(struct uart_8250_port *up, int bits)
-{
-       unsigned int status, tmout = 10000;
-
-       /* Wait up to 10ms for the character(s) to be sent. */
-       for (;;) {
-               status = serial_in(up, UART_LSR);
-
-               up->lsr_saved_flags |= status & LSR_SAVE_FLAGS;
-
-               if ((status & bits) == bits)
-                       break;
-               if (--tmout == 0)
-                       break;
-               udelay(1);
-       }
-
-       /* Wait up to 1s for flow control if necessary */
-       if (up->port.flags & UPF_CONS_FLOW) {
-               unsigned int tmout;
-               for (tmout = 1000000; tmout; tmout--) {
-                       unsigned int msr = serial_in(up, UART_MSR);
-                       up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
-                       if (msr & UART_MSR_CTS)
-                               break;
-                       udelay(1);
-                       touch_nmi_watchdog();
-               }
-       }
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-/*
- * Console polling routines for writing and reading from the uart while
- * in an interrupt or debug context.
- */
-
-static int serial8250_get_poll_char(struct uart_port *port)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-       unsigned char lsr = serial_inp(up, UART_LSR);
-
-       if (!(lsr & UART_LSR_DR))
-               return NO_POLL_CHAR;
-
-       return serial_inp(up, UART_RX);
-}
-
-
-static void serial8250_put_poll_char(struct uart_port *port,
-                        unsigned char c)
-{
-       unsigned int ier;
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-
-       /*
-        *      First save the IER then disable the interrupts
-        */
-       ier = serial_in(up, UART_IER);
-       if (up->capabilities & UART_CAP_UUE)
-               serial_out(up, UART_IER, UART_IER_UUE);
-       else
-               serial_out(up, UART_IER, 0);
-
-       wait_for_xmitr(up, BOTH_EMPTY);
-       /*
-        *      Send the character out.
-        *      If a LF, also do CR...
-        */
-       serial_out(up, UART_TX, c);
-       if (c == 10) {
-               wait_for_xmitr(up, BOTH_EMPTY);
-               serial_out(up, UART_TX, 13);
-       }
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore the IER
-        */
-       wait_for_xmitr(up, BOTH_EMPTY);
-       serial_out(up, UART_IER, ier);
-}
-
-#endif /* CONFIG_CONSOLE_POLL */
-
-static int serial8250_startup(struct uart_port *port)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-       unsigned long flags;
-       unsigned char lsr, iir;
-       int retval;
-
-       up->port.fifosize = uart_config[up->port.type].fifo_size;
-       up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
-       up->capabilities = uart_config[up->port.type].flags;
-       up->mcr = 0;
-
-       if (up->port.iotype != up->cur_iotype)
-               set_io_from_upio(port);
-
-       if (up->port.type == PORT_16C950) {
-               /* Wake up and initialize UART */
-               up->acr = 0;
-               serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
-               serial_outp(up, UART_EFR, UART_EFR_ECB);
-               serial_outp(up, UART_IER, 0);
-               serial_outp(up, UART_LCR, 0);
-               serial_icr_write(up, UART_CSR, 0); /* Reset the UART */
-               serial_outp(up, UART_LCR, 0xBF);
-               serial_outp(up, UART_EFR, UART_EFR_ECB);
-               serial_outp(up, UART_LCR, 0);
-       }
-
-#ifdef CONFIG_SERIAL_8250_RSA
-       /*
-        * If this is an RSA port, see if we can kick it up to the
-        * higher speed clock.
-        */
-       enable_rsa(up);
-#endif
-
-       /*
-        * Clear the FIFO buffers and disable them.
-        * (they will be reenabled in set_termios())
-        */
-       serial8250_clear_fifos(up);
-
-       /*
-        * Clear the interrupt registers.
-        */
-       (void) serial_inp(up, UART_LSR);
-       (void) serial_inp(up, UART_RX);
-       (void) serial_inp(up, UART_IIR);
-       (void) serial_inp(up, UART_MSR);
-
-       /*
-        * At this point, there's no way the LSR could still be 0xff;
-        * if it is, then bail out, because there's likely no UART
-        * here.
-        */
-       if (!(up->port.flags & UPF_BUGGY_UART) &&
-           (serial_inp(up, UART_LSR) == 0xff)) {
-               printk(KERN_INFO "ttyS%d: LSR safety check engaged!\n",
-                      serial_index(&up->port));
-               return -ENODEV;
-       }
-
-       /*
-        * For a XR16C850, we need to set the trigger levels
-        */
-       if (up->port.type == PORT_16850) {
-               unsigned char fctr;
-
-               serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
-
-               fctr = serial_inp(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX);
-               serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_RX);
-               serial_outp(up, UART_TRG, UART_TRG_96);
-               serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_TX);
-               serial_outp(up, UART_TRG, UART_TRG_96);
-
-               serial_outp(up, UART_LCR, 0);
-       }
-
-       if (is_real_interrupt(up->port.irq)) {
-               unsigned char iir1;
-               /*
-                * Test for UARTs that do not reassert THRE when the
-                * transmitter is idle and the interrupt has already
-                * been cleared.  Real 16550s should always reassert
-                * this interrupt whenever the transmitter is idle and
-                * the interrupt is enabled.  Delays are necessary to
-                * allow register changes to become visible.
-                */
-               spin_lock_irqsave(&up->port.lock, flags);
-               if (up->port.irqflags & IRQF_SHARED)
-                       disable_irq_nosync(up->port.irq);
-
-               wait_for_xmitr(up, UART_LSR_THRE);
-               serial_out_sync(up, UART_IER, UART_IER_THRI);
-               udelay(1); /* allow THRE to set */
-               iir1 = serial_in(up, UART_IIR);
-               serial_out(up, UART_IER, 0);
-               serial_out_sync(up, UART_IER, UART_IER_THRI);
-               udelay(1); /* allow a working UART time to re-assert THRE */
-               iir = serial_in(up, UART_IIR);
-               serial_out(up, UART_IER, 0);
-
-               if (up->port.irqflags & IRQF_SHARED)
-                       enable_irq(up->port.irq);
-               spin_unlock_irqrestore(&up->port.lock, flags);
-
-               /*
-                * If the interrupt is not reasserted, setup a timer to
-                * kick the UART on a regular basis.
-                */
-               if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) {
-                       up->bugs |= UART_BUG_THRE;
-                       pr_debug("ttyS%d - using backup timer\n",
-                                serial_index(port));
-               }
-       }
-
-       /*
-        * The above check will only give an accurate result the first time
-        * the port is opened so this value needs to be preserved.
-        */
-       if (up->bugs & UART_BUG_THRE) {
-               up->timer.function = serial8250_backup_timeout;
-               up->timer.data = (unsigned long)up;
-               mod_timer(&up->timer, jiffies +
-                       uart_poll_timeout(port) + HZ / 5);
-       }
-
-       /*
-        * If the "interrupt" for this port doesn't correspond with any
-        * hardware interrupt, we use a timer-based system.  The original
-        * driver used to do this with IRQ0.
-        */
-       if (!is_real_interrupt(up->port.irq)) {
-               up->timer.data = (unsigned long)up;
-               mod_timer(&up->timer, jiffies + uart_poll_timeout(port));
-       } else {
-               retval = serial_link_irq_chain(up);
-               if (retval)
-                       return retval;
-       }
-
-       /*
-        * Now, initialize the UART
-        */
-       serial_outp(up, UART_LCR, UART_LCR_WLEN8);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       if (up->port.flags & UPF_FOURPORT) {
-               if (!is_real_interrupt(up->port.irq))
-                       up->port.mctrl |= TIOCM_OUT1;
-       } else
-               /*
-                * Most PC uarts need OUT2 raised to enable interrupts.
-                */
-               if (is_real_interrupt(up->port.irq))
-                       up->port.mctrl |= TIOCM_OUT2;
-
-       serial8250_set_mctrl(&up->port, up->port.mctrl);
-
-       /* Serial over Lan (SoL) hack:
-          Intel 8257x Gigabit ethernet chips have a
-          16550 emulation, to be used for Serial Over Lan.
-          Those chips take a longer time than a normal
-          serial device to signalize that a transmission
-          data was queued. Due to that, the above test generally
-          fails. One solution would be to delay the reading of
-          iir. However, this is not reliable, since the timeout
-          is variable. So, let's just don't test if we receive
-          TX irq. This way, we'll never enable UART_BUG_TXEN.
-        */
-       if (skip_txen_test || up->port.flags & UPF_NO_TXEN_TEST)
-               goto dont_test_tx_en;
-
-       /*
-        * Do a quick test to see if we receive an
-        * interrupt when we enable the TX irq.
-        */
-       serial_outp(up, UART_IER, UART_IER_THRI);
-       lsr = serial_in(up, UART_LSR);
-       iir = serial_in(up, UART_IIR);
-       serial_outp(up, UART_IER, 0);
-
-       if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {
-               if (!(up->bugs & UART_BUG_TXEN)) {
-                       up->bugs |= UART_BUG_TXEN;
-                       pr_debug("ttyS%d - enabling bad tx status workarounds\n",
-                                serial_index(port));
-               }
-       } else {
-               up->bugs &= ~UART_BUG_TXEN;
-       }
-
-dont_test_tx_en:
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       /*
-        * Clear the interrupt registers again for luck, and clear the
-        * saved flags to avoid getting false values from polling
-        * routines or the previous session.
-        */
-       serial_inp(up, UART_LSR);
-       serial_inp(up, UART_RX);
-       serial_inp(up, UART_IIR);
-       serial_inp(up, UART_MSR);
-       up->lsr_saved_flags = 0;
-       up->msr_saved_flags = 0;
-
-       /*
-        * Finally, enable interrupts.  Note: Modem status interrupts
-        * are set via set_termios(), which will be occurring imminently
-        * anyway, so we don't enable them here.
-        */
-       up->ier = UART_IER_RLSI | UART_IER_RDI;
-       serial_outp(up, UART_IER, up->ier);
-
-       if (up->port.flags & UPF_FOURPORT) {
-               unsigned int icp;
-               /*
-                * Enable interrupts on the AST Fourport board
-                */
-               icp = (up->port.iobase & 0xfe0) | 0x01f;
-               outb_p(0x80, icp);
-               (void) inb_p(icp);
-       }
-
-       return 0;
-}
-
-static void serial8250_shutdown(struct uart_port *port)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-       unsigned long flags;
-
-       /*
-        * Disable interrupts from this port
-        */
-       up->ier = 0;
-       serial_outp(up, UART_IER, 0);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       if (up->port.flags & UPF_FOURPORT) {
-               /* reset interrupts on the AST Fourport board */
-               inb((up->port.iobase & 0xfe0) | 0x1f);
-               up->port.mctrl |= TIOCM_OUT1;
-       } else
-               up->port.mctrl &= ~TIOCM_OUT2;
-
-       serial8250_set_mctrl(&up->port, up->port.mctrl);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       /*
-        * Disable break condition and FIFOs
-        */
-       serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC);
-       serial8250_clear_fifos(up);
-
-#ifdef CONFIG_SERIAL_8250_RSA
-       /*
-        * Reset the RSA board back to 115kbps compat mode.
-        */
-       disable_rsa(up);
-#endif
-
-       /*
-        * Read data port to reset things, and then unlink from
-        * the IRQ chain.
-        */
-       (void) serial_in(up, UART_RX);
-
-       del_timer_sync(&up->timer);
-       up->timer.function = serial8250_timeout;
-       if (is_real_interrupt(up->port.irq))
-               serial_unlink_irq_chain(up);
-}
-
-static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud)
-{
-       unsigned int quot;
-
-       /*
-        * Handle magic divisors for baud rates above baud_base on
-        * SMSC SuperIO chips.
-        */
-       if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
-           baud == (port->uartclk/4))
-               quot = 0x8001;
-       else if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
-                baud == (port->uartclk/8))
-               quot = 0x8002;
-       else
-               quot = uart_get_divisor(port, baud);
-
-       return quot;
-}
-
-void
-serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
-                         struct ktermios *old)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-       unsigned char cval, fcr = 0;
-       unsigned long flags;
-       unsigned int baud, quot;
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               cval = UART_LCR_WLEN5;
-               break;
-       case CS6:
-               cval = UART_LCR_WLEN6;
-               break;
-       case CS7:
-               cval = UART_LCR_WLEN7;
-               break;
-       default:
-       case CS8:
-               cval = UART_LCR_WLEN8;
-               break;
-       }
-
-       if (termios->c_cflag & CSTOPB)
-               cval |= UART_LCR_STOP;
-       if (termios->c_cflag & PARENB)
-               cval |= UART_LCR_PARITY;
-       if (!(termios->c_cflag & PARODD))
-               cval |= UART_LCR_EPAR;
-#ifdef CMSPAR
-       if (termios->c_cflag & CMSPAR)
-               cval |= UART_LCR_SPAR;
-#endif
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old,
-                                 port->uartclk / 16 / 0xffff,
-                                 port->uartclk / 16);
-       quot = serial8250_get_divisor(port, baud);
-
-       /*
-        * Oxford Semi 952 rev B workaround
-        */
-       if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0)
-               quot++;
-
-       if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) {
-               if (baud < 2400)
-                       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
-               else
-                       fcr = uart_config[up->port.type].fcr;
-       }
-
-       /*
-        * MCR-based auto flow control.  When AFE is enabled, RTS will be
-        * deasserted when the receive FIFO contains more characters than
-        * the trigger, or the MCR RTS bit is cleared.  In the case where
-        * the remote UART is not using CTS auto flow control, we must
-        * have sufficient FIFO entries for the latency of the remote
-        * UART to respond.  IOW, at least 32 bytes of FIFO.
-        */
-       if (up->capabilities & UART_CAP_AFE && up->port.fifosize >= 32) {
-               up->mcr &= ~UART_MCR_AFE;
-               if (termios->c_cflag & CRTSCTS)
-                       up->mcr |= UART_MCR_AFE;
-       }
-
-       /*
-        * Ok, we're now changing the port state.  Do it with
-        * interrupts disabled.
-        */
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
-       if (termios->c_iflag & INPCK)
-               up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               up->port.read_status_mask |= UART_LSR_BI;
-
-       /*
-        * Characteres to ignore
-        */
-       up->port.ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
-       if (termios->c_iflag & IGNBRK) {
-               up->port.ignore_status_mask |= UART_LSR_BI;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       up->port.ignore_status_mask |= UART_LSR_OE;
-       }
-
-       /*
-        * ignore all characters if CREAD is not set
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               up->port.ignore_status_mask |= UART_LSR_DR;
-
-       /*
-        * CTS flow control flag and modem status interrupts
-        */
-       up->ier &= ~UART_IER_MSI;
-       if (!(up->bugs & UART_BUG_NOMSR) &&
-                       UART_ENABLE_MS(&up->port, termios->c_cflag))
-               up->ier |= UART_IER_MSI;
-       if (up->capabilities & UART_CAP_UUE)
-               up->ier |= UART_IER_UUE | UART_IER_RTOIE;
-
-       serial_out(up, UART_IER, up->ier);
-
-       if (up->capabilities & UART_CAP_EFR) {
-               unsigned char efr = 0;
-               /*
-                * TI16C752/Startech hardware flow control.  FIXME:
-                * - TI16C752 requires control thresholds to be set.
-                * - UART_MCR_RTS is ineffective if auto-RTS mode is enabled.
-                */
-               if (termios->c_cflag & CRTSCTS)
-                       efr |= UART_EFR_CTS;
-
-               serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
-               serial_outp(up, UART_EFR, efr);
-       }
-
-#ifdef CONFIG_ARCH_OMAP
-       /* Workaround to enable 115200 baud on OMAP1510 internal ports */
-       if (cpu_is_omap1510() && is_omap_port(up)) {
-               if (baud == 115200) {
-                       quot = 1;
-                       serial_out(up, UART_OMAP_OSC_12M_SEL, 1);
-               } else
-                       serial_out(up, UART_OMAP_OSC_12M_SEL, 0);
-       }
-#endif
-
-       if (up->capabilities & UART_NATSEMI) {
-               /* Switch to bank 2 not bank 1, to avoid resetting EXCR2 */
-               serial_outp(up, UART_LCR, 0xe0);
-       } else {
-               serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
-       }
-
-       serial_dl_write(up, quot);
-
-       /*
-        * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
-        * is written without DLAB set, this mode will be disabled.
-        */
-       if (up->port.type == PORT_16750)
-               serial_outp(up, UART_FCR, fcr);
-
-       serial_outp(up, UART_LCR, cval);                /* reset DLAB */
-       up->lcr = cval;                                 /* Save LCR */
-       if (up->port.type != PORT_16750) {
-               if (fcr & UART_FCR_ENABLE_FIFO) {
-                       /* emulated UARTs (Lucent Venus 167x) need two steps */
-                       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-               }
-               serial_outp(up, UART_FCR, fcr);         /* set fcr */
-       }
-       serial8250_set_mctrl(&up->port, up->port.mctrl);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-       /* Don't rewrite B0 */
-       if (tty_termios_baud_rate(termios))
-               tty_termios_encode_baud_rate(termios, baud, baud);
-}
-EXPORT_SYMBOL(serial8250_do_set_termios);
-
-static void
-serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
-                      struct ktermios *old)
-{
-       if (port->set_termios)
-               port->set_termios(port, termios, old);
-       else
-               serial8250_do_set_termios(port, termios, old);
-}
-
-static void
-serial8250_set_ldisc(struct uart_port *port, int new)
-{
-       if (new == N_PPS) {
-               port->flags |= UPF_HARDPPS_CD;
-               serial8250_enable_ms(port);
-       } else
-               port->flags &= ~UPF_HARDPPS_CD;
-}
-
-
-void serial8250_do_pm(struct uart_port *port, unsigned int state,
-                     unsigned int oldstate)
-{
-       struct uart_8250_port *p =
-               container_of(port, struct uart_8250_port, port);
-
-       serial8250_set_sleep(p, state != 0);
-}
-EXPORT_SYMBOL(serial8250_do_pm);
-
-static void
-serial8250_pm(struct uart_port *port, unsigned int state,
-             unsigned int oldstate)
-{
-       if (port->pm)
-               port->pm(port, state, oldstate);
-       else
-               serial8250_do_pm(port, state, oldstate);
-}
-
-static unsigned int serial8250_port_size(struct uart_8250_port *pt)
-{
-       if (pt->port.iotype == UPIO_AU)
-               return 0x1000;
-#ifdef CONFIG_ARCH_OMAP
-       if (is_omap_port(pt))
-               return 0x16 << pt->port.regshift;
-#endif
-       return 8 << pt->port.regshift;
-}
-
-/*
- * Resource handling.
- */
-static int serial8250_request_std_resource(struct uart_8250_port *up)
-{
-       unsigned int size = serial8250_port_size(up);
-       int ret = 0;
-
-       switch (up->port.iotype) {
-       case UPIO_AU:
-       case UPIO_TSI:
-       case UPIO_MEM32:
-       case UPIO_MEM:
-       case UPIO_DWAPB:
-       case UPIO_DWAPB32:
-               if (!up->port.mapbase)
-                       break;
-
-               if (!request_mem_region(up->port.mapbase, size, "serial")) {
-                       ret = -EBUSY;
-                       break;
-               }
-
-               if (up->port.flags & UPF_IOREMAP) {
-                       up->port.membase = ioremap_nocache(up->port.mapbase,
-                                                                       size);
-                       if (!up->port.membase) {
-                               release_mem_region(up->port.mapbase, size);
-                               ret = -ENOMEM;
-                       }
-               }
-               break;
-
-       case UPIO_HUB6:
-       case UPIO_PORT:
-               if (!request_region(up->port.iobase, size, "serial"))
-                       ret = -EBUSY;
-               break;
-       }
-       return ret;
-}
-
-static void serial8250_release_std_resource(struct uart_8250_port *up)
-{
-       unsigned int size = serial8250_port_size(up);
-
-       switch (up->port.iotype) {
-       case UPIO_AU:
-       case UPIO_TSI:
-       case UPIO_MEM32:
-       case UPIO_MEM:
-       case UPIO_DWAPB:
-       case UPIO_DWAPB32:
-               if (!up->port.mapbase)
-                       break;
-
-               if (up->port.flags & UPF_IOREMAP) {
-                       iounmap(up->port.membase);
-                       up->port.membase = NULL;
-               }
-
-               release_mem_region(up->port.mapbase, size);
-               break;
-
-       case UPIO_HUB6:
-       case UPIO_PORT:
-               release_region(up->port.iobase, size);
-               break;
-       }
-}
-
-static int serial8250_request_rsa_resource(struct uart_8250_port *up)
-{
-       unsigned long start = UART_RSA_BASE << up->port.regshift;
-       unsigned int size = 8 << up->port.regshift;
-       int ret = -EINVAL;
-
-       switch (up->port.iotype) {
-       case UPIO_HUB6:
-       case UPIO_PORT:
-               start += up->port.iobase;
-               if (request_region(start, size, "serial-rsa"))
-                       ret = 0;
-               else
-                       ret = -EBUSY;
-               break;
-       }
-
-       return ret;
-}
-
-static void serial8250_release_rsa_resource(struct uart_8250_port *up)
-{
-       unsigned long offset = UART_RSA_BASE << up->port.regshift;
-       unsigned int size = 8 << up->port.regshift;
-
-       switch (up->port.iotype) {
-       case UPIO_HUB6:
-       case UPIO_PORT:
-               release_region(up->port.iobase + offset, size);
-               break;
-       }
-}
-
-static void serial8250_release_port(struct uart_port *port)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-
-       serial8250_release_std_resource(up);
-       if (up->port.type == PORT_RSA)
-               serial8250_release_rsa_resource(up);
-}
-
-static int serial8250_request_port(struct uart_port *port)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-       int ret = 0;
-
-       ret = serial8250_request_std_resource(up);
-       if (ret == 0 && up->port.type == PORT_RSA) {
-               ret = serial8250_request_rsa_resource(up);
-               if (ret < 0)
-                       serial8250_release_std_resource(up);
-       }
-
-       return ret;
-}
-
-static void serial8250_config_port(struct uart_port *port, int flags)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-       int probeflags = PROBE_ANY;
-       int ret;
-
-       /*
-        * Find the region that we can probe for.  This in turn
-        * tells us whether we can probe for the type of port.
-        */
-       ret = serial8250_request_std_resource(up);
-       if (ret < 0)
-               return;
-
-       ret = serial8250_request_rsa_resource(up);
-       if (ret < 0)
-               probeflags &= ~PROBE_RSA;
-
-       if (up->port.iotype != up->cur_iotype)
-               set_io_from_upio(port);
-
-       if (flags & UART_CONFIG_TYPE)
-               autoconfig(up, probeflags);
-
-       /* if access method is AU, it is a 16550 with a quirk */
-       if (up->port.type == PORT_16550A && up->port.iotype == UPIO_AU)
-               up->bugs |= UART_BUG_NOMSR;
-
-       if (up->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ)
-               autoconfig_irq(up);
-
-       if (up->port.type != PORT_RSA && probeflags & PROBE_RSA)
-               serial8250_release_rsa_resource(up);
-       if (up->port.type == PORT_UNKNOWN)
-               serial8250_release_std_resource(up);
-}
-
-static int
-serial8250_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       if (ser->irq >= nr_irqs || ser->irq < 0 ||
-           ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||
-           ser->type >= ARRAY_SIZE(uart_config) || ser->type == PORT_CIRRUS ||
-           ser->type == PORT_STARTECH)
-               return -EINVAL;
-       return 0;
-}
-
-static const char *
-serial8250_type(struct uart_port *port)
-{
-       int type = port->type;
-
-       if (type >= ARRAY_SIZE(uart_config))
-               type = 0;
-       return uart_config[type].name;
-}
-
-static struct uart_ops serial8250_pops = {
-       .tx_empty       = serial8250_tx_empty,
-       .set_mctrl      = serial8250_set_mctrl,
-       .get_mctrl      = serial8250_get_mctrl,
-       .stop_tx        = serial8250_stop_tx,
-       .start_tx       = serial8250_start_tx,
-       .stop_rx        = serial8250_stop_rx,
-       .enable_ms      = serial8250_enable_ms,
-       .break_ctl      = serial8250_break_ctl,
-       .startup        = serial8250_startup,
-       .shutdown       = serial8250_shutdown,
-       .set_termios    = serial8250_set_termios,
-       .set_ldisc      = serial8250_set_ldisc,
-       .pm             = serial8250_pm,
-       .type           = serial8250_type,
-       .release_port   = serial8250_release_port,
-       .request_port   = serial8250_request_port,
-       .config_port    = serial8250_config_port,
-       .verify_port    = serial8250_verify_port,
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_get_char = serial8250_get_poll_char,
-       .poll_put_char = serial8250_put_poll_char,
-#endif
-};
-
-static struct uart_8250_port serial8250_ports[UART_NR];
-
-static void (*serial8250_isa_config)(int port, struct uart_port *up,
-       unsigned short *capabilities);
-
-void serial8250_set_isa_configurator(
-       void (*v)(int port, struct uart_port *up, unsigned short *capabilities))
-{
-       serial8250_isa_config = v;
-}
-EXPORT_SYMBOL(serial8250_set_isa_configurator);
-
-static void __init serial8250_isa_init_ports(void)
-{
-       struct uart_8250_port *up;
-       static int first = 1;
-       int i, irqflag = 0;
-
-       if (!first)
-               return;
-       first = 0;
-
-       for (i = 0; i < nr_uarts; i++) {
-               struct uart_8250_port *up = &serial8250_ports[i];
-
-               up->port.line = i;
-               spin_lock_init(&up->port.lock);
-
-               init_timer(&up->timer);
-               up->timer.function = serial8250_timeout;
-
-               /*
-                * ALPHA_KLUDGE_MCR needs to be killed.
-                */
-               up->mcr_mask = ~ALPHA_KLUDGE_MCR;
-               up->mcr_force = ALPHA_KLUDGE_MCR;
-
-               up->port.ops = &serial8250_pops;
-       }
-
-       if (share_irqs)
-               irqflag = IRQF_SHARED;
-
-       for (i = 0, up = serial8250_ports;
-            i < ARRAY_SIZE(old_serial_port) && i < nr_uarts;
-            i++, up++) {
-               up->port.iobase   = old_serial_port[i].port;
-               up->port.irq      = irq_canonicalize(old_serial_port[i].irq);
-               up->port.irqflags = old_serial_port[i].irqflags;
-               up->port.uartclk  = old_serial_port[i].baud_base * 16;
-               up->port.flags    = old_serial_port[i].flags;
-               up->port.hub6     = old_serial_port[i].hub6;
-               up->port.membase  = old_serial_port[i].iomem_base;
-               up->port.iotype   = old_serial_port[i].io_type;
-               up->port.regshift = old_serial_port[i].iomem_reg_shift;
-               set_io_from_upio(&up->port);
-               up->port.irqflags |= irqflag;
-               if (serial8250_isa_config != NULL)
-                       serial8250_isa_config(i, &up->port, &up->capabilities);
-
-       }
-}
-
-static void
-serial8250_init_fixed_type_port(struct uart_8250_port *up, unsigned int type)
-{
-       up->port.type = type;
-       up->port.fifosize = uart_config[type].fifo_size;
-       up->capabilities = uart_config[type].flags;
-       up->tx_loadsz = uart_config[type].tx_loadsz;
-}
-
-static void __init
-serial8250_register_ports(struct uart_driver *drv, struct device *dev)
-{
-       int i;
-
-       for (i = 0; i < nr_uarts; i++) {
-               struct uart_8250_port *up = &serial8250_ports[i];
-               up->cur_iotype = 0xFF;
-       }
-
-       serial8250_isa_init_ports();
-
-       for (i = 0; i < nr_uarts; i++) {
-               struct uart_8250_port *up = &serial8250_ports[i];
-
-               up->port.dev = dev;
-
-               if (up->port.flags & UPF_FIXED_TYPE)
-                       serial8250_init_fixed_type_port(up, up->port.type);
-
-               uart_add_one_port(drv, &up->port);
-       }
-}
-
-#ifdef CONFIG_SERIAL_8250_CONSOLE
-
-static void serial8250_console_putchar(struct uart_port *port, int ch)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-
-       wait_for_xmitr(up, UART_LSR_THRE);
-       serial_out(up, UART_TX, ch);
-}
-
-/*
- *     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.
- */
-static void
-serial8250_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct uart_8250_port *up = &serial8250_ports[co->index];
-       unsigned long flags;
-       unsigned int ier;
-       int locked = 1;
-
-       touch_nmi_watchdog();
-
-       local_irq_save(flags);
-       if (up->port.sysrq) {
-               /* serial8250_handle_port() already took the lock */
-               locked = 0;
-       } else if (oops_in_progress) {
-               locked = spin_trylock(&up->port.lock);
-       } else
-               spin_lock(&up->port.lock);
-
-       /*
-        *      First save the IER then disable the interrupts
-        */
-       ier = serial_in(up, UART_IER);
-
-       if (up->capabilities & UART_CAP_UUE)
-               serial_out(up, UART_IER, UART_IER_UUE);
-       else
-               serial_out(up, UART_IER, 0);
-
-       uart_console_write(&up->port, s, count, serial8250_console_putchar);
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore the IER
-        */
-       wait_for_xmitr(up, BOTH_EMPTY);
-       serial_out(up, UART_IER, ier);
-
-       /*
-        *      The receive handling will happen properly because the
-        *      receive ready bit will still be set; it is not cleared
-        *      on read.  However, modem control will not, we must
-        *      call it if we have saved something in the saved flags
-        *      while processing with interrupts off.
-        */
-       if (up->msr_saved_flags)
-               check_modem_status(up);
-
-       if (locked)
-               spin_unlock(&up->port.lock);
-       local_irq_restore(flags);
-}
-
-static int __init serial8250_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port;
-       int baud = 9600;
-       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.
-        */
-       if (co->index >= nr_uarts)
-               co->index = 0;
-       port = &serial8250_ports[co->index].port;
-       if (!port->iobase && !port->membase)
-               return -ENODEV;
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static int serial8250_console_early_setup(void)
-{
-       return serial8250_find_port_for_earlycon();
-}
-
-static struct console serial8250_console = {
-       .name           = "ttyS",
-       .write          = serial8250_console_write,
-       .device         = uart_console_device,
-       .setup          = serial8250_console_setup,
-       .early_setup    = serial8250_console_early_setup,
-       .flags          = CON_PRINTBUFFER | CON_ANYTIME,
-       .index          = -1,
-       .data           = &serial8250_reg,
-};
-
-static int __init serial8250_console_init(void)
-{
-       if (nr_uarts > UART_NR)
-               nr_uarts = UART_NR;
-
-       serial8250_isa_init_ports();
-       register_console(&serial8250_console);
-       return 0;
-}
-console_initcall(serial8250_console_init);
-
-int serial8250_find_port(struct uart_port *p)
-{
-       int line;
-       struct uart_port *port;
-
-       for (line = 0; line < nr_uarts; line++) {
-               port = &serial8250_ports[line].port;
-               if (uart_match_port(p, port))
-                       return line;
-       }
-       return -ENODEV;
-}
-
-#define SERIAL8250_CONSOLE     &serial8250_console
-#else
-#define SERIAL8250_CONSOLE     NULL
-#endif
-
-static struct uart_driver serial8250_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "serial",
-       .dev_name               = "ttyS",
-       .major                  = TTY_MAJOR,
-       .minor                  = 64,
-       .cons                   = SERIAL8250_CONSOLE,
-};
-
-/*
- * early_serial_setup - early registration for 8250 ports
- *
- * Setup an 8250 port structure prior to console initialisation.  Use
- * after console initialisation will cause undefined behaviour.
- */
-int __init early_serial_setup(struct uart_port *port)
-{
-       struct uart_port *p;
-
-       if (port->line >= ARRAY_SIZE(serial8250_ports))
-               return -ENODEV;
-
-       serial8250_isa_init_ports();
-       p = &serial8250_ports[port->line].port;
-       p->iobase       = port->iobase;
-       p->membase      = port->membase;
-       p->irq          = port->irq;
-       p->irqflags     = port->irqflags;
-       p->uartclk      = port->uartclk;
-       p->fifosize     = port->fifosize;
-       p->regshift     = port->regshift;
-       p->iotype       = port->iotype;
-       p->flags        = port->flags;
-       p->mapbase      = port->mapbase;
-       p->private_data = port->private_data;
-       p->type         = port->type;
-       p->line         = port->line;
-
-       set_io_from_upio(p);
-       if (port->serial_in)
-               p->serial_in = port->serial_in;
-       if (port->serial_out)
-               p->serial_out = port->serial_out;
-
-       return 0;
-}
-
-/**
- *     serial8250_suspend_port - suspend one serial port
- *     @line:  serial line number
- *
- *     Suspend one serial port.
- */
-void serial8250_suspend_port(int line)
-{
-       uart_suspend_port(&serial8250_reg, &serial8250_ports[line].port);
-}
-
-/**
- *     serial8250_resume_port - resume one serial port
- *     @line:  serial line number
- *
- *     Resume one serial port.
- */
-void serial8250_resume_port(int line)
-{
-       struct uart_8250_port *up = &serial8250_ports[line];
-
-       if (up->capabilities & UART_NATSEMI) {
-               unsigned char tmp;
-
-               /* Ensure it's still in high speed mode */
-               serial_outp(up, UART_LCR, 0xE0);
-
-               tmp = serial_in(up, 0x04); /* EXCR2 */
-               tmp &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
-               tmp |= 0x10;  /* 1.625 divisor for baud_base --> 921600 */
-               serial_outp(up, 0x04, tmp);
-
-               serial_outp(up, UART_LCR, 0);
-       }
-       uart_resume_port(&serial8250_reg, &up->port);
-}
-
-/*
- * Register a set of serial devices attached to a platform device.  The
- * list is terminated with a zero flags entry, which means we expect
- * all entries to have at least UPF_BOOT_AUTOCONF set.
- */
-static int __devinit serial8250_probe(struct platform_device *dev)
-{
-       struct plat_serial8250_port *p = dev->dev.platform_data;
-       struct uart_port port;
-       int ret, i, irqflag = 0;
-
-       memset(&port, 0, sizeof(struct uart_port));
-
-       if (share_irqs)
-               irqflag = IRQF_SHARED;
-
-       for (i = 0; p && p->flags != 0; p++, i++) {
-               port.iobase             = p->iobase;
-               port.membase            = p->membase;
-               port.irq                = p->irq;
-               port.irqflags           = p->irqflags;
-               port.uartclk            = p->uartclk;
-               port.regshift           = p->regshift;
-               port.iotype             = p->iotype;
-               port.flags              = p->flags;
-               port.mapbase            = p->mapbase;
-               port.hub6               = p->hub6;
-               port.private_data       = p->private_data;
-               port.type               = p->type;
-               port.serial_in          = p->serial_in;
-               port.serial_out         = p->serial_out;
-               port.set_termios        = p->set_termios;
-               port.pm                 = p->pm;
-               port.dev                = &dev->dev;
-               port.irqflags           |= irqflag;
-               ret = serial8250_register_port(&port);
-               if (ret < 0) {
-                       dev_err(&dev->dev, "unable to register port at index %d "
-                               "(IO%lx MEM%llx IRQ%d): %d\n", i,
-                               p->iobase, (unsigned long long)p->mapbase,
-                               p->irq, ret);
-               }
-       }
-       return 0;
-}
-
-/*
- * Remove serial ports registered against a platform device.
- */
-static int __devexit serial8250_remove(struct platform_device *dev)
-{
-       int i;
-
-       for (i = 0; i < nr_uarts; i++) {
-               struct uart_8250_port *up = &serial8250_ports[i];
-
-               if (up->port.dev == &dev->dev)
-                       serial8250_unregister_port(i);
-       }
-       return 0;
-}
-
-static int serial8250_suspend(struct platform_device *dev, pm_message_t state)
-{
-       int i;
-
-       for (i = 0; i < UART_NR; i++) {
-               struct uart_8250_port *up = &serial8250_ports[i];
-
-               if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
-                       uart_suspend_port(&serial8250_reg, &up->port);
-       }
-
-       return 0;
-}
-
-static int serial8250_resume(struct platform_device *dev)
-{
-       int i;
-
-       for (i = 0; i < UART_NR; i++) {
-               struct uart_8250_port *up = &serial8250_ports[i];
-
-               if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
-                       serial8250_resume_port(i);
-       }
-
-       return 0;
-}
-
-static struct platform_driver serial8250_isa_driver = {
-       .probe          = serial8250_probe,
-       .remove         = __devexit_p(serial8250_remove),
-       .suspend        = serial8250_suspend,
-       .resume         = serial8250_resume,
-       .driver         = {
-               .name   = "serial8250",
-               .owner  = THIS_MODULE,
-       },
-};
-
-/*
- * This "device" covers _all_ ISA 8250-compatible serial devices listed
- * in the table in include/asm/serial.h
- */
-static struct platform_device *serial8250_isa_devs;
-
-/*
- * serial8250_register_port and serial8250_unregister_port allows for
- * 16x50 serial ports to be configured at run-time, to support PCMCIA
- * modems and PCI multiport cards.
- */
-static DEFINE_MUTEX(serial_mutex);
-
-static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *port)
-{
-       int i;
-
-       /*
-        * First, find a port entry which matches.
-        */
-       for (i = 0; i < nr_uarts; i++)
-               if (uart_match_port(&serial8250_ports[i].port, port))
-                       return &serial8250_ports[i];
-
-       /*
-        * We didn't find a matching entry, so look for the first
-        * free entry.  We look for one which hasn't been previously
-        * used (indicated by zero iobase).
-        */
-       for (i = 0; i < nr_uarts; i++)
-               if (serial8250_ports[i].port.type == PORT_UNKNOWN &&
-                   serial8250_ports[i].port.iobase == 0)
-                       return &serial8250_ports[i];
-
-       /*
-        * That also failed.  Last resort is to find any entry which
-        * doesn't have a real port associated with it.
-        */
-       for (i = 0; i < nr_uarts; i++)
-               if (serial8250_ports[i].port.type == PORT_UNKNOWN)
-                       return &serial8250_ports[i];
-
-       return NULL;
-}
-
-/**
- *     serial8250_register_port - register a serial port
- *     @port: serial port template
- *
- *     Configure the serial port specified by the request. If the
- *     port exists and is in use, it is hung up and unregistered
- *     first.
- *
- *     The port is then probed and if necessary the IRQ is autodetected
- *     If this fails an error is returned.
- *
- *     On success the port is ready to use and the line number is returned.
- */
-int serial8250_register_port(struct uart_port *port)
-{
-       struct uart_8250_port *uart;
-       int ret = -ENOSPC;
-
-       if (port->uartclk == 0)
-               return -EINVAL;
-
-       mutex_lock(&serial_mutex);
-
-       uart = serial8250_find_match_or_unused(port);
-       if (uart) {
-               uart_remove_one_port(&serial8250_reg, &uart->port);
-
-               uart->port.iobase       = port->iobase;
-               uart->port.membase      = port->membase;
-               uart->port.irq          = port->irq;
-               uart->port.irqflags     = port->irqflags;
-               uart->port.uartclk      = port->uartclk;
-               uart->port.fifosize     = port->fifosize;
-               uart->port.regshift     = port->regshift;
-               uart->port.iotype       = port->iotype;
-               uart->port.flags        = port->flags | UPF_BOOT_AUTOCONF;
-               uart->port.mapbase      = port->mapbase;
-               uart->port.private_data = port->private_data;
-               if (port->dev)
-                       uart->port.dev = port->dev;
-
-               if (port->flags & UPF_FIXED_TYPE)
-                       serial8250_init_fixed_type_port(uart, port->type);
-
-               set_io_from_upio(&uart->port);
-               /* Possibly override default I/O functions.  */
-               if (port->serial_in)
-                       uart->port.serial_in = port->serial_in;
-               if (port->serial_out)
-                       uart->port.serial_out = port->serial_out;
-               /*  Possibly override set_termios call */
-               if (port->set_termios)
-                       uart->port.set_termios = port->set_termios;
-               if (port->pm)
-                       uart->port.pm = port->pm;
-
-               if (serial8250_isa_config != NULL)
-                       serial8250_isa_config(0, &uart->port,
-                                       &uart->capabilities);
-
-               ret = uart_add_one_port(&serial8250_reg, &uart->port);
-               if (ret == 0)
-                       ret = uart->port.line;
-       }
-       mutex_unlock(&serial_mutex);
-
-       return ret;
-}
-EXPORT_SYMBOL(serial8250_register_port);
-
-/**
- *     serial8250_unregister_port - remove a 16x50 serial port at runtime
- *     @line: serial line number
- *
- *     Remove one serial port.  This may not be called from interrupt
- *     context.  We hand the port back to the our control.
- */
-void serial8250_unregister_port(int line)
-{
-       struct uart_8250_port *uart = &serial8250_ports[line];
-
-       mutex_lock(&serial_mutex);
-       uart_remove_one_port(&serial8250_reg, &uart->port);
-       if (serial8250_isa_devs) {
-               uart->port.flags &= ~UPF_BOOT_AUTOCONF;
-               uart->port.type = PORT_UNKNOWN;
-               uart->port.dev = &serial8250_isa_devs->dev;
-               uart_add_one_port(&serial8250_reg, &uart->port);
-       } else {
-               uart->port.dev = NULL;
-       }
-       mutex_unlock(&serial_mutex);
-}
-EXPORT_SYMBOL(serial8250_unregister_port);
-
-static int __init serial8250_init(void)
-{
-       int ret;
-
-       if (nr_uarts > UART_NR)
-               nr_uarts = UART_NR;
-
-       printk(KERN_INFO "Serial: 8250/16550 driver, "
-               "%d ports, IRQ sharing %sabled\n", nr_uarts,
-               share_irqs ? "en" : "dis");
-
-#ifdef CONFIG_SPARC
-       ret = sunserial_register_minors(&serial8250_reg, UART_NR);
-#else
-       serial8250_reg.nr = UART_NR;
-       ret = uart_register_driver(&serial8250_reg);
-#endif
-       if (ret)
-               goto out;
-
-       serial8250_isa_devs = platform_device_alloc("serial8250",
-                                                   PLAT8250_DEV_LEGACY);
-       if (!serial8250_isa_devs) {
-               ret = -ENOMEM;
-               goto unreg_uart_drv;
-       }
-
-       ret = platform_device_add(serial8250_isa_devs);
-       if (ret)
-               goto put_dev;
-
-       serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev);
-
-       ret = platform_driver_register(&serial8250_isa_driver);
-       if (ret == 0)
-               goto out;
-
-       platform_device_del(serial8250_isa_devs);
-put_dev:
-       platform_device_put(serial8250_isa_devs);
-unreg_uart_drv:
-#ifdef CONFIG_SPARC
-       sunserial_unregister_minors(&serial8250_reg, UART_NR);
-#else
-       uart_unregister_driver(&serial8250_reg);
-#endif
-out:
-       return ret;
-}
-
-static void __exit serial8250_exit(void)
-{
-       struct platform_device *isa_dev = serial8250_isa_devs;
-
-       /*
-        * This tells serial8250_unregister_port() not to re-register
-        * the ports (thereby making serial8250_isa_driver permanently
-        * in use.)
-        */
-       serial8250_isa_devs = NULL;
-
-       platform_driver_unregister(&serial8250_isa_driver);
-       platform_device_unregister(isa_dev);
-
-#ifdef CONFIG_SPARC
-       sunserial_unregister_minors(&serial8250_reg, UART_NR);
-#else
-       uart_unregister_driver(&serial8250_reg);
-#endif
-}
-
-module_init(serial8250_init);
-module_exit(serial8250_exit);
-
-EXPORT_SYMBOL(serial8250_suspend_port);
-EXPORT_SYMBOL(serial8250_resume_port);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Generic 8250/16x50 serial driver");
-
-module_param(share_irqs, uint, 0644);
-MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices"
-       " (unsafe)");
-
-module_param(nr_uarts, uint, 0644);
-MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")");
-
-module_param(skip_txen_test, uint, 0644);
-MODULE_PARM_DESC(skip_txen_test, "Skip checking for the TXEN bug at init time");
-
-#ifdef CONFIG_SERIAL_8250_RSA
-module_param_array(probe_rsa, ulong, &probe_rsa_count, 0444);
-MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
-#endif
-MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
diff --git a/drivers/serial/8250.h b/drivers/serial/8250.h
deleted file mode 100644 (file)
index 6e19ea3..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- *  linux/drivers/char/8250.h
- *
- *  Driver for 8250/16550-type serial ports
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *
- *  Copyright (C) 2001 Russell King.
- *
- * 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.
- */
-
-#include <linux/serial_8250.h>
-
-struct old_serial_port {
-       unsigned int uart;
-       unsigned int baud_base;
-       unsigned int port;
-       unsigned int irq;
-       unsigned int flags;
-       unsigned char hub6;
-       unsigned char io_type;
-       unsigned char *iomem_base;
-       unsigned short iomem_reg_shift;
-       unsigned long irqflags;
-};
-
-/*
- * This replaces serial_uart_config in include/linux/serial.h
- */
-struct serial8250_config {
-       const char      *name;
-       unsigned short  fifo_size;
-       unsigned short  tx_loadsz;
-       unsigned char   fcr;
-       unsigned int    flags;
-};
-
-#define UART_CAP_FIFO  (1 << 8)        /* UART has FIFO */
-#define UART_CAP_EFR   (1 << 9)        /* UART has EFR */
-#define UART_CAP_SLEEP (1 << 10)       /* UART has IER sleep */
-#define UART_CAP_AFE   (1 << 11)       /* MCR-based hw flow control */
-#define UART_CAP_UUE   (1 << 12)       /* UART needs IER bit 6 set (Xscale) */
-
-#define UART_BUG_QUOT  (1 << 0)        /* UART has buggy quot LSB */
-#define UART_BUG_TXEN  (1 << 1)        /* UART has buggy TX IIR status */
-#define UART_BUG_NOMSR (1 << 2)        /* UART has buggy MSR status bits (Au1x00) */
-#define UART_BUG_THRE  (1 << 3)        /* UART has buggy THRE reassertion */
-
-#define PROBE_RSA      (1 << 0)
-#define PROBE_ANY      (~0)
-
-#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
-
-#ifdef CONFIG_SERIAL_8250_SHARE_IRQ
-#define SERIAL8250_SHARE_IRQS 1
-#else
-#define SERIAL8250_SHARE_IRQS 0
-#endif
-
-#if defined(__alpha__) && !defined(CONFIG_PCI)
-/*
- * Digital did something really horribly wrong with the OUT1 and OUT2
- * lines on at least some ALPHA's.  The failure mode is that if either
- * is cleared, the machine locks up with endless interrupts.
- */
-#define ALPHA_KLUDGE_MCR  (UART_MCR_OUT2 | UART_MCR_OUT1)
-#elif defined(CONFIG_SBC8560)
-/*
- * WindRiver did something similarly broken on their SBC8560 board. The
- * UART tristates its IRQ output while OUT2 is clear, but they pulled
- * the interrupt line _up_ instead of down, so if we register the IRQ
- * while the UART is in that state, we die in an IRQ storm. */
-#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2)
-#else
-#define ALPHA_KLUDGE_MCR 0
-#endif
diff --git a/drivers/serial/8250_accent.c b/drivers/serial/8250_accent.c
deleted file mode 100644 (file)
index 9c10262..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- *  linux/drivers/serial/8250_accent.c
- *
- *  Copyright (C) 2005 Russell King.
- *  Data taken from include/asm-i386/serial.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/serial_8250.h>
-
-#define PORT(_base,_irq)                               \
-       {                                               \
-               .iobase         = _base,                \
-               .irq            = _irq,                 \
-               .uartclk        = 1843200,              \
-               .iotype         = UPIO_PORT,            \
-               .flags          = UPF_BOOT_AUTOCONF,    \
-       }
-
-static struct plat_serial8250_port accent_data[] = {
-       PORT(0x330, 4),
-       PORT(0x338, 4),
-       { },
-};
-
-static struct platform_device accent_device = {
-       .name                   = "serial8250",
-       .id                     = PLAT8250_DEV_ACCENT,
-       .dev                    = {
-               .platform_data  = accent_data,
-       },
-};
-
-static int __init accent_init(void)
-{
-       return platform_device_register(&accent_device);
-}
-
-module_init(accent_init);
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("8250 serial probe module for Accent Async cards");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_acorn.c b/drivers/serial/8250_acorn.c
deleted file mode 100644 (file)
index b0ce8c5..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- *  linux/drivers/serial/acorn.c
- *
- *  Copyright (C) 1996-2003 Russell King.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/tty.h>
-#include <linux/serial_core.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/ecard.h>
-#include <asm/string.h>
-
-#include "8250.h"
-
-#define MAX_PORTS      3
-
-struct serial_card_type {
-       unsigned int    num_ports;
-       unsigned int    uartclk;
-       unsigned int    type;
-       unsigned int    offset[MAX_PORTS];
-};
-
-struct serial_card_info {
-       unsigned int    num_ports;
-       int             ports[MAX_PORTS];
-       void __iomem *vaddr;
-};
-
-static int __devinit
-serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
-{
-       struct serial_card_info *info;
-       struct serial_card_type *type = id->data;
-       struct uart_port port;
-       unsigned long bus_addr;
-       unsigned int i;
-
-       info = kzalloc(sizeof(struct serial_card_info), GFP_KERNEL);
-       if (!info)
-               return -ENOMEM;
-
-       info->num_ports = type->num_ports;
-
-       bus_addr = ecard_resource_start(ec, type->type);
-       info->vaddr = ecardm_iomap(ec, type->type, 0, 0);
-       if (!info->vaddr) {
-               kfree(info);
-               return -ENOMEM;
-       }
-
-       ecard_set_drvdata(ec, info);
-
-       memset(&port, 0, sizeof(struct uart_port));
-       port.irq        = ec->irq;
-       port.flags      = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
-       port.uartclk    = type->uartclk;
-       port.iotype     = UPIO_MEM;
-       port.regshift   = 2;
-       port.dev        = &ec->dev;
-
-       for (i = 0; i < info->num_ports; i ++) {
-               port.membase = info->vaddr + type->offset[i];
-               port.mapbase = bus_addr + type->offset[i];
-
-               info->ports[i] = serial8250_register_port(&port);
-       }
-
-       return 0;
-}
-
-static void __devexit serial_card_remove(struct expansion_card *ec)
-{
-       struct serial_card_info *info = ecard_get_drvdata(ec);
-       int i;
-
-       ecard_set_drvdata(ec, NULL);
-
-       for (i = 0; i < info->num_ports; i++)
-               if (info->ports[i] > 0)
-                       serial8250_unregister_port(info->ports[i]);
-
-       kfree(info);
-}
-
-static struct serial_card_type atomwide_type = {
-       .num_ports      = 3,
-       .uartclk        = 7372800,
-       .type           = ECARD_RES_IOCSLOW,
-       .offset         = { 0x2800, 0x2400, 0x2000 },
-};
-
-static struct serial_card_type serport_type = {
-       .num_ports      = 2,
-       .uartclk        = 3686400,
-       .type           = ECARD_RES_IOCSLOW,
-       .offset         = { 0x2000, 0x2020 },
-};
-
-static const struct ecard_id serial_cids[] = {
-       { MANU_ATOMWIDE,        PROD_ATOMWIDE_3PSERIAL, &atomwide_type  },
-       { MANU_SERPORT,         PROD_SERPORT_DSPORT,    &serport_type   },
-       { 0xffff, 0xffff }
-};
-
-static struct ecard_driver serial_card_driver = {
-       .probe          = serial_card_probe,
-       .remove         = __devexit_p(serial_card_remove),
-       .id_table       = serial_cids,
-       .drv = {
-               .name   = "8250_acorn",
-       },
-};
-
-static int __init serial_card_init(void)
-{
-       return ecard_register_driver(&serial_card_driver);
-}
-
-static void __exit serial_card_exit(void)
-{
-       ecard_remove_driver(&serial_card_driver);
-}
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("Acorn 8250-compatible serial port expansion card driver");
-MODULE_LICENSE("GPL");
-
-module_init(serial_card_init);
-module_exit(serial_card_exit);
diff --git a/drivers/serial/8250_boca.c b/drivers/serial/8250_boca.c
deleted file mode 100644 (file)
index 3bfe0f7..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- *  linux/drivers/serial/8250_boca.c
- *
- *  Copyright (C) 2005 Russell King.
- *  Data taken from include/asm-i386/serial.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/serial_8250.h>
-
-#define PORT(_base,_irq)                               \
-       {                                               \
-               .iobase         = _base,                \
-               .irq            = _irq,                 \
-               .uartclk        = 1843200,              \
-               .iotype         = UPIO_PORT,            \
-               .flags          = UPF_BOOT_AUTOCONF,    \
-       }
-
-static struct plat_serial8250_port boca_data[] = {
-       PORT(0x100, 12),
-       PORT(0x108, 12),
-       PORT(0x110, 12),
-       PORT(0x118, 12),
-       PORT(0x120, 12),
-       PORT(0x128, 12),
-       PORT(0x130, 12),
-       PORT(0x138, 12),
-       PORT(0x140, 12),
-       PORT(0x148, 12),
-       PORT(0x150, 12),
-       PORT(0x158, 12),
-       PORT(0x160, 12),
-       PORT(0x168, 12),
-       PORT(0x170, 12),
-       PORT(0x178, 12),
-       { },
-};
-
-static struct platform_device boca_device = {
-       .name                   = "serial8250",
-       .id                     = PLAT8250_DEV_BOCA,
-       .dev                    = {
-               .platform_data  = boca_data,
-       },
-};
-
-static int __init boca_init(void)
-{
-       return platform_device_register(&boca_device);
-}
-
-module_init(boca_init);
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("8250 serial probe module for Boca cards");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_early.c b/drivers/serial/8250_early.c
deleted file mode 100644 (file)
index eaafb98..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Early serial console for 8250/16550 devices
- *
- * (c) Copyright 2004 Hewlett-Packard Development Company, L.P.
- *     Bjorn Helgaas <bjorn.helgaas@hp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Based on the 8250.c serial driver, Copyright (C) 2001 Russell King,
- * and on early_printk.c by Andi Kleen.
- *
- * This is for use before the serial driver has initialized, in
- * particular, before the UARTs have been discovered and named.
- * Instead of specifying the console device as, e.g., "ttyS0",
- * we locate the device directly by its MMIO or I/O port address.
- *
- * The user can specify the device directly, e.g.,
- *     earlycon=uart8250,io,0x3f8,9600n8
- *     earlycon=uart8250,mmio,0xff5e0000,115200n8
- *     earlycon=uart8250,mmio32,0xff5e0000,115200n8
- * or
- *     console=uart8250,io,0x3f8,9600n8
- *     console=uart8250,mmio,0xff5e0000,115200n8
- *     console=uart8250,mmio32,0xff5e0000,115200n8
- */
-
-#include <linux/tty.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/serial_core.h>
-#include <linux/serial_reg.h>
-#include <linux/serial.h>
-#include <linux/serial_8250.h>
-#include <asm/io.h>
-#include <asm/serial.h>
-#ifdef CONFIG_FIX_EARLYCON_MEM
-#include <asm/pgtable.h>
-#include <asm/fixmap.h>
-#endif
-
-struct early_serial8250_device {
-       struct uart_port port;
-       char options[16];               /* e.g., 115200n8 */
-       unsigned int baud;
-};
-
-static struct early_serial8250_device early_device;
-
-static unsigned int __init serial_in(struct uart_port *port, int offset)
-{
-       switch (port->iotype) {
-       case UPIO_MEM:
-               return readb(port->membase + offset);
-       case UPIO_MEM32:
-               return readl(port->membase + (offset << 2));
-       case UPIO_PORT:
-               return inb(port->iobase + offset);
-       default:
-               return 0;
-       }
-}
-
-static void __init serial_out(struct uart_port *port, int offset, int value)
-{
-       switch (port->iotype) {
-       case UPIO_MEM:
-               writeb(value, port->membase + offset);
-               break;
-       case UPIO_MEM32:
-               writel(value, port->membase + (offset << 2));
-               break;
-       case UPIO_PORT:
-               outb(value, port->iobase + offset);
-               break;
-       }
-}
-
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-
-static void __init wait_for_xmitr(struct uart_port *port)
-{
-       unsigned int status;
-
-       for (;;) {
-               status = serial_in(port, UART_LSR);
-               if ((status & BOTH_EMPTY) == BOTH_EMPTY)
-                       return;
-               cpu_relax();
-       }
-}
-
-static void __init serial_putc(struct uart_port *port, int c)
-{
-       wait_for_xmitr(port);
-       serial_out(port, UART_TX, c);
-}
-
-static void __init early_serial8250_write(struct console *console,
-                                       const char *s, unsigned int count)
-{
-       struct uart_port *port = &early_device.port;
-       unsigned int ier;
-
-       /* Save the IER and disable interrupts */
-       ier = serial_in(port, UART_IER);
-       serial_out(port, UART_IER, 0);
-
-       uart_console_write(port, s, count, serial_putc);
-
-       /* Wait for transmitter to become empty and restore the IER */
-       wait_for_xmitr(port);
-       serial_out(port, UART_IER, ier);
-}
-
-static unsigned int __init probe_baud(struct uart_port *port)
-{
-       unsigned char lcr, dll, dlm;
-       unsigned int quot;
-
-       lcr = serial_in(port, UART_LCR);
-       serial_out(port, UART_LCR, lcr | UART_LCR_DLAB);
-       dll = serial_in(port, UART_DLL);
-       dlm = serial_in(port, UART_DLM);
-       serial_out(port, UART_LCR, lcr);
-
-       quot = (dlm << 8) | dll;
-       return (port->uartclk / 16) / quot;
-}
-
-static void __init init_port(struct early_serial8250_device *device)
-{
-       struct uart_port *port = &device->port;
-       unsigned int divisor;
-       unsigned char c;
-
-       serial_out(port, UART_LCR, 0x3);        /* 8n1 */
-       serial_out(port, UART_IER, 0);          /* no interrupt */
-       serial_out(port, UART_FCR, 0);          /* no fifo */
-       serial_out(port, UART_MCR, 0x3);        /* DTR + RTS */
-
-       divisor = port->uartclk / (16 * device->baud);
-       c = serial_in(port, UART_LCR);
-       serial_out(port, UART_LCR, c | UART_LCR_DLAB);
-       serial_out(port, UART_DLL, divisor & 0xff);
-       serial_out(port, UART_DLM, (divisor >> 8) & 0xff);
-       serial_out(port, UART_LCR, c & ~UART_LCR_DLAB);
-}
-
-static int __init parse_options(struct early_serial8250_device *device,
-                                                               char *options)
-{
-       struct uart_port *port = &device->port;
-       int mmio, mmio32, length;
-
-       if (!options)
-               return -ENODEV;
-
-       port->uartclk = BASE_BAUD * 16;
-
-       mmio = !strncmp(options, "mmio,", 5);
-       mmio32 = !strncmp(options, "mmio32,", 7);
-       if (mmio || mmio32) {
-               port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32);
-               port->mapbase = simple_strtoul(options + (mmio ? 5 : 7),
-                                              &options, 0);
-               if (mmio32)
-                       port->regshift = 2;
-#ifdef CONFIG_FIX_EARLYCON_MEM
-               set_fixmap_nocache(FIX_EARLYCON_MEM_BASE,
-                                       port->mapbase & PAGE_MASK);
-               port->membase =
-                       (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
-               port->membase += port->mapbase & ~PAGE_MASK;
-#else
-               port->membase = ioremap_nocache(port->mapbase, 64);
-               if (!port->membase) {
-                       printk(KERN_ERR "%s: Couldn't ioremap 0x%llx\n",
-                               __func__,
-                              (unsigned long long) port->mapbase);
-                       return -ENOMEM;
-               }
-#endif
-       } else if (!strncmp(options, "io,", 3)) {
-               port->iotype = UPIO_PORT;
-               port->iobase = simple_strtoul(options + 3, &options, 0);
-               mmio = 0;
-       } else
-               return -EINVAL;
-
-       options = strchr(options, ',');
-       if (options) {
-               options++;
-               device->baud = simple_strtoul(options, NULL, 0);
-               length = min(strcspn(options, " "), sizeof(device->options));
-               strncpy(device->options, options, length);
-       } else {
-               device->baud = probe_baud(port);
-               snprintf(device->options, sizeof(device->options), "%u",
-                       device->baud);
-       }
-
-       if (mmio || mmio32)
-               printk(KERN_INFO
-                      "Early serial console at MMIO%s 0x%llx (options '%s')\n",
-                       mmio32 ? "32" : "",
-                       (unsigned long long)port->mapbase,
-                       device->options);
-       else
-               printk(KERN_INFO
-                     "Early serial console at I/O port 0x%lx (options '%s')\n",
-                       port->iobase,
-                       device->options);
-
-       return 0;
-}
-
-static struct console early_serial8250_console __initdata = {
-       .name   = "uart",
-       .write  = early_serial8250_write,
-       .flags  = CON_PRINTBUFFER | CON_BOOT,
-       .index  = -1,
-};
-
-static int __init early_serial8250_setup(char *options)
-{
-       struct early_serial8250_device *device = &early_device;
-       int err;
-
-       if (device->port.membase || device->port.iobase)
-               return 0;
-
-       err = parse_options(device, options);
-       if (err < 0)
-               return err;
-
-       init_port(device);
-       return 0;
-}
-
-int __init setup_early_serial8250_console(char *cmdline)
-{
-       char *options;
-       int err;
-
-       options = strstr(cmdline, "uart8250,");
-       if (!options) {
-               options = strstr(cmdline, "uart,");
-               if (!options)
-                       return 0;
-       }
-
-       options = strchr(cmdline, ',') + 1;
-       err = early_serial8250_setup(options);
-       if (err < 0)
-               return err;
-
-       register_console(&early_serial8250_console);
-
-       return 0;
-}
-
-int serial8250_find_port_for_earlycon(void)
-{
-       struct early_serial8250_device *device = &early_device;
-       struct uart_port *port = &device->port;
-       int line;
-       int ret;
-
-       if (!device->port.membase && !device->port.iobase)
-               return -ENODEV;
-
-       line = serial8250_find_port(port);
-       if (line < 0)
-               return -ENODEV;
-
-       ret = update_console_cmdline("uart", 8250,
-                            "ttyS", line, device->options);
-       if (ret < 0)
-               ret = update_console_cmdline("uart", 0,
-                                    "ttyS", line, device->options);
-
-       return ret;
-}
-
-early_param("earlycon", setup_early_serial8250_console);
diff --git a/drivers/serial/8250_exar_st16c554.c b/drivers/serial/8250_exar_st16c554.c
deleted file mode 100644 (file)
index 567143a..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- *  linux/drivers/serial/8250_exar.c
- *
- *  Written by Paul B Schroeder < pschroeder "at" uplogix "dot" com >
- *  Based on 8250_boca.
- *
- *  Copyright (C) 2005 Russell King.
- *  Data taken from include/asm-i386/serial.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/serial_8250.h>
-
-#define PORT(_base,_irq)                               \
-       {                                               \
-               .iobase         = _base,                \
-               .irq            = _irq,                 \
-               .uartclk        = 1843200,              \
-               .iotype         = UPIO_PORT,            \
-               .flags          = UPF_BOOT_AUTOCONF,    \
-       }
-
-static struct plat_serial8250_port exar_data[] = {
-       PORT(0x100, 5),
-       PORT(0x108, 5),
-       PORT(0x110, 5),
-       PORT(0x118, 5),
-       { },
-};
-
-static struct platform_device exar_device = {
-       .name                   = "serial8250",
-       .id                     = PLAT8250_DEV_EXAR_ST16C554,
-       .dev                    = {
-               .platform_data  = exar_data,
-       },
-};
-
-static int __init exar_init(void)
-{
-       return platform_device_register(&exar_device);
-}
-
-module_init(exar_init);
-
-MODULE_AUTHOR("Paul B Schroeder");
-MODULE_DESCRIPTION("8250 serial probe module for Exar cards");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_fourport.c b/drivers/serial/8250_fourport.c
deleted file mode 100644 (file)
index 6375d68..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- *  linux/drivers/serial/8250_fourport.c
- *
- *  Copyright (C) 2005 Russell King.
- *  Data taken from include/asm-i386/serial.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/serial_8250.h>
-
-#define PORT(_base,_irq)                                               \
-       {                                                               \
-               .iobase         = _base,                                \
-               .irq            = _irq,                                 \
-               .uartclk        = 1843200,                              \
-               .iotype         = UPIO_PORT,                            \
-               .flags          = UPF_BOOT_AUTOCONF | UPF_FOURPORT,     \
-       }
-
-static struct plat_serial8250_port fourport_data[] = {
-       PORT(0x1a0, 9),
-       PORT(0x1a8, 9),
-       PORT(0x1b0, 9),
-       PORT(0x1b8, 9),
-       PORT(0x2a0, 5),
-       PORT(0x2a8, 5),
-       PORT(0x2b0, 5),
-       PORT(0x2b8, 5),
-       { },
-};
-
-static struct platform_device fourport_device = {
-       .name                   = "serial8250",
-       .id                     = PLAT8250_DEV_FOURPORT,
-       .dev                    = {
-               .platform_data  = fourport_data,
-       },
-};
-
-static int __init fourport_init(void)
-{
-       return platform_device_register(&fourport_device);
-}
-
-module_init(fourport_init);
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("8250 serial probe module for AST Fourport cards");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_gsc.c b/drivers/serial/8250_gsc.c
deleted file mode 100644 (file)
index d8c0ffb..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- *     Serial Device Initialisation for Lasi/Asp/Wax/Dino
- *
- *     (c) Copyright Matthew Wilcox <willy@debian.org> 2001-2002
- *
- *     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.
- */
-
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/module.h>
-#include <linux/serial_core.h>
-#include <linux/signal.h>
-#include <linux/types.h>
-
-#include <asm/hardware.h>
-#include <asm/parisc-device.h>
-#include <asm/io.h>
-
-#include "8250.h"
-
-static int __init serial_init_chip(struct parisc_device *dev)
-{
-       struct uart_port port;
-       unsigned long address;
-       int err;
-
-       if (!dev->irq) {
-               /* We find some unattached serial ports by walking native
-                * busses.  These should be silently ignored.  Otherwise,
-                * what we have here is a missing parent device, so tell
-                * the user what they're missing.
-                */
-               if (parisc_parent(dev)->id.hw_type != HPHW_IOA)
-                       printk(KERN_INFO
-                               "Serial: device 0x%llx not configured.\n"
-                               "Enable support for Wax, Lasi, Asp or Dino.\n",
-                               (unsigned long long)dev->hpa.start);
-               return -ENODEV;
-       }
-
-       address = dev->hpa.start;
-       if (dev->id.sversion != 0x8d)
-               address += 0x800;
-
-       memset(&port, 0, sizeof(port));
-       port.iotype     = UPIO_MEM;
-       /* 7.272727MHz on Lasi.  Assumed the same for Dino, Wax and Timi. */
-       port.uartclk    = 7272727;
-       port.mapbase    = address;
-       port.membase    = ioremap_nocache(address, 16);
-       port.irq        = dev->irq;
-       port.flags      = UPF_BOOT_AUTOCONF;
-       port.dev        = &dev->dev;
-
-       err = serial8250_register_port(&port);
-       if (err < 0) {
-               printk(KERN_WARNING
-                       "serial8250_register_port returned error %d\n", err);
-               iounmap(port.membase);
-               return err;
-       }
-
-       return 0;
-}
-
-static struct parisc_device_id serial_tbl[] = {
-       { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00075 },
-       { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008c },
-       { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008d },
-       { 0 }
-};
-
-/* Hack.  Some machines have SERIAL_0 attached to Lasi and SERIAL_1
- * attached to Dino.  Unfortunately, Dino appears before Lasi in the device
- * tree.  To ensure that ttyS0 == SERIAL_0, we register two drivers; one
- * which only knows about Lasi and then a second which will find all the
- * other serial ports.  HPUX ignores this problem.
- */
-static struct parisc_device_id lasi_tbl[] = {
-       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03B, 0x0008C }, /* C1xx/C1xxL */
-       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03C, 0x0008C }, /* B132L */
-       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03D, 0x0008C }, /* B160L */
-       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03E, 0x0008C }, /* B132L+ */
-       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03F, 0x0008C }, /* B180L+ */
-       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x046, 0x0008C }, /* Rocky2 120 */
-       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x047, 0x0008C }, /* Rocky2 150 */
-       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x04E, 0x0008C }, /* Kiji L2 132 */
-       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x056, 0x0008C }, /* Raven+ */
-       { 0 }
-};
-
-
-MODULE_DEVICE_TABLE(parisc, serial_tbl);
-
-static struct parisc_driver lasi_driver = {
-       .name           = "serial_1",
-       .id_table       = lasi_tbl,
-       .probe          = serial_init_chip,
-};
-
-static struct parisc_driver serial_driver = {
-       .name           = "serial",
-       .id_table       = serial_tbl,
-       .probe          = serial_init_chip,
-};
-
-static int __init probe_serial_gsc(void)
-{
-       register_parisc_driver(&lasi_driver);
-       register_parisc_driver(&serial_driver);
-       return 0;
-}
-
-module_init(probe_serial_gsc);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_hp300.c b/drivers/serial/8250_hp300.c
deleted file mode 100644 (file)
index c13438c..0000000
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Driver for the 98626/98644/internal serial interface on hp300/hp400
- * (based on the National Semiconductor INS8250/NS16550AF/WD16C552 UARTs)
- *
- * Ported from 2.2 and modified to use the normal 8250 driver
- * by Kars de Jong <jongk@linux-m68k.org>, May 2004.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <linux/serial_8250.h>
-#include <linux/delay.h>
-#include <linux/dio.h>
-#include <linux/console.h>
-#include <linux/slab.h>
-#include <asm/io.h>
-
-#include "8250.h"
-
-#if !defined(CONFIG_HPDCA) && !defined(CONFIG_HPAPCI)
-#warning CONFIG_8250 defined but neither CONFIG_HPDCA nor CONFIG_HPAPCI defined, are you sure?
-#endif
-
-#ifdef CONFIG_HPAPCI
-struct hp300_port
-{
-       struct hp300_port *next;        /* next port */
-       int line;                       /* line (tty) number */
-};
-
-static struct hp300_port *hp300_ports;
-#endif
-
-#ifdef CONFIG_HPDCA
-
-static int __devinit hpdca_init_one(struct dio_dev *d,
-                                       const struct dio_device_id *ent);
-static void __devexit hpdca_remove_one(struct dio_dev *d);
-
-static struct dio_device_id hpdca_dio_tbl[] = {
-       { DIO_ID_DCA0 },
-       { DIO_ID_DCA0REM },
-       { DIO_ID_DCA1 },
-       { DIO_ID_DCA1REM },
-       { 0 }
-};
-
-static struct dio_driver hpdca_driver = {
-       .name      = "hpdca",
-       .id_table  = hpdca_dio_tbl,
-       .probe     = hpdca_init_one,
-       .remove    = __devexit_p(hpdca_remove_one),
-};
-
-#endif
-
-static unsigned int num_ports;
-
-extern int hp300_uart_scode;
-
-/* Offset to UART registers from base of DCA */
-#define UART_OFFSET    17
-
-#define DCA_ID         0x01    /* ID (read), reset (write) */
-#define DCA_IC         0x03    /* Interrupt control        */
-
-/* Interrupt control */
-#define DCA_IC_IE      0x80    /* Master interrupt enable  */
-
-#define HPDCA_BAUD_BASE 153600
-
-/* Base address of the Frodo part */
-#define FRODO_BASE     (0x41c000)
-
-/*
- * Where we find the 8250-like APCI ports, and how far apart they are.
- */
-#define FRODO_APCIBASE         0x0
-#define FRODO_APCISPACE                0x20
-#define FRODO_APCI_OFFSET(x)   (FRODO_APCIBASE + ((x) * FRODO_APCISPACE))
-
-#define HPAPCI_BAUD_BASE 500400
-
-#ifdef CONFIG_SERIAL_8250_CONSOLE
-/*
- * Parse the bootinfo to find descriptions for headless console and
- * debug serial ports and register them with the 8250 driver.
- * This function should be called before serial_console_init() is called
- * to make sure the serial console will be available for use. IA-64 kernel
- * calls this function from setup_arch() after the EFI and ACPI tables have
- * been parsed.
- */
-int __init hp300_setup_serial_console(void)
-{
-       int scode;
-       struct uart_port port;
-
-       memset(&port, 0, sizeof(port));
-
-       if (hp300_uart_scode < 0 || hp300_uart_scode > DIO_SCMAX)
-               return 0;
-
-       if (DIO_SCINHOLE(hp300_uart_scode))
-               return 0;
-
-       scode = hp300_uart_scode;
-
-       /* Memory mapped I/O */
-       port.iotype = UPIO_MEM;
-       port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF;
-       port.type = PORT_UNKNOWN;
-
-       /* Check for APCI console */
-       if (scode == 256) {
-#ifdef CONFIG_HPAPCI
-               printk(KERN_INFO "Serial console is HP APCI 1\n");
-
-               port.uartclk = HPAPCI_BAUD_BASE * 16;
-               port.mapbase = (FRODO_BASE + FRODO_APCI_OFFSET(1));
-               port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE);
-               port.regshift = 2;
-               add_preferred_console("ttyS", port.line, "9600n8");
-#else
-               printk(KERN_WARNING "Serial console is APCI but support is disabled (CONFIG_HPAPCI)!\n");
-               return 0;
-#endif
-       } else {
-#ifdef CONFIG_HPDCA
-               unsigned long pa = dio_scodetophysaddr(scode);
-               if (!pa)
-                       return 0;
-
-               printk(KERN_INFO "Serial console is HP DCA at select code %d\n", scode);
-
-               port.uartclk = HPDCA_BAUD_BASE * 16;
-               port.mapbase = (pa + UART_OFFSET);
-               port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE);
-               port.regshift = 1;
-               port.irq = DIO_IPL(pa + DIO_VIRADDRBASE);
-
-               /* Enable board-interrupts */
-               out_8(pa + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE);
-
-               if (DIO_ID(pa + DIO_VIRADDRBASE) & 0x80)
-                       add_preferred_console("ttyS", port.line, "9600n8");
-#else
-               printk(KERN_WARNING "Serial console is DCA but support is disabled (CONFIG_HPDCA)!\n");
-               return 0;
-#endif
-       }
-
-       if (early_serial_setup(&port) < 0)
-               printk(KERN_WARNING "hp300_setup_serial_console(): early_serial_setup() failed.\n");
-       return 0;
-}
-#endif /* CONFIG_SERIAL_8250_CONSOLE */
-
-#ifdef CONFIG_HPDCA
-static int __devinit hpdca_init_one(struct dio_dev *d,
-                               const struct dio_device_id *ent)
-{
-       struct uart_port port;
-       int line;
-
-#ifdef CONFIG_SERIAL_8250_CONSOLE
-       if (hp300_uart_scode == d->scode) {
-               /* Already got it. */
-               return 0;
-       }
-#endif
-       memset(&port, 0, sizeof(struct uart_port));
-
-       /* Memory mapped I/O */
-       port.iotype = UPIO_MEM;
-       port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF;
-       port.irq = d->ipl;
-       port.uartclk = HPDCA_BAUD_BASE * 16;
-       port.mapbase = (d->resource.start + UART_OFFSET);
-       port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE);
-       port.regshift = 1;
-       port.dev = &d->dev;
-       line = serial8250_register_port(&port);
-
-       if (line < 0) {
-               printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d"
-                      " irq %d failed\n", d->scode, port.irq);
-               return -ENOMEM;
-       }
-
-       /* Enable board-interrupts */
-       out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE);
-       dio_set_drvdata(d, (void *)line);
-
-       /* Reset the DCA */
-       out_8(d->resource.start + DIO_VIRADDRBASE + DCA_ID, 0xff);
-       udelay(100);
-
-       num_ports++;
-
-       return 0;
-}
-#endif
-
-static int __init hp300_8250_init(void)
-{
-       static int called;
-#ifdef CONFIG_HPAPCI
-       int line;
-       unsigned long base;
-       struct uart_port uport;
-       struct hp300_port *port;
-       int i;
-#endif
-       if (called)
-               return -ENODEV;
-       called = 1;
-
-       if (!MACH_IS_HP300)
-               return -ENODEV;
-
-#ifdef CONFIG_HPDCA
-       dio_register_driver(&hpdca_driver);
-#endif
-#ifdef CONFIG_HPAPCI
-       if (hp300_model < HP_400) {
-               if (!num_ports)
-                       return -ENODEV;
-               return 0;
-       }
-       /* These models have the Frodo chip.
-        * Port 0 is reserved for the Apollo Domain keyboard.
-        * Port 1 is either the console or the DCA.
-        */
-       for (i = 1; i < 4; i++) {
-               /* Port 1 is the console on a 425e, on other machines it's
-                * mapped to DCA.
-                */
-#ifdef CONFIG_SERIAL_8250_CONSOLE
-               if (i == 1)
-                       continue;
-#endif
-
-               /* Create new serial device */
-               port = kmalloc(sizeof(struct hp300_port), GFP_KERNEL);
-               if (!port)
-                       return -ENOMEM;
-
-               memset(&uport, 0, sizeof(struct uart_port));
-
-               base = (FRODO_BASE + FRODO_APCI_OFFSET(i));
-
-               /* Memory mapped I/O */
-               uport.iotype = UPIO_MEM;
-               uport.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ \
-                             | UPF_BOOT_AUTOCONF;
-               /* XXX - no interrupt support yet */
-               uport.irq = 0;
-               uport.uartclk = HPAPCI_BAUD_BASE * 16;
-               uport.mapbase = base;
-               uport.membase = (char *)(base + DIO_VIRADDRBASE);
-               uport.regshift = 2;
-
-               line = serial8250_register_port(&uport);
-
-               if (line < 0) {
-                       printk(KERN_NOTICE "8250_hp300: register_serial() APCI"
-                              " %d irq %d failed\n", i, uport.irq);
-                       kfree(port);
-                       continue;
-               }
-
-               port->line = line;
-               port->next = hp300_ports;
-               hp300_ports = port;
-
-               num_ports++;
-       }
-#endif
-
-       /* Any boards found? */
-       if (!num_ports)
-               return -ENODEV;
-
-       return 0;
-}
-
-#ifdef CONFIG_HPDCA
-static void __devexit hpdca_remove_one(struct dio_dev *d)
-{
-       int line;
-
-       line = (int) dio_get_drvdata(d);
-       if (d->resource.start) {
-               /* Disable board-interrupts */
-               out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, 0);
-       }
-       serial8250_unregister_port(line);
-}
-#endif
-
-static void __exit hp300_8250_exit(void)
-{
-#ifdef CONFIG_HPAPCI
-       struct hp300_port *port, *to_free;
-
-       for (port = hp300_ports; port; ) {
-               serial8250_unregister_port(port->line);
-               to_free = port;
-               port = port->next;
-               kfree(to_free);
-       }
-
-       hp300_ports = NULL;
-#endif
-#ifdef CONFIG_HPDCA
-       dio_unregister_driver(&hpdca_driver);
-#endif
-}
-
-module_init(hp300_8250_init);
-module_exit(hp300_8250_exit);
-MODULE_DESCRIPTION("HP DCA/APCI serial driver");
-MODULE_AUTHOR("Kars de Jong <jongk@linux-m68k.org>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_hub6.c b/drivers/serial/8250_hub6.c
deleted file mode 100644 (file)
index 7609150..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- *  linux/drivers/serial/8250_hub6.c
- *
- *  Copyright (C) 2005 Russell King.
- *  Data taken from include/asm-i386/serial.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/serial_8250.h>
-
-#define HUB6(card,port)                                                        \
-       {                                                               \
-               .iobase         = 0x302,                                \
-               .irq            = 3,                                    \
-               .uartclk        = 1843200,                              \
-               .iotype         = UPIO_HUB6,                            \
-               .flags          = UPF_BOOT_AUTOCONF,                    \
-               .hub6           = (card) << 6 | (port) << 3 | 1,        \
-       }
-
-static struct plat_serial8250_port hub6_data[] = {
-       HUB6(0, 0),
-       HUB6(0, 1),
-       HUB6(0, 2),
-       HUB6(0, 3),
-       HUB6(0, 4),
-       HUB6(0, 5),
-       HUB6(1, 0),
-       HUB6(1, 1),
-       HUB6(1, 2),
-       HUB6(1, 3),
-       HUB6(1, 4),
-       HUB6(1, 5),
-       { },
-};
-
-static struct platform_device hub6_device = {
-       .name                   = "serial8250",
-       .id                     = PLAT8250_DEV_HUB6,
-       .dev                    = {
-               .platform_data  = hub6_data,
-       },
-};
-
-static int __init hub6_init(void)
-{
-       return platform_device_register(&hub6_device);
-}
-
-module_init(hub6_init);
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("8250 serial probe module for Hub6 cards");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_mca.c b/drivers/serial/8250_mca.c
deleted file mode 100644 (file)
index d10be94..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- *  linux/drivers/serial/8250_mca.c
- *
- *  Copyright (C) 2005 Russell King.
- *  Data taken from include/asm-i386/serial.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/mca.h>
-#include <linux/serial_8250.h>
-
-/*
- * FIXME: Should we be doing AUTO_IRQ here?
- */
-#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
-#define MCA_FLAGS      UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ
-#else
-#define MCA_FLAGS      UPF_BOOT_AUTOCONF | UPF_SKIP_TEST
-#endif
-
-#define PORT(_base,_irq)                       \
-       {                                       \
-               .iobase         = _base,        \
-               .irq            = _irq,         \
-               .uartclk        = 1843200,      \
-               .iotype         = UPIO_PORT,    \
-               .flags          = MCA_FLAGS,    \
-       }
-
-static struct plat_serial8250_port mca_data[] = {
-       PORT(0x3220, 3),
-       PORT(0x3228, 3),
-       PORT(0x4220, 3),
-       PORT(0x4228, 3),
-       PORT(0x5220, 3),
-       PORT(0x5228, 3),
-       { },
-};
-
-static struct platform_device mca_device = {
-       .name                   = "serial8250",
-       .id                     = PLAT8250_DEV_MCA,
-       .dev                    = {
-               .platform_data  = mca_data,
-       },
-};
-
-static int __init mca_init(void)
-{
-       if (!MCA_bus)
-               return -ENODEV;
-       return platform_device_register(&mca_device);
-}
-
-module_init(mca_init);
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("8250 serial probe module for MCA ports");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
deleted file mode 100644 (file)
index 8b8930f..0000000
+++ /dev/null
@@ -1,3850 +0,0 @@
-/*
- *  linux/drivers/char/8250_pci.c
- *
- *  Probe module for 8250/16550-type PCI serial ports.
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *
- *  Copyright (C) 2001 Russell King, 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.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/tty.h>
-#include <linux/serial_core.h>
-#include <linux/8250_pci.h>
-#include <linux/bitops.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-
-#include "8250.h"
-
-#undef SERIAL_DEBUG_PCI
-
-/*
- * init function returns:
- *  > 0 - number of ports
- *  = 0 - use board->num_ports
- *  < 0 - error
- */
-struct pci_serial_quirk {
-       u32     vendor;
-       u32     device;
-       u32     subvendor;
-       u32     subdevice;
-       int     (*init)(struct pci_dev *dev);
-       int     (*setup)(struct serial_private *,
-                        const struct pciserial_board *,
-                        struct uart_port *, int);
-       void    (*exit)(struct pci_dev *dev);
-};
-
-#define PCI_NUM_BAR_RESOURCES  6
-
-struct serial_private {
-       struct pci_dev          *dev;
-       unsigned int            nr;
-       void __iomem            *remapped_bar[PCI_NUM_BAR_RESOURCES];
-       struct pci_serial_quirk *quirk;
-       int                     line[0];
-};
-
-static void moan_device(const char *str, struct pci_dev *dev)
-{
-       printk(KERN_WARNING
-              "%s: %s\n"
-              "Please send the output of lspci -vv, this\n"
-              "message (0x%04x,0x%04x,0x%04x,0x%04x), the\n"
-              "manufacturer and name of serial board or\n"
-              "modem board to rmk+serial@arm.linux.org.uk.\n",
-              pci_name(dev), str, dev->vendor, dev->device,
-              dev->subsystem_vendor, dev->subsystem_device);
-}
-
-static int
-setup_port(struct serial_private *priv, struct uart_port *port,
-          int bar, int offset, int regshift)
-{
-       struct pci_dev *dev = priv->dev;
-       unsigned long base, len;
-
-       if (bar >= PCI_NUM_BAR_RESOURCES)
-               return -EINVAL;
-
-       base = pci_resource_start(dev, bar);
-
-       if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) {
-               len =  pci_resource_len(dev, bar);
-
-               if (!priv->remapped_bar[bar])
-                       priv->remapped_bar[bar] = ioremap_nocache(base, len);
-               if (!priv->remapped_bar[bar])
-                       return -ENOMEM;
-
-               port->iotype = UPIO_MEM;
-               port->iobase = 0;
-               port->mapbase = base + offset;
-               port->membase = priv->remapped_bar[bar] + offset;
-               port->regshift = regshift;
-       } else {
-               port->iotype = UPIO_PORT;
-               port->iobase = base + offset;
-               port->mapbase = 0;
-               port->membase = NULL;
-               port->regshift = 0;
-       }
-       return 0;
-}
-
-/*
- * ADDI-DATA GmbH communication cards <info@addi-data.com>
- */
-static int addidata_apci7800_setup(struct serial_private *priv,
-                               const struct pciserial_board *board,
-                               struct uart_port *port, int idx)
-{
-       unsigned int bar = 0, offset = board->first_offset;
-       bar = FL_GET_BASE(board->flags);
-
-       if (idx < 2) {
-               offset += idx * board->uart_offset;
-       } else if ((idx >= 2) && (idx < 4)) {
-               bar += 1;
-               offset += ((idx - 2) * board->uart_offset);
-       } else if ((idx >= 4) && (idx < 6)) {
-               bar += 2;
-               offset += ((idx - 4) * board->uart_offset);
-       } else if (idx >= 6) {
-               bar += 3;
-               offset += ((idx - 6) * board->uart_offset);
-       }
-
-       return setup_port(priv, port, bar, offset, board->reg_shift);
-}
-
-/*
- * AFAVLAB uses a different mixture of BARs and offsets
- * Not that ugly ;) -- HW
- */
-static int
-afavlab_setup(struct serial_private *priv, const struct pciserial_board *board,
-             struct uart_port *port, int idx)
-{
-       unsigned int bar, offset = board->first_offset;
-
-       bar = FL_GET_BASE(board->flags);
-       if (idx < 4)
-               bar += idx;
-       else {
-               bar = 4;
-               offset += (idx - 4) * board->uart_offset;
-       }
-
-       return setup_port(priv, port, bar, offset, board->reg_shift);
-}
-
-/*
- * HP's Remote Management Console.  The Diva chip came in several
- * different versions.  N-class, L2000 and A500 have two Diva chips, each
- * with 3 UARTs (the third UART on the second chip is unused).  Superdome
- * and Keystone have one Diva chip with 3 UARTs.  Some later machines have
- * one Diva chip, but it has been expanded to 5 UARTs.
- */
-static int pci_hp_diva_init(struct pci_dev *dev)
-{
-       int rc = 0;
-
-       switch (dev->subsystem_device) {
-       case PCI_DEVICE_ID_HP_DIVA_TOSCA1:
-       case PCI_DEVICE_ID_HP_DIVA_HALFDOME:
-       case PCI_DEVICE_ID_HP_DIVA_KEYSTONE:
-       case PCI_DEVICE_ID_HP_DIVA_EVEREST:
-               rc = 3;
-               break;
-       case PCI_DEVICE_ID_HP_DIVA_TOSCA2:
-               rc = 2;
-               break;
-       case PCI_DEVICE_ID_HP_DIVA_MAESTRO:
-               rc = 4;
-               break;
-       case PCI_DEVICE_ID_HP_DIVA_POWERBAR:
-       case PCI_DEVICE_ID_HP_DIVA_HURRICANE:
-               rc = 1;
-               break;
-       }
-
-       return rc;
-}
-
-/*
- * HP's Diva chip puts the 4th/5th serial port further out, and
- * some serial ports are supposed to be hidden on certain models.
- */
-static int
-pci_hp_diva_setup(struct serial_private *priv,
-               const struct pciserial_board *board,
-               struct uart_port *port, int idx)
-{
-       unsigned int offset = board->first_offset;
-       unsigned int bar = FL_GET_BASE(board->flags);
-
-       switch (priv->dev->subsystem_device) {
-       case PCI_DEVICE_ID_HP_DIVA_MAESTRO:
-               if (idx == 3)
-                       idx++;
-               break;
-       case PCI_DEVICE_ID_HP_DIVA_EVEREST:
-               if (idx > 0)
-                       idx++;
-               if (idx > 2)
-                       idx++;
-               break;
-       }
-       if (idx > 2)
-               offset = 0x18;
-
-       offset += idx * board->uart_offset;
-
-       return setup_port(priv, port, bar, offset, board->reg_shift);
-}
-
-/*
- * Added for EKF Intel i960 serial boards
- */
-static int pci_inteli960ni_init(struct pci_dev *dev)
-{
-       unsigned long oldval;
-
-       if (!(dev->subsystem_device & 0x1000))
-               return -ENODEV;
-
-       /* is firmware started? */
-       pci_read_config_dword(dev, 0x44, (void *)&oldval);
-       if (oldval == 0x00001000L) { /* RESET value */
-               printk(KERN_DEBUG "Local i960 firmware missing");
-               return -ENODEV;
-       }
-       return 0;
-}
-
-/*
- * Some PCI serial cards using the PLX 9050 PCI interface chip require
- * that the card interrupt be explicitly enabled or disabled.  This
- * seems to be mainly needed on card using the PLX which also use I/O
- * mapped memory.
- */
-static int pci_plx9050_init(struct pci_dev *dev)
-{
-       u8 irq_config;
-       void __iomem *p;
-
-       if ((pci_resource_flags(dev, 0) & IORESOURCE_MEM) == 0) {
-               moan_device("no memory in bar 0", dev);
-               return 0;
-       }
-
-       irq_config = 0x41;
-       if (dev->vendor == PCI_VENDOR_ID_PANACOM ||
-           dev->subsystem_vendor == PCI_SUBVENDOR_ID_EXSYS)
-               irq_config = 0x43;
-
-       if ((dev->vendor == PCI_VENDOR_ID_PLX) &&
-           (dev->device == PCI_DEVICE_ID_PLX_ROMULUS))
-               /*
-                * As the megawolf cards have the int pins active
-                * high, and have 2 UART chips, both ints must be
-                * enabled on the 9050. Also, the UARTS are set in
-                * 16450 mode by default, so we have to enable the
-                * 16C950 'enhanced' mode so that we can use the
-                * deep FIFOs
-                */
-               irq_config = 0x5b;
-       /*
-        * enable/disable interrupts
-        */
-       p = ioremap_nocache(pci_resource_start(dev, 0), 0x80);
-       if (p == NULL)
-               return -ENOMEM;
-       writel(irq_config, p + 0x4c);
-
-       /*
-        * Read the register back to ensure that it took effect.
-        */
-       readl(p + 0x4c);
-       iounmap(p);
-
-       return 0;
-}
-
-static void __devexit pci_plx9050_exit(struct pci_dev *dev)
-{
-       u8 __iomem *p;
-
-       if ((pci_resource_flags(dev, 0) & IORESOURCE_MEM) == 0)
-               return;
-
-       /*
-        * disable interrupts
-        */
-       p = ioremap_nocache(pci_resource_start(dev, 0), 0x80);
-       if (p != NULL) {
-               writel(0, p + 0x4c);
-
-               /*
-                * Read the register back to ensure that it took effect.
-                */
-               readl(p + 0x4c);
-               iounmap(p);
-       }
-}
-
-#define NI8420_INT_ENABLE_REG  0x38
-#define NI8420_INT_ENABLE_BIT  0x2000
-
-static void __devexit pci_ni8420_exit(struct pci_dev *dev)
-{
-       void __iomem *p;
-       unsigned long base, len;
-       unsigned int bar = 0;
-
-       if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) {
-               moan_device("no memory in bar", dev);
-               return;
-       }
-
-       base = pci_resource_start(dev, bar);
-       len =  pci_resource_len(dev, bar);
-       p = ioremap_nocache(base, len);
-       if (p == NULL)
-               return;
-
-       /* Disable the CPU Interrupt */
-       writel(readl(p + NI8420_INT_ENABLE_REG) & ~(NI8420_INT_ENABLE_BIT),
-              p + NI8420_INT_ENABLE_REG);
-       iounmap(p);
-}
-
-
-/* MITE registers */
-#define MITE_IOWBSR1   0xc4
-#define MITE_IOWCR1    0xf4
-#define MITE_LCIMR1    0x08
-#define MITE_LCIMR2    0x10
-
-#define MITE_LCIMR2_CLR_CPU_IE (1 << 30)
-
-static void __devexit pci_ni8430_exit(struct pci_dev *dev)
-{
-       void __iomem *p;
-       unsigned long base, len;
-       unsigned int bar = 0;
-
-       if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) {
-               moan_device("no memory in bar", dev);
-               return;
-       }
-
-       base = pci_resource_start(dev, bar);
-       len =  pci_resource_len(dev, bar);
-       p = ioremap_nocache(base, len);
-       if (p == NULL)
-               return;
-
-       /* Disable the CPU Interrupt */
-       writel(MITE_LCIMR2_CLR_CPU_IE, p + MITE_LCIMR2);
-       iounmap(p);
-}
-
-/* SBS Technologies Inc. PMC-OCTPRO and P-OCTAL cards */
-static int
-sbs_setup(struct serial_private *priv, const struct pciserial_board *board,
-               struct uart_port *port, int idx)
-{
-       unsigned int bar, offset = board->first_offset;
-
-       bar = 0;
-
-       if (idx < 4) {
-               /* first four channels map to 0, 0x100, 0x200, 0x300 */
-               offset += idx * board->uart_offset;
-       } else if (idx < 8) {
-               /* last four channels map to 0x1000, 0x1100, 0x1200, 0x1300 */
-               offset += idx * board->uart_offset + 0xC00;
-       } else /* we have only 8 ports on PMC-OCTALPRO */
-               return 1;
-
-       return setup_port(priv, port, bar, offset, board->reg_shift);
-}
-
-/*
-* This does initialization for PMC OCTALPRO cards:
-* maps the device memory, resets the UARTs (needed, bc
-* if the module is removed and inserted again, the card
-* is in the sleep mode) and enables global interrupt.
-*/
-
-/* global control register offset for SBS PMC-OctalPro */
-#define OCT_REG_CR_OFF         0x500
-
-static int sbs_init(struct pci_dev *dev)
-{
-       u8 __iomem *p;
-
-       p = pci_ioremap_bar(dev, 0);
-
-       if (p == NULL)
-               return -ENOMEM;
-       /* Set bit-4 Control Register (UART RESET) in to reset the uarts */
-       writeb(0x10, p + OCT_REG_CR_OFF);
-       udelay(50);
-       writeb(0x0, p + OCT_REG_CR_OFF);
-
-       /* Set bit-2 (INTENABLE) of Control Register */
-       writeb(0x4, p + OCT_REG_CR_OFF);
-       iounmap(p);
-
-       return 0;
-}
-
-/*
- * Disables the global interrupt of PMC-OctalPro
- */
-
-static void __devexit sbs_exit(struct pci_dev *dev)
-{
-       u8 __iomem *p;
-
-       p = pci_ioremap_bar(dev, 0);
-       /* FIXME: What if resource_len < OCT_REG_CR_OFF */
-       if (p != NULL)
-               writeb(0, p + OCT_REG_CR_OFF);
-       iounmap(p);
-}
-
-/*
- * SIIG serial cards have an PCI interface chip which also controls
- * the UART clocking frequency. Each UART can be clocked independently
- * (except cards equiped with 4 UARTs) and initial clocking settings
- * are stored in the EEPROM chip. It can cause problems because this
- * version of serial driver doesn't support differently clocked UART's
- * on single PCI card. To prevent this, initialization functions set
- * high frequency clocking for all UART's on given card. It is safe (I
- * hope) because it doesn't touch EEPROM settings to prevent conflicts
- * with other OSes (like M$ DOS).
- *
- *  SIIG support added by Andrey Panin <pazke@donpac.ru>, 10/1999
- *
- * There is two family of SIIG serial cards with different PCI
- * interface chip and different configuration methods:
- *     - 10x cards have control registers in IO and/or memory space;
- *     - 20x cards have control registers in standard PCI configuration space.
- *
- * Note: all 10x cards have PCI device ids 0x10..
- *       all 20x cards have PCI device ids 0x20..
- *
- * There are also Quartet Serial cards which use Oxford Semiconductor
- * 16954 quad UART PCI chip clocked by 18.432 MHz quartz.
- *
- * Note: some SIIG cards are probed by the parport_serial object.
- */
-
-#define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc)
-#define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8)
-
-static int pci_siig10x_init(struct pci_dev *dev)
-{
-       u16 data;
-       void __iomem *p;
-
-       switch (dev->device & 0xfff8) {
-       case PCI_DEVICE_ID_SIIG_1S_10x: /* 1S */
-               data = 0xffdf;
-               break;
-       case PCI_DEVICE_ID_SIIG_2S_10x: /* 2S, 2S1P */
-               data = 0xf7ff;
-               break;
-       default:                        /* 1S1P, 4S */
-               data = 0xfffb;
-               break;
-       }
-
-       p = ioremap_nocache(pci_resource_start(dev, 0), 0x80);
-       if (p == NULL)
-               return -ENOMEM;
-
-       writew(readw(p + 0x28) & data, p + 0x28);
-       readw(p + 0x28);
-       iounmap(p);
-       return 0;
-}
-
-#define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc)
-#define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc)
-
-static int pci_siig20x_init(struct pci_dev *dev)
-{
-       u8 data;
-
-       /* Change clock frequency for the first UART. */
-       pci_read_config_byte(dev, 0x6f, &data);
-       pci_write_config_byte(dev, 0x6f, data & 0xef);
-
-       /* If this card has 2 UART, we have to do the same with second UART. */
-       if (((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S_20x) ||
-           ((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S1P_20x)) {
-               pci_read_config_byte(dev, 0x73, &data);
-               pci_write_config_byte(dev, 0x73, data & 0xef);
-       }
-       return 0;
-}
-
-static int pci_siig_init(struct pci_dev *dev)
-{
-       unsigned int type = dev->device & 0xff00;
-
-       if (type == 0x1000)
-               return pci_siig10x_init(dev);
-       else if (type == 0x2000)
-               return pci_siig20x_init(dev);
-
-       moan_device("Unknown SIIG card", dev);
-       return -ENODEV;
-}
-
-static int pci_siig_setup(struct serial_private *priv,
-                         const struct pciserial_board *board,
-                         struct uart_port *port, int idx)
-{
-       unsigned int bar = FL_GET_BASE(board->flags) + idx, offset = 0;
-
-       if (idx > 3) {
-               bar = 4;
-               offset = (idx - 4) * 8;
-       }
-
-       return setup_port(priv, port, bar, offset, 0);
-}
-
-/*
- * Timedia has an explosion of boards, and to avoid the PCI table from
- * growing *huge*, we use this function to collapse some 70 entries
- * in the PCI table into one, for sanity's and compactness's sake.
- */
-static const unsigned short timedia_single_port[] = {
-       0x4025, 0x4027, 0x4028, 0x5025, 0x5027, 0
-};
-
-static const unsigned short timedia_dual_port[] = {
-       0x0002, 0x4036, 0x4037, 0x4038, 0x4078, 0x4079, 0x4085,
-       0x4088, 0x4089, 0x5037, 0x5078, 0x5079, 0x5085, 0x6079,
-       0x7079, 0x8079, 0x8137, 0x8138, 0x8237, 0x8238, 0x9079,
-       0x9137, 0x9138, 0x9237, 0x9238, 0xA079, 0xB079, 0xC079,
-       0xD079, 0
-};
-
-static const unsigned short timedia_quad_port[] = {
-       0x4055, 0x4056, 0x4095, 0x4096, 0x5056, 0x8156, 0x8157,
-       0x8256, 0x8257, 0x9056, 0x9156, 0x9157, 0x9158, 0x9159,
-       0x9256, 0x9257, 0xA056, 0xA157, 0xA158, 0xA159, 0xB056,
-       0xB157, 0
-};
-
-static const unsigned short timedia_eight_port[] = {
-       0x4065, 0x4066, 0x5065, 0x5066, 0x8166, 0x9066, 0x9166,
-       0x9167, 0x9168, 0xA066, 0xA167, 0xA168, 0
-};
-
-static const struct timedia_struct {
-       int num;
-       const unsigned short *ids;
-} timedia_data[] = {
-       { 1, timedia_single_port },
-       { 2, timedia_dual_port },
-       { 4, timedia_quad_port },
-       { 8, timedia_eight_port }
-};
-
-static int pci_timedia_init(struct pci_dev *dev)
-{
-       const unsigned short *ids;
-       int i, j;
-
-       for (i = 0; i < ARRAY_SIZE(timedia_data); i++) {
-               ids = timedia_data[i].ids;
-               for (j = 0; ids[j]; j++)
-                       if (dev->subsystem_device == ids[j])
-                               return timedia_data[i].num;
-       }
-       return 0;
-}
-
-/*
- * Timedia/SUNIX uses a mixture of BARs and offsets
- * Ugh, this is ugly as all hell --- TYT
- */
-static int
-pci_timedia_setup(struct serial_private *priv,
-                 const struct pciserial_board *board,
-                 struct uart_port *port, int idx)
-{
-       unsigned int bar = 0, offset = board->first_offset;
-
-       switch (idx) {
-       case 0:
-               bar = 0;
-               break;
-       case 1:
-               offset = board->uart_offset;
-               bar = 0;
-               break;
-       case 2:
-               bar = 1;
-               break;
-       case 3:
-               offset = board->uart_offset;
-               /* FALLTHROUGH */
-       case 4: /* BAR 2 */
-       case 5: /* BAR 3 */
-       case 6: /* BAR 4 */
-       case 7: /* BAR 5 */
-               bar = idx - 2;
-       }
-
-       return setup_port(priv, port, bar, offset, board->reg_shift);
-}
-
-/*
- * Some Titan cards are also a little weird
- */
-static int
-titan_400l_800l_setup(struct serial_private *priv,
-                     const struct pciserial_board *board,
-                     struct uart_port *port, int idx)
-{
-       unsigned int bar, offset = board->first_offset;
-
-       switch (idx) {
-       case 0:
-               bar = 1;
-               break;
-       case 1:
-               bar = 2;
-               break;
-       default:
-               bar = 4;
-               offset = (idx - 2) * board->uart_offset;
-       }
-
-       return setup_port(priv, port, bar, offset, board->reg_shift);
-}
-
-static int pci_xircom_init(struct pci_dev *dev)
-{
-       msleep(100);
-       return 0;
-}
-
-static int pci_ni8420_init(struct pci_dev *dev)
-{
-       void __iomem *p;
-       unsigned long base, len;
-       unsigned int bar = 0;
-
-       if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) {
-               moan_device("no memory in bar", dev);
-               return 0;
-       }
-
-       base = pci_resource_start(dev, bar);
-       len =  pci_resource_len(dev, bar);
-       p = ioremap_nocache(base, len);
-       if (p == NULL)
-               return -ENOMEM;
-
-       /* Enable CPU Interrupt */
-       writel(readl(p + NI8420_INT_ENABLE_REG) | NI8420_INT_ENABLE_BIT,
-              p + NI8420_INT_ENABLE_REG);
-
-       iounmap(p);
-       return 0;
-}
-
-#define MITE_IOWBSR1_WSIZE     0xa
-#define MITE_IOWBSR1_WIN_OFFSET        0x800
-#define MITE_IOWBSR1_WENAB     (1 << 7)
-#define MITE_LCIMR1_IO_IE_0    (1 << 24)
-#define MITE_LCIMR2_SET_CPU_IE (1 << 31)
-#define MITE_IOWCR1_RAMSEL_MASK        0xfffffffe
-
-static int pci_ni8430_init(struct pci_dev *dev)
-{
-       void __iomem *p;
-       unsigned long base, len;
-       u32 device_window;
-       unsigned int bar = 0;
-
-       if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) {
-               moan_device("no memory in bar", dev);
-               return 0;
-       }
-
-       base = pci_resource_start(dev, bar);
-       len =  pci_resource_len(dev, bar);
-       p = ioremap_nocache(base, len);
-       if (p == NULL)
-               return -ENOMEM;
-
-       /* Set device window address and size in BAR0 */
-       device_window = ((base + MITE_IOWBSR1_WIN_OFFSET) & 0xffffff00)
-                       | MITE_IOWBSR1_WENAB | MITE_IOWBSR1_WSIZE;
-       writel(device_window, p + MITE_IOWBSR1);
-
-       /* Set window access to go to RAMSEL IO address space */
-       writel((readl(p + MITE_IOWCR1) & MITE_IOWCR1_RAMSEL_MASK),
-              p + MITE_IOWCR1);
-
-       /* Enable IO Bus Interrupt 0 */
-       writel(MITE_LCIMR1_IO_IE_0, p + MITE_LCIMR1);
-
-       /* Enable CPU Interrupt */
-       writel(MITE_LCIMR2_SET_CPU_IE, p + MITE_LCIMR2);
-
-       iounmap(p);
-       return 0;
-}
-
-/* UART Port Control Register */
-#define NI8430_PORTCON 0x0f
-#define NI8430_PORTCON_TXVR_ENABLE     (1 << 3)
-
-static int
-pci_ni8430_setup(struct serial_private *priv,
-                const struct pciserial_board *board,
-                struct uart_port *port, int idx)
-{
-       void __iomem *p;
-       unsigned long base, len;
-       unsigned int bar, offset = board->first_offset;
-
-       if (idx >= board->num_ports)
-               return 1;
-
-       bar = FL_GET_BASE(board->flags);
-       offset += idx * board->uart_offset;
-
-       base = pci_resource_start(priv->dev, bar);
-       len =  pci_resource_len(priv->dev, bar);
-       p = ioremap_nocache(base, len);
-
-       /* enable the transciever */
-       writeb(readb(p + offset + NI8430_PORTCON) | NI8430_PORTCON_TXVR_ENABLE,
-              p + offset + NI8430_PORTCON);
-
-       iounmap(p);
-
-       return setup_port(priv, port, bar, offset, board->reg_shift);
-}
-
-
-static int pci_netmos_init(struct pci_dev *dev)
-{
-       /* subdevice 0x00PS means <P> parallel, <S> serial */
-       unsigned int num_serial = dev->subsystem_device & 0xf;
-
-       if ((dev->device == PCI_DEVICE_ID_NETMOS_9901) ||
-               (dev->device == PCI_DEVICE_ID_NETMOS_9865))
-               return 0;
-       if (dev->subsystem_vendor == PCI_VENDOR_ID_IBM &&
-                       dev->subsystem_device == 0x0299)
-               return 0;
-
-       if (num_serial == 0)
-               return -ENODEV;
-       return num_serial;
-}
-
-/*
- * These chips are available with optionally one parallel port and up to
- * two serial ports. Unfortunately they all have the same product id.
- *
- * Basic configuration is done over a region of 32 I/O ports. The base
- * ioport is called INTA or INTC, depending on docs/other drivers.
- *
- * The region of the 32 I/O ports is configured in POSIO0R...
- */
-
-/* registers */
-#define ITE_887x_MISCR         0x9c
-#define ITE_887x_INTCBAR       0x78
-#define ITE_887x_UARTBAR       0x7c
-#define ITE_887x_PS0BAR                0x10
-#define ITE_887x_POSIO0                0x60
-
-/* I/O space size */
-#define ITE_887x_IOSIZE                32
-/* I/O space size (bits 26-24; 8 bytes = 011b) */
-#define ITE_887x_POSIO_IOSIZE_8                (3 << 24)
-/* I/O space size (bits 26-24; 32 bytes = 101b) */
-#define ITE_887x_POSIO_IOSIZE_32       (5 << 24)
-/* Decoding speed (1 = slow, 2 = medium, 3 = fast) */
-#define ITE_887x_POSIO_SPEED           (3 << 29)
-/* enable IO_Space bit */
-#define ITE_887x_POSIO_ENABLE          (1 << 31)
-
-static int pci_ite887x_init(struct pci_dev *dev)
-{
-       /* inta_addr are the configuration addresses of the ITE */
-       static const short inta_addr[] = { 0x2a0, 0x2c0, 0x220, 0x240, 0x1e0,
-                                                       0x200, 0x280, 0 };
-       int ret, i, type;
-       struct resource *iobase = NULL;
-       u32 miscr, uartbar, ioport;
-
-       /* search for the base-ioport */
-       i = 0;
-       while (inta_addr[i] && iobase == NULL) {
-               iobase = request_region(inta_addr[i], ITE_887x_IOSIZE,
-                                                               "ite887x");
-               if (iobase != NULL) {
-                       /* write POSIO0R - speed | size | ioport */
-                       pci_write_config_dword(dev, ITE_887x_POSIO0,
-                               ITE_887x_POSIO_ENABLE | ITE_887x_POSIO_SPEED |
-                               ITE_887x_POSIO_IOSIZE_32 | inta_addr[i]);
-                       /* write INTCBAR - ioport */
-                       pci_write_config_dword(dev, ITE_887x_INTCBAR,
-                                                               inta_addr[i]);
-                       ret = inb(inta_addr[i]);
-                       if (ret != 0xff) {
-                               /* ioport connected */
-                               break;
-                       }
-                       release_region(iobase->start, ITE_887x_IOSIZE);
-                       iobase = NULL;
-               }
-               i++;
-       }
-
-       if (!inta_addr[i]) {
-               printk(KERN_ERR "ite887x: could not find iobase\n");
-               return -ENODEV;
-       }
-
-       /* start of undocumented type checking (see parport_pc.c) */
-       type = inb(iobase->start + 0x18) & 0x0f;
-
-       switch (type) {
-       case 0x2:       /* ITE8871 (1P) */
-       case 0xa:       /* ITE8875 (1P) */
-               ret = 0;
-               break;
-       case 0xe:       /* ITE8872 (2S1P) */
-               ret = 2;
-               break;
-       case 0x6:       /* ITE8873 (1S) */
-               ret = 1;
-               break;
-       case 0x8:       /* ITE8874 (2S) */
-               ret = 2;
-               break;
-       default:
-               moan_device("Unknown ITE887x", dev);
-               ret = -ENODEV;
-       }
-
-       /* configure all serial ports */
-       for (i = 0; i < ret; i++) {
-               /* read the I/O port from the device */
-               pci_read_config_dword(dev, ITE_887x_PS0BAR + (0x4 * (i + 1)),
-                                                               &ioport);
-               ioport &= 0x0000FF00;   /* the actual base address */
-               pci_write_config_dword(dev, ITE_887x_POSIO0 + (0x4 * (i + 1)),
-                       ITE_887x_POSIO_ENABLE | ITE_887x_POSIO_SPEED |
-                       ITE_887x_POSIO_IOSIZE_8 | ioport);
-
-               /* write the ioport to the UARTBAR */
-               pci_read_config_dword(dev, ITE_887x_UARTBAR, &uartbar);
-               uartbar &= ~(0xffff << (16 * i));       /* clear half the reg */
-               uartbar |= (ioport << (16 * i));        /* set the ioport */
-               pci_write_config_dword(dev, ITE_887x_UARTBAR, uartbar);
-
-               /* get current config */
-               pci_read_config_dword(dev, ITE_887x_MISCR, &miscr);
-               /* disable interrupts (UARTx_Routing[3:0]) */
-               miscr &= ~(0xf << (12 - 4 * i));
-               /* activate the UART (UARTx_En) */
-               miscr |= 1 << (23 - i);
-               /* write new config with activated UART */
-               pci_write_config_dword(dev, ITE_887x_MISCR, miscr);
-       }
-
-       if (ret <= 0) {
-               /* the device has no UARTs if we get here */
-               release_region(iobase->start, ITE_887x_IOSIZE);
-       }
-
-       return ret;
-}
-
-static void __devexit pci_ite887x_exit(struct pci_dev *dev)
-{
-       u32 ioport;
-       /* the ioport is bit 0-15 in POSIO0R */
-       pci_read_config_dword(dev, ITE_887x_POSIO0, &ioport);
-       ioport &= 0xffff;
-       release_region(ioport, ITE_887x_IOSIZE);
-}
-
-/*
- * Oxford Semiconductor Inc.
- * Check that device is part of the Tornado range of devices, then determine
- * the number of ports available on the device.
- */
-static int pci_oxsemi_tornado_init(struct pci_dev *dev)
-{
-       u8 __iomem *p;
-       unsigned long deviceID;
-       unsigned int  number_uarts = 0;
-
-       /* OxSemi Tornado devices are all 0xCxxx */
-       if (dev->vendor == PCI_VENDOR_ID_OXSEMI &&
-           (dev->device & 0xF000) != 0xC000)
-               return 0;
-
-       p = pci_iomap(dev, 0, 5);
-       if (p == NULL)
-               return -ENOMEM;
-
-       deviceID = ioread32(p);
-       /* Tornado device */
-       if (deviceID == 0x07000200) {
-               number_uarts = ioread8(p + 4);
-               printk(KERN_DEBUG
-                       "%d ports detected on Oxford PCI Express device\n",
-                                                               number_uarts);
-       }
-       pci_iounmap(dev, p);
-       return number_uarts;
-}
-
-static int
-pci_default_setup(struct serial_private *priv,
-                 const struct pciserial_board *board,
-                 struct uart_port *port, int idx)
-{
-       unsigned int bar, offset = board->first_offset, maxnr;
-
-       bar = FL_GET_BASE(board->flags);
-       if (board->flags & FL_BASE_BARS)
-               bar += idx;
-       else
-               offset += idx * board->uart_offset;
-
-       maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >>
-               (board->reg_shift + 3);
-
-       if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr)
-               return 1;
-
-       return setup_port(priv, port, bar, offset, board->reg_shift);
-}
-
-static int
-ce4100_serial_setup(struct serial_private *priv,
-                 const struct pciserial_board *board,
-                 struct uart_port *port, int idx)
-{
-       int ret;
-
-       ret = setup_port(priv, port, 0, 0, board->reg_shift);
-       port->iotype = UPIO_MEM32;
-       port->type = PORT_XSCALE;
-       port->flags = (port->flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
-       port->regshift = 2;
-
-       return ret;
-}
-
-static int skip_tx_en_setup(struct serial_private *priv,
-                       const struct pciserial_board *board,
-                       struct uart_port *port, int idx)
-{
-       port->flags |= UPF_NO_TXEN_TEST;
-       printk(KERN_DEBUG "serial8250: skipping TxEn test for device "
-                         "[%04x:%04x] subsystem [%04x:%04x]\n",
-                         priv->dev->vendor,
-                         priv->dev->device,
-                         priv->dev->subsystem_vendor,
-                         priv->dev->subsystem_device);
-
-       return pci_default_setup(priv, board, port, idx);
-}
-
-/* This should be in linux/pci_ids.h */
-#define PCI_VENDOR_ID_SBSMODULARIO     0x124B
-#define PCI_SUBVENDOR_ID_SBSMODULARIO  0x124B
-#define PCI_DEVICE_ID_OCTPRO           0x0001
-#define PCI_SUBDEVICE_ID_OCTPRO232     0x0108
-#define PCI_SUBDEVICE_ID_OCTPRO422     0x0208
-#define PCI_SUBDEVICE_ID_POCTAL232     0x0308
-#define PCI_SUBDEVICE_ID_POCTAL422     0x0408
-#define PCI_VENDOR_ID_ADVANTECH                0x13fe
-#define PCI_DEVICE_ID_INTEL_CE4100_UART 0x2e66
-#define PCI_DEVICE_ID_ADVANTECH_PCI3620        0x3620
-#define PCI_DEVICE_ID_TITAN_200I       0x8028
-#define PCI_DEVICE_ID_TITAN_400I       0x8048
-#define PCI_DEVICE_ID_TITAN_800I       0x8088
-#define PCI_DEVICE_ID_TITAN_800EH      0xA007
-#define PCI_DEVICE_ID_TITAN_800EHB     0xA008
-#define PCI_DEVICE_ID_TITAN_400EH      0xA009
-#define PCI_DEVICE_ID_TITAN_100E       0xA010
-#define PCI_DEVICE_ID_TITAN_200E       0xA012
-#define PCI_DEVICE_ID_TITAN_400E       0xA013
-#define PCI_DEVICE_ID_TITAN_800E       0xA014
-#define PCI_DEVICE_ID_TITAN_200EI      0xA016
-#define PCI_DEVICE_ID_TITAN_200EISI    0xA017
-#define PCI_DEVICE_ID_OXSEMI_16PCI958  0x9538
-
-/* Unknown vendors/cards - this should not be in linux/pci_ids.h */
-#define PCI_SUBDEVICE_ID_UNKNOWN_0x1584        0x1584
-
-/*
- * Master list of serial port init/setup/exit quirks.
- * This does not describe the general nature of the port.
- * (ie, baud base, number and location of ports, etc)
- *
- * This list is ordered alphabetically by vendor then device.
- * Specific entries must come before more generic entries.
- */
-static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
-       /*
-       * ADDI-DATA GmbH communication cards <info@addi-data.com>
-       */
-       {
-               .vendor         = PCI_VENDOR_ID_ADDIDATA_OLD,
-               .device         = PCI_DEVICE_ID_ADDIDATA_APCI7800,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = addidata_apci7800_setup,
-       },
-       /*
-        * AFAVLAB cards - these may be called via parport_serial
-        *  It is not clear whether this applies to all products.
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_AFAVLAB,
-               .device         = PCI_ANY_ID,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = afavlab_setup,
-       },
-       /*
-        * HP Diva
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_HP,
-               .device         = PCI_DEVICE_ID_HP_DIVA,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_hp_diva_init,
-               .setup          = pci_hp_diva_setup,
-       },
-       /*
-        * Intel
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_INTEL,
-               .device         = PCI_DEVICE_ID_INTEL_80960_RP,
-               .subvendor      = 0xe4bf,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_inteli960ni_init,
-               .setup          = pci_default_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_INTEL,
-               .device         = PCI_DEVICE_ID_INTEL_8257X_SOL,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = skip_tx_en_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_INTEL,
-               .device         = PCI_DEVICE_ID_INTEL_82573L_SOL,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = skip_tx_en_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_INTEL,
-               .device         = PCI_DEVICE_ID_INTEL_82573E_SOL,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = skip_tx_en_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_INTEL,
-               .device         = PCI_DEVICE_ID_INTEL_CE4100_UART,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = ce4100_serial_setup,
-       },
-       /*
-        * ITE
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_ITE,
-               .device         = PCI_DEVICE_ID_ITE_8872,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ite887x_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_ite887x_exit),
-       },
-       /*
-        * National Instruments
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PCI23216,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8420_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_ni8420_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PCI2328,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8420_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_ni8420_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PCI2324,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8420_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_ni8420_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PCI2322,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8420_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_ni8420_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PCI2324I,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8420_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_ni8420_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PCI2322I,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8420_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_ni8420_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PXI8420_23216,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8420_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_ni8420_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PXI8420_2328,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8420_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_ni8420_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PXI8420_2324,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8420_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_ni8420_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PXI8420_2322,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8420_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_ni8420_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PXI8422_2324,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8420_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_ni8420_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PXI8422_2322,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8420_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_ni8420_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_ANY_ID,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8430_init,
-               .setup          = pci_ni8430_setup,
-               .exit           = __devexit_p(pci_ni8430_exit),
-       },
-       /*
-        * Panacom
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_PANACOM,
-               .device         = PCI_DEVICE_ID_PANACOM_QUADMODEM,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_plx9050_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_plx9050_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_PANACOM,
-               .device         = PCI_DEVICE_ID_PANACOM_DUALMODEM,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_plx9050_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_plx9050_exit),
-       },
-       /*
-        * PLX
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_PLX,
-               .device         = PCI_DEVICE_ID_PLX_9030,
-               .subvendor      = PCI_SUBVENDOR_ID_PERLE,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = pci_default_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_PLX,
-               .device         = PCI_DEVICE_ID_PLX_9050,
-               .subvendor      = PCI_SUBVENDOR_ID_EXSYS,
-               .subdevice      = PCI_SUBDEVICE_ID_EXSYS_4055,
-               .init           = pci_plx9050_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_plx9050_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_PLX,
-               .device         = PCI_DEVICE_ID_PLX_9050,
-               .subvendor      = PCI_SUBVENDOR_ID_KEYSPAN,
-               .subdevice      = PCI_SUBDEVICE_ID_KEYSPAN_SX2,
-               .init           = pci_plx9050_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_plx9050_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_PLX,
-               .device         = PCI_DEVICE_ID_PLX_9050,
-               .subvendor      = PCI_VENDOR_ID_PLX,
-               .subdevice      = PCI_SUBDEVICE_ID_UNKNOWN_0x1584,
-               .init           = pci_plx9050_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_plx9050_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_PLX,
-               .device         = PCI_DEVICE_ID_PLX_ROMULUS,
-               .subvendor      = PCI_VENDOR_ID_PLX,
-               .subdevice      = PCI_DEVICE_ID_PLX_ROMULUS,
-               .init           = pci_plx9050_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_plx9050_exit),
-       },
-       /*
-        * SBS Technologies, Inc., PMC-OCTALPRO 232
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_SBSMODULARIO,
-               .device         = PCI_DEVICE_ID_OCTPRO,
-               .subvendor      = PCI_SUBVENDOR_ID_SBSMODULARIO,
-               .subdevice      = PCI_SUBDEVICE_ID_OCTPRO232,
-               .init           = sbs_init,
-               .setup          = sbs_setup,
-               .exit           = __devexit_p(sbs_exit),
-       },
-       /*
-        * SBS Technologies, Inc., PMC-OCTALPRO 422
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_SBSMODULARIO,
-               .device         = PCI_DEVICE_ID_OCTPRO,
-               .subvendor      = PCI_SUBVENDOR_ID_SBSMODULARIO,
-               .subdevice      = PCI_SUBDEVICE_ID_OCTPRO422,
-               .init           = sbs_init,
-               .setup          = sbs_setup,
-               .exit           = __devexit_p(sbs_exit),
-       },
-       /*
-        * SBS Technologies, Inc., P-Octal 232
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_SBSMODULARIO,
-               .device         = PCI_DEVICE_ID_OCTPRO,
-               .subvendor      = PCI_SUBVENDOR_ID_SBSMODULARIO,
-               .subdevice      = PCI_SUBDEVICE_ID_POCTAL232,
-               .init           = sbs_init,
-               .setup          = sbs_setup,
-               .exit           = __devexit_p(sbs_exit),
-       },
-       /*
-        * SBS Technologies, Inc., P-Octal 422
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_SBSMODULARIO,
-               .device         = PCI_DEVICE_ID_OCTPRO,
-               .subvendor      = PCI_SUBVENDOR_ID_SBSMODULARIO,
-               .subdevice      = PCI_SUBDEVICE_ID_POCTAL422,
-               .init           = sbs_init,
-               .setup          = sbs_setup,
-               .exit           = __devexit_p(sbs_exit),
-       },
-       /*
-        * SIIG cards - these may be called via parport_serial
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_SIIG,
-               .device         = PCI_ANY_ID,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_siig_init,
-               .setup          = pci_siig_setup,
-       },
-       /*
-        * Titan cards
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_TITAN,
-               .device         = PCI_DEVICE_ID_TITAN_400L,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = titan_400l_800l_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_TITAN,
-               .device         = PCI_DEVICE_ID_TITAN_800L,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = titan_400l_800l_setup,
-       },
-       /*
-        * Timedia cards
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_TIMEDIA,
-               .device         = PCI_DEVICE_ID_TIMEDIA_1889,
-               .subvendor      = PCI_VENDOR_ID_TIMEDIA,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_timedia_init,
-               .setup          = pci_timedia_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_TIMEDIA,
-               .device         = PCI_ANY_ID,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = pci_timedia_setup,
-       },
-       /*
-        * Xircom cards
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_XIRCOM,
-               .device         = PCI_DEVICE_ID_XIRCOM_X3201_MDM,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_xircom_init,
-               .setup          = pci_default_setup,
-       },
-       /*
-        * Netmos cards - these may be called via parport_serial
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_NETMOS,
-               .device         = PCI_ANY_ID,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_netmos_init,
-               .setup          = pci_default_setup,
-       },
-       /*
-        * For Oxford Semiconductor and Mainpine
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_OXSEMI,
-               .device         = PCI_ANY_ID,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_oxsemi_tornado_init,
-               .setup          = pci_default_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_MAINPINE,
-               .device         = PCI_ANY_ID,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_oxsemi_tornado_init,
-               .setup          = pci_default_setup,
-       },
-       /*
-        * Default "match everything" terminator entry
-        */
-       {
-               .vendor         = PCI_ANY_ID,
-               .device         = PCI_ANY_ID,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = pci_default_setup,
-       }
-};
-
-static inline int quirk_id_matches(u32 quirk_id, u32 dev_id)
-{
-       return quirk_id == PCI_ANY_ID || quirk_id == dev_id;
-}
-
-static struct pci_serial_quirk *find_quirk(struct pci_dev *dev)
-{
-       struct pci_serial_quirk *quirk;
-
-       for (quirk = pci_serial_quirks; ; quirk++)
-               if (quirk_id_matches(quirk->vendor, dev->vendor) &&
-                   quirk_id_matches(quirk->device, dev->device) &&
-                   quirk_id_matches(quirk->subvendor, dev->subsystem_vendor) &&
-                   quirk_id_matches(quirk->subdevice, dev->subsystem_device))
-                       break;
-       return quirk;
-}
-
-static inline int get_pci_irq(struct pci_dev *dev,
-                               const struct pciserial_board *board)
-{
-       if (board->flags & FL_NOIRQ)
-               return 0;
-       else
-               return dev->irq;
-}
-
-/*
- * This is the configuration table for all of the PCI serial boards
- * which we support.  It is directly indexed by the pci_board_num_t enum
- * value, which is encoded in the pci_device_id PCI probe table's
- * driver_data member.
- *
- * The makeup of these names are:
- *  pbn_bn{_bt}_n_baud{_offsetinhex}
- *
- *  bn         = PCI BAR number
- *  bt         = Index using PCI BARs
- *  n          = number of serial ports
- *  baud       = baud rate
- *  offsetinhex        = offset for each sequential port (in hex)
- *
- * This table is sorted by (in order): bn, bt, baud, offsetindex, n.
- *
- * Please note: in theory if n = 1, _bt infix should make no difference.
- * ie, pbn_b0_1_115200 is the same as pbn_b0_bt_1_115200
- */
-enum pci_board_num_t {
-       pbn_default = 0,
-
-       pbn_b0_1_115200,
-       pbn_b0_2_115200,
-       pbn_b0_4_115200,
-       pbn_b0_5_115200,
-       pbn_b0_8_115200,
-
-       pbn_b0_1_921600,
-       pbn_b0_2_921600,
-       pbn_b0_4_921600,
-
-       pbn_b0_2_1130000,
-
-       pbn_b0_4_1152000,
-
-       pbn_b0_2_1843200,
-       pbn_b0_4_1843200,
-
-       pbn_b0_2_1843200_200,
-       pbn_b0_4_1843200_200,
-       pbn_b0_8_1843200_200,
-
-       pbn_b0_1_4000000,
-
-       pbn_b0_bt_1_115200,
-       pbn_b0_bt_2_115200,
-       pbn_b0_bt_4_115200,
-       pbn_b0_bt_8_115200,
-
-       pbn_b0_bt_1_460800,
-       pbn_b0_bt_2_460800,
-       pbn_b0_bt_4_460800,
-
-       pbn_b0_bt_1_921600,
-       pbn_b0_bt_2_921600,
-       pbn_b0_bt_4_921600,
-       pbn_b0_bt_8_921600,
-
-       pbn_b1_1_115200,
-       pbn_b1_2_115200,
-       pbn_b1_4_115200,
-       pbn_b1_8_115200,
-       pbn_b1_16_115200,
-
-       pbn_b1_1_921600,
-       pbn_b1_2_921600,
-       pbn_b1_4_921600,
-       pbn_b1_8_921600,
-
-       pbn_b1_2_1250000,
-
-       pbn_b1_bt_1_115200,
-       pbn_b1_bt_2_115200,
-       pbn_b1_bt_4_115200,
-
-       pbn_b1_bt_2_921600,
-
-       pbn_b1_1_1382400,
-       pbn_b1_2_1382400,
-       pbn_b1_4_1382400,
-       pbn_b1_8_1382400,
-
-       pbn_b2_1_115200,
-       pbn_b2_2_115200,
-       pbn_b2_4_115200,
-       pbn_b2_8_115200,
-
-       pbn_b2_1_460800,
-       pbn_b2_4_460800,
-       pbn_b2_8_460800,
-       pbn_b2_16_460800,
-
-       pbn_b2_1_921600,
-       pbn_b2_4_921600,
-       pbn_b2_8_921600,
-
-       pbn_b2_8_1152000,
-
-       pbn_b2_bt_1_115200,
-       pbn_b2_bt_2_115200,
-       pbn_b2_bt_4_115200,
-
-       pbn_b2_bt_2_921600,
-       pbn_b2_bt_4_921600,
-
-       pbn_b3_2_115200,
-       pbn_b3_4_115200,
-       pbn_b3_8_115200,
-
-       pbn_b4_bt_2_921600,
-       pbn_b4_bt_4_921600,
-       pbn_b4_bt_8_921600,
-
-       /*
-        * Board-specific versions.
-        */
-       pbn_panacom,
-       pbn_panacom2,
-       pbn_panacom4,
-       pbn_exsys_4055,
-       pbn_plx_romulus,
-       pbn_oxsemi,
-       pbn_oxsemi_1_4000000,
-       pbn_oxsemi_2_4000000,
-       pbn_oxsemi_4_4000000,
-       pbn_oxsemi_8_4000000,
-       pbn_intel_i960,
-       pbn_sgi_ioc3,
-       pbn_computone_4,
-       pbn_computone_6,
-       pbn_computone_8,
-       pbn_sbsxrsio,
-       pbn_exar_XR17C152,
-       pbn_exar_XR17C154,
-       pbn_exar_XR17C158,
-       pbn_exar_ibm_saturn,
-       pbn_pasemi_1682M,
-       pbn_ni8430_2,
-       pbn_ni8430_4,
-       pbn_ni8430_8,
-       pbn_ni8430_16,
-       pbn_ADDIDATA_PCIe_1_3906250,
-       pbn_ADDIDATA_PCIe_2_3906250,
-       pbn_ADDIDATA_PCIe_4_3906250,
-       pbn_ADDIDATA_PCIe_8_3906250,
-       pbn_ce4100_1_115200,
-};
-
-/*
- * uart_offset - the space between channels
- * reg_shift   - describes how the UART registers are mapped
- *               to PCI memory by the card.
- * For example IER register on SBS, Inc. PMC-OctPro is located at
- * offset 0x10 from the UART base, while UART_IER is defined as 1
- * in include/linux/serial_reg.h,
- * see first lines of serial_in() and serial_out() in 8250.c
-*/
-
-static struct pciserial_board pci_boards[] __devinitdata = {
-       [pbn_default] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 1,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_1_115200] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 1,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_2_115200] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 2,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_4_115200] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 4,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_5_115200] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 5,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_8_115200] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 8,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_1_921600] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 1,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_2_921600] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 2,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_4_921600] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 4,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b0_2_1130000] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 2,
-               .base_baud      = 1130000,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b0_4_1152000] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 4,
-               .base_baud      = 1152000,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b0_2_1843200] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 2,
-               .base_baud      = 1843200,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_4_1843200] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 4,
-               .base_baud      = 1843200,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b0_2_1843200_200] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 2,
-               .base_baud      = 1843200,
-               .uart_offset    = 0x200,
-       },
-       [pbn_b0_4_1843200_200] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 4,
-               .base_baud      = 1843200,
-               .uart_offset    = 0x200,
-       },
-       [pbn_b0_8_1843200_200] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 8,
-               .base_baud      = 1843200,
-               .uart_offset    = 0x200,
-       },
-       [pbn_b0_1_4000000] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 1,
-               .base_baud      = 4000000,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b0_bt_1_115200] = {
-               .flags          = FL_BASE0|FL_BASE_BARS,
-               .num_ports      = 1,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_bt_2_115200] = {
-               .flags          = FL_BASE0|FL_BASE_BARS,
-               .num_ports      = 2,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_bt_4_115200] = {
-               .flags          = FL_BASE0|FL_BASE_BARS,
-               .num_ports      = 4,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_bt_8_115200] = {
-               .flags          = FL_BASE0|FL_BASE_BARS,
-               .num_ports      = 8,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b0_bt_1_460800] = {
-               .flags          = FL_BASE0|FL_BASE_BARS,
-               .num_ports      = 1,
-               .base_baud      = 460800,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_bt_2_460800] = {
-               .flags          = FL_BASE0|FL_BASE_BARS,
-               .num_ports      = 2,
-               .base_baud      = 460800,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_bt_4_460800] = {
-               .flags          = FL_BASE0|FL_BASE_BARS,
-               .num_ports      = 4,
-               .base_baud      = 460800,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b0_bt_1_921600] = {
-               .flags          = FL_BASE0|FL_BASE_BARS,
-               .num_ports      = 1,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_bt_2_921600] = {
-               .flags          = FL_BASE0|FL_BASE_BARS,
-               .num_ports      = 2,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_bt_4_921600] = {
-               .flags          = FL_BASE0|FL_BASE_BARS,
-               .num_ports      = 4,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_bt_8_921600] = {
-               .flags          = FL_BASE0|FL_BASE_BARS,
-               .num_ports      = 8,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b1_1_115200] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 1,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b1_2_115200] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 2,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b1_4_115200] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 4,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b1_8_115200] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 8,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b1_16_115200] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 16,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b1_1_921600] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 1,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b1_2_921600] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 2,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b1_4_921600] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 4,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b1_8_921600] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 8,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b1_2_1250000] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 2,
-               .base_baud      = 1250000,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b1_bt_1_115200] = {
-               .flags          = FL_BASE1|FL_BASE_BARS,
-               .num_ports      = 1,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b1_bt_2_115200] = {
-               .flags          = FL_BASE1|FL_BASE_BARS,
-               .num_ports      = 2,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b1_bt_4_115200] = {
-               .flags          = FL_BASE1|FL_BASE_BARS,
-               .num_ports      = 4,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b1_bt_2_921600] = {
-               .flags          = FL_BASE1|FL_BASE_BARS,
-               .num_ports      = 2,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b1_1_1382400] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 1,
-               .base_baud      = 1382400,
-               .uart_offset    = 8,
-       },
-       [pbn_b1_2_1382400] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 2,
-               .base_baud      = 1382400,
-               .uart_offset    = 8,
-       },
-       [pbn_b1_4_1382400] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 4,
-               .base_baud      = 1382400,
-               .uart_offset    = 8,
-       },
-       [pbn_b1_8_1382400] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 8,
-               .base_baud      = 1382400,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b2_1_115200] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 1,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b2_2_115200] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 2,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b2_4_115200] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 4,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b2_8_115200] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 8,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b2_1_460800] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 1,
-               .base_baud      = 460800,
-               .uart_offset    = 8,
-       },
-       [pbn_b2_4_460800] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 4,
-               .base_baud      = 460800,
-               .uart_offset    = 8,
-       },
-       [pbn_b2_8_460800] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 8,
-               .base_baud      = 460800,
-               .uart_offset    = 8,
-       },
-       [pbn_b2_16_460800] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 16,
-               .base_baud      = 460800,
-               .uart_offset    = 8,
-        },
-
-       [pbn_b2_1_921600] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 1,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b2_4_921600] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 4,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b2_8_921600] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 8,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b2_8_1152000] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 8,
-               .base_baud      = 1152000,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b2_bt_1_115200] = {
-               .flags          = FL_BASE2|FL_BASE_BARS,
-               .num_ports      = 1,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b2_bt_2_115200] = {
-               .flags          = FL_BASE2|FL_BASE_BARS,
-               .num_ports      = 2,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b2_bt_4_115200] = {
-               .flags          = FL_BASE2|FL_BASE_BARS,
-               .num_ports      = 4,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b2_bt_2_921600] = {
-               .flags          = FL_BASE2|FL_BASE_BARS,
-               .num_ports      = 2,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b2_bt_4_921600] = {
-               .flags          = FL_BASE2|FL_BASE_BARS,
-               .num_ports      = 4,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b3_2_115200] = {
-               .flags          = FL_BASE3,
-               .num_ports      = 2,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b3_4_115200] = {
-               .flags          = FL_BASE3,
-               .num_ports      = 4,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b3_8_115200] = {
-               .flags          = FL_BASE3,
-               .num_ports      = 8,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b4_bt_2_921600] = {
-               .flags          = FL_BASE4,
-               .num_ports      = 2,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b4_bt_4_921600] = {
-               .flags          = FL_BASE4,
-               .num_ports      = 4,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b4_bt_8_921600] = {
-               .flags          = FL_BASE4,
-               .num_ports      = 8,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-
-       /*
-        * Entries following this are board-specific.
-        */
-
-       /*
-        * Panacom - IOMEM
-        */
-       [pbn_panacom] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 2,
-               .base_baud      = 921600,
-               .uart_offset    = 0x400,
-               .reg_shift      = 7,
-       },
-       [pbn_panacom2] = {
-               .flags          = FL_BASE2|FL_BASE_BARS,
-               .num_ports      = 2,
-               .base_baud      = 921600,
-               .uart_offset    = 0x400,
-               .reg_shift      = 7,
-       },
-       [pbn_panacom4] = {
-               .flags          = FL_BASE2|FL_BASE_BARS,
-               .num_ports      = 4,
-               .base_baud      = 921600,
-               .uart_offset    = 0x400,
-               .reg_shift      = 7,
-       },
-
-       [pbn_exsys_4055] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 4,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-
-       /* I think this entry is broken - the first_offset looks wrong --rmk */
-       [pbn_plx_romulus] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 4,
-               .base_baud      = 921600,
-               .uart_offset    = 8 << 2,
-               .reg_shift      = 2,
-               .first_offset   = 0x03,
-       },
-
-       /*
-        * This board uses the size of PCI Base region 0 to
-        * signal now many ports are available
-        */
-       [pbn_oxsemi] = {
-               .flags          = FL_BASE0|FL_REGION_SZ_CAP,
-               .num_ports      = 32,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_oxsemi_1_4000000] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 1,
-               .base_baud      = 4000000,
-               .uart_offset    = 0x200,
-               .first_offset   = 0x1000,
-       },
-       [pbn_oxsemi_2_4000000] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 2,
-               .base_baud      = 4000000,
-               .uart_offset    = 0x200,
-               .first_offset   = 0x1000,
-       },
-       [pbn_oxsemi_4_4000000] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 4,
-               .base_baud      = 4000000,
-               .uart_offset    = 0x200,
-               .first_offset   = 0x1000,
-       },
-       [pbn_oxsemi_8_4000000] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 8,
-               .base_baud      = 4000000,
-               .uart_offset    = 0x200,
-               .first_offset   = 0x1000,
-       },
-
-
-       /*
-        * EKF addition for i960 Boards form EKF with serial port.
-        * Max 256 ports.
-        */
-       [pbn_intel_i960] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 32,
-               .base_baud      = 921600,
-               .uart_offset    = 8 << 2,
-               .reg_shift      = 2,
-               .first_offset   = 0x10000,
-       },
-       [pbn_sgi_ioc3] = {
-               .flags          = FL_BASE0|FL_NOIRQ,
-               .num_ports      = 1,
-               .base_baud      = 458333,
-               .uart_offset    = 8,
-               .reg_shift      = 0,
-               .first_offset   = 0x20178,
-       },
-
-       /*
-        * Computone - uses IOMEM.
-        */
-       [pbn_computone_4] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 4,
-               .base_baud      = 921600,
-               .uart_offset    = 0x40,
-               .reg_shift      = 2,
-               .first_offset   = 0x200,
-       },
-       [pbn_computone_6] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 6,
-               .base_baud      = 921600,
-               .uart_offset    = 0x40,
-               .reg_shift      = 2,
-               .first_offset   = 0x200,
-       },
-       [pbn_computone_8] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 8,
-               .base_baud      = 921600,
-               .uart_offset    = 0x40,
-               .reg_shift      = 2,
-               .first_offset   = 0x200,
-       },
-       [pbn_sbsxrsio] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 8,
-               .base_baud      = 460800,
-               .uart_offset    = 256,
-               .reg_shift      = 4,
-       },
-       /*
-        * Exar Corp. XR17C15[248] Dual/Quad/Octal UART
-        *  Only basic 16550A support.
-        *  XR17C15[24] are not tested, but they should work.
-        */
-       [pbn_exar_XR17C152] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 2,
-               .base_baud      = 921600,
-               .uart_offset    = 0x200,
-       },
-       [pbn_exar_XR17C154] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 4,
-               .base_baud      = 921600,
-               .uart_offset    = 0x200,
-       },
-       [pbn_exar_XR17C158] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 8,
-               .base_baud      = 921600,
-               .uart_offset    = 0x200,
-       },
-       [pbn_exar_ibm_saturn] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 1,
-               .base_baud      = 921600,
-               .uart_offset    = 0x200,
-       },
-
-       /*
-        * PA Semi PWRficient PA6T-1682M on-chip UART
-        */
-       [pbn_pasemi_1682M] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 1,
-               .base_baud      = 8333333,
-       },
-       /*
-        * National Instruments 843x
-        */
-       [pbn_ni8430_16] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 16,
-               .base_baud      = 3686400,
-               .uart_offset    = 0x10,
-               .first_offset   = 0x800,
-       },
-       [pbn_ni8430_8] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 8,
-               .base_baud      = 3686400,
-               .uart_offset    = 0x10,
-               .first_offset   = 0x800,
-       },
-       [pbn_ni8430_4] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 4,
-               .base_baud      = 3686400,
-               .uart_offset    = 0x10,
-               .first_offset   = 0x800,
-       },
-       [pbn_ni8430_2] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 2,
-               .base_baud      = 3686400,
-               .uart_offset    = 0x10,
-               .first_offset   = 0x800,
-       },
-       /*
-        * ADDI-DATA GmbH PCI-Express communication cards <info@addi-data.com>
-        */
-       [pbn_ADDIDATA_PCIe_1_3906250] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 1,
-               .base_baud      = 3906250,
-               .uart_offset    = 0x200,
-               .first_offset   = 0x1000,
-       },
-       [pbn_ADDIDATA_PCIe_2_3906250] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 2,
-               .base_baud      = 3906250,
-               .uart_offset    = 0x200,
-               .first_offset   = 0x1000,
-       },
-       [pbn_ADDIDATA_PCIe_4_3906250] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 4,
-               .base_baud      = 3906250,
-               .uart_offset    = 0x200,
-               .first_offset   = 0x1000,
-       },
-       [pbn_ADDIDATA_PCIe_8_3906250] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 8,
-               .base_baud      = 3906250,
-               .uart_offset    = 0x200,
-               .first_offset   = 0x1000,
-       },
-       [pbn_ce4100_1_115200] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 1,
-               .base_baud      = 921600,
-               .reg_shift      = 2,
-       },
-};
-
-static const struct pci_device_id softmodem_blacklist[] = {
-       { PCI_VDEVICE(AL, 0x5457), }, /* ALi Corporation M5457 AC'97 Modem */
-       { PCI_VDEVICE(MOTOROLA, 0x3052), }, /* Motorola Si3052-based modem */
-       { PCI_DEVICE(0x1543, 0x3052), }, /* Si3052-based modem, default IDs */
-};
-
-/*
- * Given a complete unknown PCI device, try to use some heuristics to
- * guess what the configuration might be, based on the pitiful PCI
- * serial specs.  Returns 0 on success, 1 on failure.
- */
-static int __devinit
-serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
-{
-       const struct pci_device_id *blacklist;
-       int num_iomem, num_port, first_port = -1, i;
-
-       /*
-        * If it is not a communications device or the programming
-        * interface is greater than 6, give up.
-        *
-        * (Should we try to make guesses for multiport serial devices
-        * later?)
-        */
-       if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) &&
-            ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) ||
-           (dev->class & 0xff) > 6)
-               return -ENODEV;
-
-       /*
-        * Do not access blacklisted devices that are known not to
-        * feature serial ports.
-        */
-       for (blacklist = softmodem_blacklist;
-            blacklist < softmodem_blacklist + ARRAY_SIZE(softmodem_blacklist);
-            blacklist++) {
-               if (dev->vendor == blacklist->vendor &&
-                   dev->device == blacklist->device)
-                       return -ENODEV;
-       }
-
-       num_iomem = num_port = 0;
-       for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
-               if (pci_resource_flags(dev, i) & IORESOURCE_IO) {
-                       num_port++;
-                       if (first_port == -1)
-                               first_port = i;
-               }
-               if (pci_resource_flags(dev, i) & IORESOURCE_MEM)
-                       num_iomem++;
-       }
-
-       /*
-        * If there is 1 or 0 iomem regions, and exactly one port,
-        * use it.  We guess the number of ports based on the IO
-        * region size.
-        */
-       if (num_iomem <= 1 && num_port == 1) {
-               board->flags = first_port;
-               board->num_ports = pci_resource_len(dev, first_port) / 8;
-               return 0;
-       }
-
-       /*
-        * Now guess if we've got a board which indexes by BARs.
-        * Each IO BAR should be 8 bytes, and they should follow
-        * consecutively.
-        */
-       first_port = -1;
-       num_port = 0;
-       for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
-               if (pci_resource_flags(dev, i) & IORESOURCE_IO &&
-                   pci_resource_len(dev, i) == 8 &&
-                   (first_port == -1 || (first_port + num_port) == i)) {
-                       num_port++;
-                       if (first_port == -1)
-                               first_port = i;
-               }
-       }
-
-       if (num_port > 1) {
-               board->flags = first_port | FL_BASE_BARS;
-               board->num_ports = num_port;
-               return 0;
-       }
-
-       return -ENODEV;
-}
-
-static inline int
-serial_pci_matches(const struct pciserial_board *board,
-                  const struct pciserial_board *guessed)
-{
-       return
-           board->num_ports == guessed->num_ports &&
-           board->base_baud == guessed->base_baud &&
-           board->uart_offset == guessed->uart_offset &&
-           board->reg_shift == guessed->reg_shift &&
-           board->first_offset == guessed->first_offset;
-}
-
-struct serial_private *
-pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
-{
-       struct uart_port serial_port;
-       struct serial_private *priv;
-       struct pci_serial_quirk *quirk;
-       int rc, nr_ports, i;
-
-       nr_ports = board->num_ports;
-
-       /*
-        * Find an init and setup quirks.
-        */
-       quirk = find_quirk(dev);
-
-       /*
-        * Run the new-style initialization function.
-        * The initialization function returns:
-        *  <0  - error
-        *   0  - use board->num_ports
-        *  >0  - number of ports
-        */
-       if (quirk->init) {
-               rc = quirk->init(dev);
-               if (rc < 0) {
-                       priv = ERR_PTR(rc);
-                       goto err_out;
-               }
-               if (rc)
-                       nr_ports = rc;
-       }
-
-       priv = kzalloc(sizeof(struct serial_private) +
-                      sizeof(unsigned int) * nr_ports,
-                      GFP_KERNEL);
-       if (!priv) {
-               priv = ERR_PTR(-ENOMEM);
-               goto err_deinit;
-       }
-
-       priv->dev = dev;
-       priv->quirk = quirk;
-
-       memset(&serial_port, 0, sizeof(struct uart_port));
-       serial_port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
-       serial_port.uartclk = board->base_baud * 16;
-       serial_port.irq = get_pci_irq(dev, board);
-       serial_port.dev = &dev->dev;
-
-       for (i = 0; i < nr_ports; i++) {
-               if (quirk->setup(priv, board, &serial_port, i))
-                       break;
-
-#ifdef SERIAL_DEBUG_PCI
-               printk(KERN_DEBUG "Setup PCI port: port %lx, irq %d, type %d\n",
-                      serial_port.iobase, serial_port.irq, serial_port.iotype);
-#endif
-
-               priv->line[i] = serial8250_register_port(&serial_port);
-               if (priv->line[i] < 0) {
-                       printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), priv->line[i]);
-                       break;
-               }
-       }
-       priv->nr = i;
-       return priv;
-
-err_deinit:
-       if (quirk->exit)
-               quirk->exit(dev);
-err_out:
-       return priv;
-}
-EXPORT_SYMBOL_GPL(pciserial_init_ports);
-
-void pciserial_remove_ports(struct serial_private *priv)
-{
-       struct pci_serial_quirk *quirk;
-       int i;
-
-       for (i = 0; i < priv->nr; i++)
-               serial8250_unregister_port(priv->line[i]);
-
-       for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
-               if (priv->remapped_bar[i])
-                       iounmap(priv->remapped_bar[i]);
-               priv->remapped_bar[i] = NULL;
-       }
-
-       /*
-        * Find the exit quirks.
-        */
-       quirk = find_quirk(priv->dev);
-       if (quirk->exit)
-               quirk->exit(priv->dev);
-
-       kfree(priv);
-}
-EXPORT_SYMBOL_GPL(pciserial_remove_ports);
-
-void pciserial_suspend_ports(struct serial_private *priv)
-{
-       int i;
-
-       for (i = 0; i < priv->nr; i++)
-               if (priv->line[i] >= 0)
-                       serial8250_suspend_port(priv->line[i]);
-}
-EXPORT_SYMBOL_GPL(pciserial_suspend_ports);
-
-void pciserial_resume_ports(struct serial_private *priv)
-{
-       int i;
-
-       /*
-        * Ensure that the board is correctly configured.
-        */
-       if (priv->quirk->init)
-               priv->quirk->init(priv->dev);
-
-       for (i = 0; i < priv->nr; i++)
-               if (priv->line[i] >= 0)
-                       serial8250_resume_port(priv->line[i]);
-}
-EXPORT_SYMBOL_GPL(pciserial_resume_ports);
-
-/*
- * Probe one serial board.  Unfortunately, there is no rhyme nor reason
- * to the arrangement of serial ports on a PCI card.
- */
-static int __devinit
-pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
-{
-       struct serial_private *priv;
-       const struct pciserial_board *board;
-       struct pciserial_board tmp;
-       int rc;
-
-       if (ent->driver_data >= ARRAY_SIZE(pci_boards)) {
-               printk(KERN_ERR "pci_init_one: invalid driver_data: %ld\n",
-                       ent->driver_data);
-               return -EINVAL;
-       }
-
-       board = &pci_boards[ent->driver_data];
-
-       rc = pci_enable_device(dev);
-       if (rc)
-               return rc;
-
-       if (ent->driver_data == pbn_default) {
-               /*
-                * Use a copy of the pci_board entry for this;
-                * avoid changing entries in the table.
-                */
-               memcpy(&tmp, board, sizeof(struct pciserial_board));
-               board = &tmp;
-
-               /*
-                * We matched one of our class entries.  Try to
-                * determine the parameters of this board.
-                */
-               rc = serial_pci_guess_board(dev, &tmp);
-               if (rc)
-                       goto disable;
-       } else {
-               /*
-                * We matched an explicit entry.  If we are able to
-                * detect this boards settings with our heuristic,
-                * then we no longer need this entry.
-                */
-               memcpy(&tmp, &pci_boards[pbn_default],
-                      sizeof(struct pciserial_board));
-               rc = serial_pci_guess_board(dev, &tmp);
-               if (rc == 0 && serial_pci_matches(board, &tmp))
-                       moan_device("Redundant entry in serial pci_table.",
-                                   dev);
-       }
-
-       priv = pciserial_init_ports(dev, board);
-       if (!IS_ERR(priv)) {
-               pci_set_drvdata(dev, priv);
-               return 0;
-       }
-
-       rc = PTR_ERR(priv);
-
- disable:
-       pci_disable_device(dev);
-       return rc;
-}
-
-static void __devexit pciserial_remove_one(struct pci_dev *dev)
-{
-       struct serial_private *priv = pci_get_drvdata(dev);
-
-       pci_set_drvdata(dev, NULL);
-
-       pciserial_remove_ports(priv);
-
-       pci_disable_device(dev);
-}
-
-#ifdef CONFIG_PM
-static int pciserial_suspend_one(struct pci_dev *dev, pm_message_t state)
-{
-       struct serial_private *priv = pci_get_drvdata(dev);
-
-       if (priv)
-               pciserial_suspend_ports(priv);
-
-       pci_save_state(dev);
-       pci_set_power_state(dev, pci_choose_state(dev, state));
-       return 0;
-}
-
-static int pciserial_resume_one(struct pci_dev *dev)
-{
-       int err;
-       struct serial_private *priv = pci_get_drvdata(dev);
-
-       pci_set_power_state(dev, PCI_D0);
-       pci_restore_state(dev);
-
-       if (priv) {
-               /*
-                * The device may have been disabled.  Re-enable it.
-                */
-               err = pci_enable_device(dev);
-               /* FIXME: We cannot simply error out here */
-               if (err)
-                       printk(KERN_ERR "pciserial: Unable to re-enable ports, trying to continue.\n");
-               pciserial_resume_ports(priv);
-       }
-       return 0;
-}
-#endif
-
-static struct pci_device_id serial_pci_tbl[] = {
-       /* Advantech use PCI_DEVICE_ID_ADVANTECH_PCI3620 (0x3620) as 'PCI_SUBVENDOR_ID' */
-       {       PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620,
-               PCI_DEVICE_ID_ADVANTECH_PCI3620, 0x0001, 0, 0,
-               pbn_b2_8_921600 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
-               pbn_b1_8_1382400 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
-               pbn_b1_4_1382400 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
-               pbn_b1_2_1382400 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
-               pbn_b1_8_1382400 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
-               pbn_b1_4_1382400 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
-               pbn_b1_2_1382400 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, 0, 0,
-               pbn_b1_8_921600 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, 0, 0,
-               pbn_b1_8_921600 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, 0, 0,
-               pbn_b1_4_921600 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, 0, 0,
-               pbn_b1_4_921600 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, 0, 0,
-               pbn_b1_2_921600 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6, 0, 0,
-               pbn_b1_8_921600 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1, 0, 0,
-               pbn_b1_8_921600 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1, 0, 0,
-               pbn_b1_4_921600 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_20MHZ, 0, 0,
-               pbn_b1_2_1250000 },
-       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_2, 0, 0,
-               pbn_b0_2_1843200 },
-       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_4, 0, 0,
-               pbn_b0_4_1843200 },
-       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
-               PCI_VENDOR_ID_AFAVLAB,
-               PCI_SUBDEVICE_ID_AFAVLAB_P061, 0, 0,
-               pbn_b0_4_1152000 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_232, 0, 0,
-               pbn_b0_2_1843200_200 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_232, 0, 0,
-               pbn_b0_4_1843200_200 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_232, 0, 0,
-               pbn_b0_8_1843200_200 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_1_1, 0, 0,
-               pbn_b0_2_1843200_200 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_2, 0, 0,
-               pbn_b0_4_1843200_200 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4, 0, 0,
-               pbn_b0_8_1843200_200 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2, 0, 0,
-               pbn_b0_2_1843200_200 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4, 0, 0,
-               pbn_b0_4_1843200_200 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8, 0, 0,
-               pbn_b0_8_1843200_200 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_485, 0, 0,
-               pbn_b0_2_1843200_200 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_485, 0, 0,
-               pbn_b0_4_1843200_200 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_485, 0, 0,
-               pbn_b0_8_1843200_200 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
-               PCI_VENDOR_ID_IBM, PCI_SUBDEVICE_ID_IBM_SATURN_SERIAL_ONE_PORT,
-               0, 0, pbn_exar_ibm_saturn },
-
-       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_1_115200 },
-       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_2_115200 },
-       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_4_115200 },
-       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_2_115200 },
-       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_4_115200 },
-       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_8_115200 },
-       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_7803,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_8_460800 },
-       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM8,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_8_115200 },
-
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_2_115200 },
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_2_921600 },
-       /*
-        * VScom SPCOM800, from sl@s.pl
-        */
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_8_921600 },
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_4_921600 },
-       /* Unknown card - subdevice 0x1584 */
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-               PCI_VENDOR_ID_PLX,
-               PCI_SUBDEVICE_ID_UNKNOWN_0x1584, 0, 0,
-               pbn_b0_4_115200 },
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-               PCI_SUBVENDOR_ID_KEYSPAN,
-               PCI_SUBDEVICE_ID_KEYSPAN_SX2, 0, 0,
-               pbn_panacom },
-       {       PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_panacom4 },
-       {       PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_panacom2 },
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
-               PCI_VENDOR_ID_ESDGMBH,
-               PCI_DEVICE_ID_ESDGMBH_CPCIASIO4, 0, 0,
-               pbn_b2_4_115200 },
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-               PCI_SUBVENDOR_ID_CHASE_PCIFAST,
-               PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0,
-               pbn_b2_4_460800 },
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-               PCI_SUBVENDOR_ID_CHASE_PCIFAST,
-               PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0,
-               pbn_b2_8_460800 },
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-               PCI_SUBVENDOR_ID_CHASE_PCIFAST,
-               PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0,
-               pbn_b2_16_460800 },
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-               PCI_SUBVENDOR_ID_CHASE_PCIFAST,
-               PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0,
-               pbn_b2_16_460800 },
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-               PCI_SUBVENDOR_ID_CHASE_PCIRAS,
-               PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0,
-               pbn_b2_4_460800 },
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-               PCI_SUBVENDOR_ID_CHASE_PCIRAS,
-               PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0,
-               pbn_b2_8_460800 },
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-               PCI_SUBVENDOR_ID_EXSYS,
-               PCI_SUBDEVICE_ID_EXSYS_4055, 0, 0,
-               pbn_exsys_4055 },
-       /*
-        * Megawolf Romulus PCI Serial Card, from Mike Hudson
-        * (Exoray@isys.ca)
-        */
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS,
-               0x10b5, 0x106a, 0, 0,
-               pbn_plx_romulus },
-       {       PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_4_115200 },
-       {       PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_2_115200 },
-       {       PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_8_115200 },
-       {       PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_8_115200 },
-       {       PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954,
-               PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4,
-               0, 0,
-               pbn_b0_4_921600 },
-       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
-               PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL,
-               0, 0,
-               pbn_b0_4_1152000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0x9505,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_2_921600 },
-
-               /*
-                * The below card is a little controversial since it is the
-                * subject of a PCI vendor/device ID clash.  (See
-                * www.ussg.iu.edu/hypermail/linux/kernel/0303.1/0516.html).
-                * For now just used the hex ID 0x950a.
-                */
-       {       PCI_VENDOR_ID_OXSEMI, 0x950a,
-               PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_SERIAL, 0, 0,
-               pbn_b0_2_115200 },
-       {       PCI_VENDOR_ID_OXSEMI, 0x950a,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_2_1130000 },
-       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_C950,
-               PCI_VENDOR_ID_OXSEMI, PCI_SUBDEVICE_ID_OXSEMI_C950, 0, 0,
-               pbn_b0_1_921600 },
-       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_4_115200 },
-       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_2_921600 },
-       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI958,
-               PCI_ANY_ID , PCI_ANY_ID, 0, 0,
-               pbn_b2_8_1152000 },
-
-       /*
-        * Oxford Semiconductor Inc. Tornado PCI express device range.
-        */
-       {       PCI_VENDOR_ID_OXSEMI, 0xc101,    /* OXPCIe952 1 Legacy UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc105,    /* OXPCIe952 1 Legacy UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc11b,    /* OXPCIe952 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc11f,    /* OXPCIe952 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc120,    /* OXPCIe952 1 Legacy UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc124,    /* OXPCIe952 1 Legacy UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc138,    /* OXPCIe952 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc13d,    /* OXPCIe952 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc140,    /* OXPCIe952 1 Legacy UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc141,    /* OXPCIe952 1 Legacy UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc144,    /* OXPCIe952 1 Legacy UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc145,    /* OXPCIe952 1 Legacy UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc158,    /* OXPCIe952 2 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_2_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc15d,    /* OXPCIe952 2 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_2_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc208,    /* OXPCIe954 4 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_4_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc20d,    /* OXPCIe954 4 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_4_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc308,    /* OXPCIe958 8 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_8_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc30d,    /* OXPCIe958 8 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_8_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc40b,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc40f,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc41b,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc41f,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc42b,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc42f,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc43b,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc43f,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc44b,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc44f,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc45b,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc45f,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc46b,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc46f,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc47b,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc47f,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc48b,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc48f,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc49b,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc49f,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc4ab,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc4af,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc4bb,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc4bf,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc4cb,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc4cf,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       /*
-        * Mainpine Inc. IQ Express "Rev3" utilizing OxSemi Tornado
-        */
-       {       PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 1 Port V.34 Super-G3 Fax */
-               PCI_VENDOR_ID_MAINPINE, 0x4001, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 2 Port V.34 Super-G3 Fax */
-               PCI_VENDOR_ID_MAINPINE, 0x4002, 0, 0,
-               pbn_oxsemi_2_4000000 },
-       {       PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 4 Port V.34 Super-G3 Fax */
-               PCI_VENDOR_ID_MAINPINE, 0x4004, 0, 0,
-               pbn_oxsemi_4_4000000 },
-       {       PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 8 Port V.34 Super-G3 Fax */
-               PCI_VENDOR_ID_MAINPINE, 0x4008, 0, 0,
-               pbn_oxsemi_8_4000000 },
-       /*
-        * SBS Technologies, Inc. P-Octal and PMC-OCTPRO cards,
-        * from skokodyn@yahoo.com
-        */
-       {       PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
-               PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_OCTPRO232, 0, 0,
-               pbn_sbsxrsio },
-       {       PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
-               PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_OCTPRO422, 0, 0,
-               pbn_sbsxrsio },
-       {       PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
-               PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_POCTAL232, 0, 0,
-               pbn_sbsxrsio },
-       {       PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
-               PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_POCTAL422, 0, 0,
-               pbn_sbsxrsio },
-
-       /*
-        * Digitan DS560-558, from jimd@esoft.com
-        */
-       {       PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_1_115200 },
-
-       /*
-        * Titan Electronic cards
-        *  The 400L and 800L have a custom setup quirk.
-        */
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_2_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_4_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_4_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100L,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_1_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200L,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_bt_2_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400L,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_4_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800L,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_8_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200I,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b4_bt_2_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400I,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b4_bt_4_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800I,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b4_bt_8_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400EH,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_4_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800EH,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_4_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800EHB,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_4_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100E,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200E,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_2_4000000 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400E,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_4_4000000 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800E,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_8_4000000 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EI,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_2_4000000 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_2_4000000 },
-
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_1_460800 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_1_460800 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_1_460800 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_2_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_2_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_2_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_4_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_4_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_4_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_2_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_2_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_2_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_4_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_4_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_4_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_550,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_8_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_650,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_8_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_850,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_8_921600 },
-
-       /*
-        * Computone devices submitted by Doug McNash dmcnash@computone.com
-        */
-       {       PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
-               PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4,
-               0, 0, pbn_computone_4 },
-       {       PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
-               PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8,
-               0, 0, pbn_computone_8 },
-       {       PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
-               PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6,
-               0, 0, pbn_computone_6 },
-
-       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi },
-       {       PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889,
-               PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_1_921600 },
-
-       /*
-        * AFAVLAB serial card, from Harald Welte <laforge@gnumonks.org>
-        */
-       {       PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P028,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_8_115200 },
-       {       PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P030,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_8_115200 },
-
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_2_115200 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_2_115200 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_2_115200 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATTRO_A,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_2_115200 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATTRO_B,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_2_115200 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_A,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_4_460800 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_B,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_4_460800 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_2_460800 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_2_460800 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_2_460800 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_1_115200 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_1_460800 },
-
-       /*
-        * Korenix Jetcard F0/F1 cards (JC1204, JC1208, JC1404, JC1408).
-        * Cards are identified by their subsystem vendor IDs, which
-        * (in hex) match the model number.
-        *
-        * Note that JC140x are RS422/485 cards which require ox950
-        * ACR = 0x10, and as such are not currently fully supported.
-        */
-       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
-               0x1204, 0x0004, 0, 0,
-               pbn_b0_4_921600 },
-       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
-               0x1208, 0x0004, 0, 0,
-               pbn_b0_4_921600 },
-/*     {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
-               0x1402, 0x0002, 0, 0,
-               pbn_b0_2_921600 }, */
-/*     {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
-               0x1404, 0x0004, 0, 0,
-               pbn_b0_4_921600 }, */
-       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF1,
-               0x1208, 0x0004, 0, 0,
-               pbn_b0_4_921600 },
-
-       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF2,
-               0x1204, 0x0004, 0, 0,
-               pbn_b0_4_921600 },
-       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF2,
-               0x1208, 0x0004, 0, 0,
-               pbn_b0_4_921600 },
-       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF3,
-               0x1208, 0x0004, 0, 0,
-               pbn_b0_4_921600 },
-       /*
-        * Dell Remote Access Card 4 - Tim_T_Murphy@Dell.com
-        */
-       {       PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_RAC4,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_1_1382400 },
-
-       /*
-        * Dell Remote Access Card III - Tim_T_Murphy@Dell.com
-        */
-       {       PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_RACIII,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_1_1382400 },
-
-       /*
-        * RAStel 2 port modem, gerg@moreton.com.au
-        */
-       {       PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_2_115200 },
-
-       /*
-        * EKF addition for i960 Boards form EKF with serial port
-        */
-       {       PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80960_RP,
-               0xE4BF, PCI_ANY_ID, 0, 0,
-               pbn_intel_i960 },
-
-       /*
-        * Xircom Cardbus/Ethernet combos
-        */
-       {       PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_X3201_MDM,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_115200 },
-       /*
-        * Xircom RBM56G cardbus modem - Dirk Arnold (temp entry)
-        */
-       {       PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_RBM56G,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_115200 },
-
-       /*
-        * Untested PCI modems, sent in from various folks...
-        */
-
-       /*
-        * Elsa Model 56K PCI Modem, from Andreas Rath <arh@01019freenet.de>
-        */
-       {       PCI_VENDOR_ID_ROCKWELL, 0x1004,
-               0x1048, 0x1500, 0, 0,
-               pbn_b1_1_115200 },
-
-       {       PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
-               0xFF00, 0, 0, 0,
-               pbn_sgi_ioc3 },
-
-       /*
-        * HP Diva card
-        */
-       {       PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA,
-               PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_RMP3, 0, 0,
-               pbn_b1_1_115200 },
-       {       PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_5_115200 },
-       {       PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_AUX,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_1_115200 },
-
-       {       PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM2,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b3_2_115200 },
-       {       PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM4,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b3_4_115200 },
-       {       PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b3_8_115200 },
-
-       /*
-        * Exar Corp. XR17C15[248] Dual/Quad/Octal UART
-        */
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
-               PCI_ANY_ID, PCI_ANY_ID,
-               0,
-               0, pbn_exar_XR17C152 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154,
-               PCI_ANY_ID, PCI_ANY_ID,
-               0,
-               0, pbn_exar_XR17C154 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158,
-               PCI_ANY_ID, PCI_ANY_ID,
-               0,
-               0, pbn_exar_XR17C158 },
-
-       /*
-        * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke)
-        */
-       {       PCI_VENDOR_ID_TOPIC, PCI_DEVICE_ID_TOPIC_TP560,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_115200 },
-       /*
-        * ITE
-        */
-       {       PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8872,
-               PCI_ANY_ID, PCI_ANY_ID,
-               0, 0,
-               pbn_b1_bt_1_115200 },
-
-       /*
-        * IntaShield IS-200
-        */
-       {       PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS200,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,   /* 135a.0811 */
-               pbn_b2_2_115200 },
-       /*
-        * IntaShield IS-400
-        */
-       {       PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS400,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,    /* 135a.0dc0 */
-               pbn_b2_4_115200 },
-       /*
-        * Perle PCI-RAS cards
-        */
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
-               PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS4,
-               0, 0, pbn_b2_4_921600 },
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
-               PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS8,
-               0, 0, pbn_b2_8_921600 },
-
-       /*
-        * Mainpine series cards: Fairly standard layout but fools
-        * parts of the autodetect in some cases and uses otherwise
-        * unmatched communications subclasses in the PCI Express case
-        */
-
-       {       /* RockForceDUO */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x0200,
-               0, 0, pbn_b0_2_115200 },
-       {       /* RockForceQUATRO */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x0300,
-               0, 0, pbn_b0_4_115200 },
-       {       /* RockForceDUO+ */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x0400,
-               0, 0, pbn_b0_2_115200 },
-       {       /* RockForceQUATRO+ */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x0500,
-               0, 0, pbn_b0_4_115200 },
-       {       /* RockForce+ */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x0600,
-               0, 0, pbn_b0_2_115200 },
-       {       /* RockForce+ */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x0700,
-               0, 0, pbn_b0_4_115200 },
-       {       /* RockForceOCTO+ */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x0800,
-               0, 0, pbn_b0_8_115200 },
-       {       /* RockForceDUO+ */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x0C00,
-               0, 0, pbn_b0_2_115200 },
-       {       /* RockForceQUARTRO+ */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x0D00,
-               0, 0, pbn_b0_4_115200 },
-       {       /* RockForceOCTO+ */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x1D00,
-               0, 0, pbn_b0_8_115200 },
-       {       /* RockForceD1 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x2000,
-               0, 0, pbn_b0_1_115200 },
-       {       /* RockForceF1 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x2100,
-               0, 0, pbn_b0_1_115200 },
-       {       /* RockForceD2 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x2200,
-               0, 0, pbn_b0_2_115200 },
-       {       /* RockForceF2 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x2300,
-               0, 0, pbn_b0_2_115200 },
-       {       /* RockForceD4 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x2400,
-               0, 0, pbn_b0_4_115200 },
-       {       /* RockForceF4 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x2500,
-               0, 0, pbn_b0_4_115200 },
-       {       /* RockForceD8 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x2600,
-               0, 0, pbn_b0_8_115200 },
-       {       /* RockForceF8 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x2700,
-               0, 0, pbn_b0_8_115200 },
-       {       /* IQ Express D1 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x3000,
-               0, 0, pbn_b0_1_115200 },
-       {       /* IQ Express F1 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x3100,
-               0, 0, pbn_b0_1_115200 },
-       {       /* IQ Express D2 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x3200,
-               0, 0, pbn_b0_2_115200 },
-       {       /* IQ Express F2 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x3300,
-               0, 0, pbn_b0_2_115200 },
-       {       /* IQ Express D4 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x3400,
-               0, 0, pbn_b0_4_115200 },
-       {       /* IQ Express F4 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x3500,
-               0, 0, pbn_b0_4_115200 },
-       {       /* IQ Express D8 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x3C00,
-               0, 0, pbn_b0_8_115200 },
-       {       /* IQ Express F8 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x3D00,
-               0, 0, pbn_b0_8_115200 },
-
-
-       /*
-        * PA Semi PA6T-1682M on-chip UART
-        */
-       {       PCI_VENDOR_ID_PASEMI, 0xa004,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_pasemi_1682M },
-
-       /*
-        * National Instruments
-        */
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI23216,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_16_115200 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2328,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_8_115200 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2324,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_bt_4_115200 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2322,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_bt_2_115200 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2324I,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_bt_4_115200 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2322I,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_bt_2_115200 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_23216,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_16_115200 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2328,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_8_115200 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2324,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_bt_4_115200 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2322,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_bt_2_115200 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8422_2324,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_bt_4_115200 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8422_2322,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_bt_2_115200 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2322,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8430_2 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2322,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8430_2 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2324,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8430_4 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2324,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8430_4 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2328,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8430_8 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2328,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8430_8 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_23216,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8430_16 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_23216,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8430_16 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8432_2322,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8430_2 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8432_2322,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8430_2 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8432_2324,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8430_4 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8432_2324,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8430_4 },
-
-       /*
-       * ADDI-DATA GmbH communication cards <info@addi-data.com>
-       */
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCI7500,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_b0_4_115200 },
-
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCI7420,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_b0_2_115200 },
-
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCI7300,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_b0_1_115200 },
-
-       {       PCI_VENDOR_ID_ADDIDATA_OLD,
-               PCI_DEVICE_ID_ADDIDATA_APCI7800,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_b1_8_115200 },
-
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCI7500_2,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_b0_4_115200 },
-
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCI7420_2,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_b0_2_115200 },
-
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCI7300_2,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_b0_1_115200 },
-
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCI7500_3,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_b0_4_115200 },
-
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCI7420_3,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_b0_2_115200 },
-
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCI7300_3,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_b0_1_115200 },
-
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCI7800_3,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_b0_8_115200 },
-
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCIe7500,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_ADDIDATA_PCIe_4_3906250 },
-
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCIe7420,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_ADDIDATA_PCIe_2_3906250 },
-
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCIe7300,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_ADDIDATA_PCIe_1_3906250 },
-
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCIe7800,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_ADDIDATA_PCIe_8_3906250 },
-
-       {       PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835,
-               PCI_VENDOR_ID_IBM, 0x0299,
-               0, 0, pbn_b0_bt_2_115200 },
-
-       {       PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901,
-               0xA000, 0x1000,
-               0, 0, pbn_b0_1_115200 },
-
-       /*
-        * Best Connectivity PCI Multi I/O cards
-        */
-
-       {       PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
-               0xA000, 0x1000,
-               0, 0, pbn_b0_1_115200 },
-
-       {       PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
-               0xA000, 0x3004,
-               0, 0, pbn_b0_bt_4_115200 },
-       /* Intel CE4100 */
-       {       PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CE4100_UART,
-               PCI_ANY_ID,  PCI_ANY_ID, 0, 0,
-               pbn_ce4100_1_115200 },
-
-
-       /*
-        * These entries match devices with class COMMUNICATION_SERIAL,
-        * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
-        */
-       {       PCI_ANY_ID, PCI_ANY_ID,
-               PCI_ANY_ID, PCI_ANY_ID,
-               PCI_CLASS_COMMUNICATION_SERIAL << 8,
-               0xffff00, pbn_default },
-       {       PCI_ANY_ID, PCI_ANY_ID,
-               PCI_ANY_ID, PCI_ANY_ID,
-               PCI_CLASS_COMMUNICATION_MODEM << 8,
-               0xffff00, pbn_default },
-       {       PCI_ANY_ID, PCI_ANY_ID,
-               PCI_ANY_ID, PCI_ANY_ID,
-               PCI_CLASS_COMMUNICATION_MULTISERIAL << 8,
-               0xffff00, pbn_default },
-       { 0, }
-};
-
-static struct pci_driver serial_pci_driver = {
-       .name           = "serial",
-       .probe          = pciserial_init_one,
-       .remove         = __devexit_p(pciserial_remove_one),
-#ifdef CONFIG_PM
-       .suspend        = pciserial_suspend_one,
-       .resume         = pciserial_resume_one,
-#endif
-       .id_table       = serial_pci_tbl,
-};
-
-static int __init serial8250_pci_init(void)
-{
-       return pci_register_driver(&serial_pci_driver);
-}
-
-static void __exit serial8250_pci_exit(void)
-{
-       pci_unregister_driver(&serial_pci_driver);
-}
-
-module_init(serial8250_pci_init);
-module_exit(serial8250_pci_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Generic 8250/16x50 PCI serial probe module");
-MODULE_DEVICE_TABLE(pci, serial_pci_tbl);
diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c
deleted file mode 100644 (file)
index 4822cb5..0000000
+++ /dev/null
@@ -1,523 +0,0 @@
-/*
- *  linux/drivers/char/8250_pnp.c
- *
- *  Probe module for 8250/16550-type ISAPNP serial ports.
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *
- *  Copyright (C) 2001 Russell King, All Rights Reserved.
- *
- *  Ported to the Linux PnP Layer - (C) Adam Belay.
- *
- * 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.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/pnp.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/serial_core.h>
-#include <linux/bitops.h>
-
-#include <asm/byteorder.h>
-
-#include "8250.h"
-
-#define UNKNOWN_DEV 0x3000
-
-
-static const struct pnp_device_id pnp_dev_table[] = {
-       /* Archtek America Corp. */
-       /* Archtek SmartLink Modem 3334BT Plug & Play */
-       {       "AAC000F",              0       },
-       /* Anchor Datacomm BV */
-       /* SXPro 144 External Data Fax Modem Plug & Play */
-       {       "ADC0001",              0       },
-       /* SXPro 288 External Data Fax Modem Plug & Play */
-       {       "ADC0002",              0       },
-       /* PROLiNK 1456VH ISA PnP K56flex Fax Modem */
-       {       "AEI0250",              0       },
-       /* Actiontec ISA PNP 56K X2 Fax Modem */
-       {       "AEI1240",              0       },
-       /* Rockwell 56K ACF II Fax+Data+Voice Modem */
-       {       "AKY1021",              0 /*SPCI_FL_NO_SHIRQ*/  },
-       /* AZT3005 PnP SOUND DEVICE */
-       {       "AZT4001",              0       },
-       /* Best Data Products Inc. Smart One 336F PnP Modem */
-       {       "BDP3336",              0       },
-       /*  Boca Research */
-       /* Boca Complete Ofc Communicator 14.4 Data-FAX */
-       {       "BRI0A49",              0       },
-       /* Boca Research 33,600 ACF Modem */
-       {       "BRI1400",              0       },
-       /* Boca 33.6 Kbps Internal FD34FSVD */
-       {       "BRI3400",              0       },
-       /* Boca 33.6 Kbps Internal FD34FSVD */
-       {       "BRI0A49",              0       },
-       /* Best Data Products Inc. Smart One 336F PnP Modem */
-       {       "BDP3336",              0       },
-       /* Computer Peripherals Inc */
-       /* EuroViVa CommCenter-33.6 SP PnP */
-       {       "CPI4050",              0       },
-       /* Creative Labs */
-       /* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */
-       {       "CTL3001",              0       },
-       /* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */
-       {       "CTL3011",              0       },
-       /* Davicom ISA 33.6K Modem */
-       {       "DAV0336",              0       },
-       /* Creative */
-       /* Creative Modem Blaster Flash56 DI5601-1 */
-       {       "DMB1032",              0       },
-       /* Creative Modem Blaster V.90 DI5660 */
-       {       "DMB2001",              0       },
-       /* E-Tech */
-       /* E-Tech CyberBULLET PC56RVP */
-       {       "ETT0002",              0       },
-       /* FUJITSU */
-       /* Fujitsu 33600 PnP-I2 R Plug & Play */
-       {       "FUJ0202",              0       },
-       /* Fujitsu FMV-FX431 Plug & Play */
-       {       "FUJ0205",              0       },
-       /* Fujitsu 33600 PnP-I4 R Plug & Play */
-       {       "FUJ0206",              0       },
-       /* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */
-       {       "FUJ0209",              0       },
-       /* Archtek America Corp. */
-       /* Archtek SmartLink Modem 3334BT Plug & Play */
-       {       "GVC000F",              0       },
-       /* Archtek SmartLink Modem 3334BRV 33.6K Data Fax Voice */
-       {       "GVC0303",              0       },
-       /* Hayes */
-       /* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */
-       {       "HAY0001",              0       },
-       /* Hayes Optima 336 V.34 + FAX + Voice PnP */
-       {       "HAY000C",              0       },
-       /* Hayes Optima 336B V.34 + FAX + Voice PnP */
-       {       "HAY000D",              0       },
-       /* Hayes Accura 56K Ext Fax Modem PnP */
-       {       "HAY5670",              0       },
-       /* Hayes Accura 56K Ext Fax Modem PnP */
-       {       "HAY5674",              0       },
-       /* Hayes Accura 56K Fax Modem PnP */
-       {       "HAY5675",              0       },
-       /* Hayes 288, V.34 + FAX */
-       {       "HAYF000",              0       },
-       /* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */
-       {       "HAYF001",              0       },
-       /* IBM */
-       /* IBM Thinkpad 701 Internal Modem Voice */
-       {       "IBM0033",              0       },
-       /* Intertex */
-       /* Intertex 28k8 33k6 Voice EXT PnP */
-       {       "IXDC801",              0       },
-       /* Intertex 33k6 56k Voice EXT PnP */
-       {       "IXDC901",              0       },
-       /* Intertex 28k8 33k6 Voice SP EXT PnP */
-       {       "IXDD801",              0       },
-       /* Intertex 33k6 56k Voice SP EXT PnP */
-       {       "IXDD901",              0       },
-       /* Intertex 28k8 33k6 Voice SP INT PnP */
-       {       "IXDF401",              0       },
-       /* Intertex 28k8 33k6 Voice SP EXT PnP */
-       {       "IXDF801",              0       },
-       /* Intertex 33k6 56k Voice SP EXT PnP */
-       {       "IXDF901",              0       },
-       /* Kortex International */
-       /* KORTEX 28800 Externe PnP */
-       {       "KOR4522",              0       },
-       /* KXPro 33.6 Vocal ASVD PnP */
-       {       "KORF661",              0       },
-       /* Lasat */
-       /* LASAT Internet 33600 PnP */
-       {       "LAS4040",              0       },
-       /* Lasat Safire 560 PnP */
-       {       "LAS4540",              0       },
-       /* Lasat Safire 336  PnP */
-       {       "LAS5440",              0       },
-       /* Microcom, Inc. */
-       /* Microcom TravelPorte FAST V.34 Plug & Play */
-       {       "MNP0281",              0       },
-       /* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */
-       {       "MNP0336",              0       },
-       /* Microcom DeskPorte FAST EP 28.8 Plug & Play */
-       {       "MNP0339",              0       },
-       /* Microcom DeskPorte 28.8P Plug & Play */
-       {       "MNP0342",              0       },
-       /* Microcom DeskPorte FAST ES 28.8 Plug & Play */
-       {       "MNP0500",              0       },
-       /* Microcom DeskPorte FAST ES 28.8 Plug & Play */
-       {       "MNP0501",              0       },
-       /* Microcom DeskPorte 28.8S Internal Plug & Play */
-       {       "MNP0502",              0       },
-       /* Motorola */
-       /* Motorola BitSURFR Plug & Play */
-       {       "MOT1105",              0       },
-       /* Motorola TA210 Plug & Play */
-       {       "MOT1111",              0       },
-       /* Motorola HMTA 200 (ISDN) Plug & Play */
-       {       "MOT1114",              0       },
-       /* Motorola BitSURFR Plug & Play */
-       {       "MOT1115",              0       },
-       /* Motorola Lifestyle 28.8 Internal */
-       {       "MOT1190",              0       },
-       /* Motorola V.3400 Plug & Play */
-       {       "MOT1501",              0       },
-       /* Motorola Lifestyle 28.8 V.34 Plug & Play */
-       {       "MOT1502",              0       },
-       /* Motorola Power 28.8 V.34 Plug & Play */
-       {       "MOT1505",              0       },
-       /* Motorola ModemSURFR External 28.8 Plug & Play */
-       {       "MOT1509",              0       },
-       /* Motorola Premier 33.6 Desktop Plug & Play */
-       {       "MOT150A",              0       },
-       /* Motorola VoiceSURFR 56K External PnP */
-       {       "MOT150F",              0       },
-       /* Motorola ModemSURFR 56K External PnP */
-       {       "MOT1510",              0       },
-       /* Motorola ModemSURFR 56K Internal PnP */
-       {       "MOT1550",              0       },
-       /* Motorola ModemSURFR Internal 28.8 Plug & Play */
-       {       "MOT1560",              0       },
-       /* Motorola Premier 33.6 Internal Plug & Play */
-       {       "MOT1580",              0       },
-       /* Motorola OnlineSURFR 28.8 Internal Plug & Play */
-       {       "MOT15B0",              0       },
-       /* Motorola VoiceSURFR 56K Internal PnP */
-       {       "MOT15F0",              0       },
-       /* Com 1 */
-       /*  Deskline K56 Phone System PnP */
-       {       "MVX00A1",              0       },
-       /* PC Rider K56 Phone System PnP */
-       {       "MVX00F2",              0       },
-       /* NEC 98NOTE SPEAKER PHONE FAX MODEM(33600bps) */
-       {       "nEC8241",              0       },
-       /* Pace 56 Voice Internal Plug & Play Modem */
-       {       "PMC2430",              0       },
-       /* Generic */
-       /* Generic standard PC COM port  */
-       {       "PNP0500",              0       },
-       /* Generic 16550A-compatible COM port */
-       {       "PNP0501",              0       },
-       /* Compaq 14400 Modem */
-       {       "PNPC000",              0       },
-       /* Compaq 2400/9600 Modem */
-       {       "PNPC001",              0       },
-       /* Dial-Up Networking Serial Cable between 2 PCs */
-       {       "PNPC031",              0       },
-       /* Dial-Up Networking Parallel Cable between 2 PCs */
-       {       "PNPC032",              0       },
-       /* Standard 9600 bps Modem */
-       {       "PNPC100",              0       },
-       /* Standard 14400 bps Modem */
-       {       "PNPC101",              0       },
-       /*  Standard 28800 bps Modem*/
-       {       "PNPC102",              0       },
-       /*  Standard Modem*/
-       {       "PNPC103",              0       },
-       /*  Standard 9600 bps Modem*/
-       {       "PNPC104",              0       },
-       /*  Standard 14400 bps Modem*/
-       {       "PNPC105",              0       },
-       /*  Standard 28800 bps Modem*/
-       {       "PNPC106",              0       },
-       /*  Standard Modem */
-       {       "PNPC107",              0       },
-       /* Standard 9600 bps Modem */
-       {       "PNPC108",              0       },
-       /* Standard 14400 bps Modem */
-       {       "PNPC109",              0       },
-       /* Standard 28800 bps Modem */
-       {       "PNPC10A",              0       },
-       /* Standard Modem */
-       {       "PNPC10B",              0       },
-       /* Standard 9600 bps Modem */
-       {       "PNPC10C",              0       },
-       /* Standard 14400 bps Modem */
-       {       "PNPC10D",              0       },
-       /* Standard 28800 bps Modem */
-       {       "PNPC10E",              0       },
-       /* Standard Modem */
-       {       "PNPC10F",              0       },
-       /* Standard PCMCIA Card Modem */
-       {       "PNP2000",              0       },
-       /* Rockwell */
-       /* Modular Technology */
-       /* Rockwell 33.6 DPF Internal PnP */
-       /* Modular Technology 33.6 Internal PnP */
-       {       "ROK0030",              0       },
-       /* Kortex International */
-       /* KORTEX 14400 Externe PnP */
-       {       "ROK0100",              0       },
-       /* Rockwell 28.8 */
-       {       "ROK4120",              0       },
-       /* Viking Components, Inc */
-       /* Viking 28.8 INTERNAL Fax+Data+Voice PnP */
-       {       "ROK4920",              0       },
-       /* Rockwell */
-       /* British Telecom */
-       /* Modular Technology */
-       /* Rockwell 33.6 DPF External PnP */
-       /* BT Prologue 33.6 External PnP */
-       /* Modular Technology 33.6 External PnP */
-       {       "RSS00A0",              0       },
-       /* Viking 56K FAX INT */
-       {       "RSS0262",              0       },
-       /* K56 par,VV,Voice,Speakphone,AudioSpan,PnP */
-       {       "RSS0250",              0       },
-       /* SupraExpress 28.8 Data/Fax PnP modem */
-       {       "SUP1310",              0       },
-       /* SupraExpress 336i PnP Voice Modem */
-       {       "SUP1381",              0       },
-       /* SupraExpress 33.6 Data/Fax PnP modem */
-       {       "SUP1421",              0       },
-       /* SupraExpress 33.6 Data/Fax PnP modem */
-       {       "SUP1590",              0       },
-       /* SupraExpress 336i Sp ASVD */
-       {       "SUP1620",              0       },
-       /* SupraExpress 33.6 Data/Fax PnP modem */
-       {       "SUP1760",              0       },
-       /* SupraExpress 56i Sp Intl */
-       {       "SUP2171",              0       },
-       /* Phoebe Micro */
-       /* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */
-       {       "TEX0011",              0       },
-       /* Archtek America Corp. */
-       /* Archtek SmartLink Modem 3334BT Plug & Play */
-       {       "UAC000F",              0       },
-       /* 3Com Corp. */
-       /* Gateway Telepath IIvi 33.6 */
-       {       "USR0000",              0       },
-       /* U.S. Robotics Sporster 33.6K Fax INT PnP */
-       {       "USR0002",              0       },
-       /*  Sportster Vi 14.4 PnP FAX Voicemail */
-       {       "USR0004",              0       },
-       /* U.S. Robotics 33.6K Voice INT PnP */
-       {       "USR0006",              0       },
-       /* U.S. Robotics 33.6K Voice EXT PnP */
-       {       "USR0007",              0       },
-       /* U.S. Robotics Courier V.Everything INT PnP */
-       {       "USR0009",              0       },
-       /* U.S. Robotics 33.6K Voice INT PnP */
-       {       "USR2002",              0       },
-       /* U.S. Robotics 56K Voice INT PnP */
-       {       "USR2070",              0       },
-       /* U.S. Robotics 56K Voice EXT PnP */
-       {       "USR2080",              0       },
-       /* U.S. Robotics 56K FAX INT */
-       {       "USR3031",              0       },
-       /* U.S. Robotics 56K FAX INT */
-       {       "USR3050",              0       },
-       /* U.S. Robotics 56K Voice INT PnP */
-       {       "USR3070",              0       },
-       /* U.S. Robotics 56K Voice EXT PnP */
-       {       "USR3080",              0       },
-       /* U.S. Robotics 56K Voice INT PnP */
-       {       "USR3090",              0       },
-       /* U.S. Robotics 56K Message  */
-       {       "USR9100",              0       },
-       /* U.S. Robotics 56K FAX EXT PnP*/
-       {       "USR9160",              0       },
-       /* U.S. Robotics 56K FAX INT PnP*/
-       {       "USR9170",              0       },
-       /* U.S. Robotics 56K Voice EXT PnP*/
-       {       "USR9180",              0       },
-       /* U.S. Robotics 56K Voice INT PnP*/
-       {       "USR9190",              0       },
-       /* Wacom tablets */
-       {       "WACFXXX",              0       },
-       /* Compaq touchscreen */
-       {       "FPI2002",              0 },
-       /* Fujitsu Stylistic touchscreens */
-       {       "FUJ02B2",              0 },
-       {       "FUJ02B3",              0 },
-       /* Fujitsu Stylistic LT touchscreens */
-       {       "FUJ02B4",              0 },
-       /* Passive Fujitsu Stylistic touchscreens */
-       {       "FUJ02B6",              0 },
-       {       "FUJ02B7",              0 },
-       {       "FUJ02B8",              0 },
-       {       "FUJ02B9",              0 },
-       {       "FUJ02BC",              0 },
-       /* Fujitsu Wacom Tablet PC device */
-       {       "FUJ02E5",              0       },
-       /* Fujitsu P-series tablet PC device */
-       {       "FUJ02E6",              0       },
-       /* Fujitsu Wacom 2FGT Tablet PC device */
-       {       "FUJ02E7",              0       },
-       /* Fujitsu Wacom 1FGT Tablet PC device */
-       {       "FUJ02E9",              0       },
-       /*
-        * LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6 in
-        * disguise)
-        */
-       {       "LTS0001",              0       },
-       /* Rockwell's (PORALiNK) 33600 INT PNP */
-       {       "WCI0003",              0       },
-       /* Unknown PnP modems */
-       {       "PNPCXXX",              UNKNOWN_DEV     },
-       /* More unknown PnP modems */
-       {       "PNPDXXX",              UNKNOWN_DEV     },
-       {       "",                     0       }
-};
-
-MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
-
-static char *modem_names[] __devinitdata = {
-       "MODEM", "Modem", "modem", "FAX", "Fax", "fax",
-       "56K", "56k", "K56", "33.6", "28.8", "14.4",
-       "33,600", "28,800", "14,400", "33.600", "28.800", "14.400",
-       "33600", "28800", "14400", "V.90", "V.34", "V.32", NULL
-};
-
-static int __devinit check_name(char *name)
-{
-       char **tmp;
-
-       for (tmp = modem_names; *tmp; tmp++)
-               if (strstr(name, *tmp))
-                       return 1;
-
-       return 0;
-}
-
-static int __devinit check_resources(struct pnp_dev *dev)
-{
-       resource_size_t base[] = {0x2f8, 0x3f8, 0x2e8, 0x3e8};
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(base); i++) {
-               if (pnp_possible_config(dev, IORESOURCE_IO, base[i], 8))
-                       return 1;
-       }
-
-       return 0;
-}
-
-/*
- * Given a complete unknown PnP device, try to use some heuristics to
- * detect modems. Currently use such heuristic set:
- *     - dev->name or dev->bus->name must contain "modem" substring;
- *     - device must have only one IO region (8 byte long) with base address
- *       0x2e8, 0x3e8, 0x2f8 or 0x3f8.
- *
- * Such detection looks very ugly, but can detect at least some of numerous
- * PnP modems, alternatively we must hardcode all modems in pnp_devices[]
- * table.
- */
-static int __devinit serial_pnp_guess_board(struct pnp_dev *dev, int *flags)
-{
-       if (!(check_name(pnp_dev_name(dev)) ||
-               (dev->card && check_name(dev->card->name))))
-                       return -ENODEV;
-
-       if (check_resources(dev))
-               return 0;
-
-       return -ENODEV;
-}
-
-static int __devinit
-serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
-{
-       struct uart_port port;
-       int ret, line, flags = dev_id->driver_data;
-
-       if (flags & UNKNOWN_DEV) {
-               ret = serial_pnp_guess_board(dev, &flags);
-               if (ret < 0)
-                       return ret;
-       }
-
-       memset(&port, 0, sizeof(struct uart_port));
-       if (pnp_irq_valid(dev, 0))
-               port.irq = pnp_irq(dev, 0);
-       if (pnp_port_valid(dev, 0)) {
-               port.iobase = pnp_port_start(dev, 0);
-               port.iotype = UPIO_PORT;
-       } else if (pnp_mem_valid(dev, 0)) {
-               port.mapbase = pnp_mem_start(dev, 0);
-               port.iotype = UPIO_MEM;
-               port.flags = UPF_IOREMAP;
-       } else
-               return -ENODEV;
-
-#ifdef SERIAL_DEBUG_PNP
-       printk(KERN_DEBUG
-               "Setup PNP port: port %x, mem 0x%lx, irq %d, type %d\n",
-                      port.iobase, port.mapbase, port.irq, port.iotype);
-#endif
-
-       port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
-       if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE)
-               port.flags |= UPF_SHARE_IRQ;
-       port.uartclk = 1843200;
-       port.dev = &dev->dev;
-
-       line = serial8250_register_port(&port);
-       if (line < 0)
-               return -ENODEV;
-
-       pnp_set_drvdata(dev, (void *)((long)line + 1));
-       return 0;
-}
-
-static void __devexit serial_pnp_remove(struct pnp_dev *dev)
-{
-       long line = (long)pnp_get_drvdata(dev);
-       if (line)
-               serial8250_unregister_port(line - 1);
-}
-
-#ifdef CONFIG_PM
-static int serial_pnp_suspend(struct pnp_dev *dev, pm_message_t state)
-{
-       long line = (long)pnp_get_drvdata(dev);
-
-       if (!line)
-               return -ENODEV;
-       serial8250_suspend_port(line - 1);
-       return 0;
-}
-
-static int serial_pnp_resume(struct pnp_dev *dev)
-{
-       long line = (long)pnp_get_drvdata(dev);
-
-       if (!line)
-               return -ENODEV;
-       serial8250_resume_port(line - 1);
-       return 0;
-}
-#else
-#define serial_pnp_suspend NULL
-#define serial_pnp_resume NULL
-#endif /* CONFIG_PM */
-
-static struct pnp_driver serial_pnp_driver = {
-       .name           = "serial",
-       .probe          = serial_pnp_probe,
-       .remove         = __devexit_p(serial_pnp_remove),
-       .suspend        = serial_pnp_suspend,
-       .resume         = serial_pnp_resume,
-       .id_table       = pnp_dev_table,
-};
-
-static int __init serial8250_pnp_init(void)
-{
-       return pnp_register_driver(&serial_pnp_driver);
-}
-
-static void __exit serial8250_pnp_exit(void)
-{
-       pnp_unregister_driver(&serial_pnp_driver);
-}
-
-module_init(serial8250_pnp_init);
-module_exit(serial8250_pnp_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Generic 8250/16x50 PnP serial driver");
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
deleted file mode 100644 (file)
index c1df767..0000000
+++ /dev/null
@@ -1,1598 +0,0 @@
-#
-# Serial device configuration
-#
-
-menu "Serial drivers"
-       depends on HAS_IOMEM
-
-#
-# The new 8250/16550 serial drivers
-config SERIAL_8250
-       tristate "8250/16550 and compatible serial support"
-       select SERIAL_CORE
-       ---help---
-         This selects whether you want to include the driver for the standard
-         serial ports.  The standard answer is Y.  People who might say N
-         here are those that are setting up dedicated Ethernet WWW/FTP
-         servers, or users that have one of the various bus mice instead of a
-         serial mouse and don't intend to use their machine's standard serial
-         port for anything.  (Note that the Cyclades and Stallion multi
-         serial port drivers do not need this driver built in for them to
-         work.)
-
-         To compile this driver as a module, choose M here: the
-         module will be called 8250.
-         [WARNING: Do not compile this driver as a module if you are using
-         non-standard serial ports, since the configuration information will
-         be lost when the driver is unloaded.  This limitation may be lifted
-         in the future.]
-
-         BTW1: If you have a mouseman serial mouse which is not recognized by
-         the X window system, try running gpm first.
-
-         BTW2: If you intend to use a software modem (also called Winmodem)
-         under Linux, forget it.  These modems are crippled and require
-         proprietary drivers which are only available under Windows.
-
-         Most people will say Y or M here, so that they can use serial mice,
-         modems and similar devices connecting to the standard serial ports.
-
-config SERIAL_8250_CONSOLE
-       bool "Console on 8250/16550 and compatible serial port"
-       depends on SERIAL_8250=y
-       select SERIAL_CORE_CONSOLE
-       ---help---
-         If you say Y here, it will be possible to use a serial port as the
-         system console (the system console is the device which receives all
-         kernel messages and warnings and which allows logins in single user
-         mode). This could be useful if some terminal or printer is connected
-         to that serial port.
-
-         Even if you say Y here, the currently visible virtual console
-         (/dev/tty0) will still be used as the system console by default, but
-         you can alter that using a kernel command line option such as
-         "console=ttyS1". (Try "man bootparam" or see the documentation of
-         your boot loader (grub or lilo or loadlin) about how to pass options
-         to the kernel at boot time.)
-
-         If you don't have a VGA card installed and you say Y here, the
-         kernel will automatically use the first serial line, /dev/ttyS0, as
-         system console.
-
-         You can set that using a kernel command line option such as
-         "console=uart8250,io,0x3f8,9600n8"
-         "console=uart8250,mmio,0xff5e0000,115200n8".
-         and it will switch to normal serial console when the corresponding 
-         port is ready.
-         "earlycon=uart8250,io,0x3f8,9600n8"
-         "earlycon=uart8250,mmio,0xff5e0000,115200n8".
-         it will not only setup early console.
-
-         If unsure, say N.
-
-config FIX_EARLYCON_MEM
-       bool
-       depends on X86
-       default y
-
-config SERIAL_8250_GSC
-       tristate
-       depends on SERIAL_8250 && GSC
-       default SERIAL_8250
-
-config SERIAL_8250_PCI
-       tristate "8250/16550 PCI device support" if EMBEDDED
-       depends on SERIAL_8250 && PCI
-       default SERIAL_8250
-       help
-         This builds standard PCI serial support. You may be able to
-         disable this feature if you only need legacy serial support.
-         Saves about 9K.
-
-config SERIAL_8250_PNP
-       tristate "8250/16550 PNP device support" if EMBEDDED
-       depends on SERIAL_8250 && PNP
-       default SERIAL_8250
-       help
-         This builds standard PNP serial support. You may be able to
-         disable this feature if you only need legacy serial support.
-
-config SERIAL_8250_HP300
-       tristate
-       depends on SERIAL_8250 && HP300
-       default SERIAL_8250
-
-config SERIAL_8250_CS
-       tristate "8250/16550 PCMCIA device support"
-       depends on PCMCIA && SERIAL_8250
-       ---help---
-         Say Y here to enable support for 16-bit PCMCIA serial devices,
-         including serial port cards, modems, and the modem functions of
-         multi-function Ethernet/modem cards. (PCMCIA- or PC-cards are
-         credit-card size devices often used with laptops.)
-
-         To compile this driver as a module, choose M here: the
-         module will be called serial_cs.
-
-         If unsure, say N.
-
-config SERIAL_8250_NR_UARTS
-       int "Maximum number of 8250/16550 serial ports"
-       depends on SERIAL_8250
-       default "4"
-       help
-         Set this to the number of serial ports you want the driver
-         to support.  This includes any ports discovered via ACPI or
-         PCI enumeration and any ports that may be added at run-time
-         via hot-plug, or any ISA multi-port serial cards.
-
-config SERIAL_8250_RUNTIME_UARTS
-       int "Number of 8250/16550 serial ports to register at runtime"
-       depends on SERIAL_8250
-       range 0 SERIAL_8250_NR_UARTS
-       default "4"
-       help
-         Set this to the maximum number of serial ports you want
-         the kernel to register at boot time.  This can be overridden
-         with the module parameter "nr_uarts", or boot-time parameter
-         8250.nr_uarts
-
-config SERIAL_8250_EXTENDED
-       bool "Extended 8250/16550 serial driver options"
-       depends on SERIAL_8250
-       help
-         If you wish to use any non-standard features of the standard "dumb"
-         driver, say Y here. This includes HUB6 support, shared serial
-         interrupts, special multiport support, support for more than the
-         four COM 1/2/3/4 boards, etc.
-
-         Note that the answer to this question won't directly affect the
-         kernel: saying N will just cause the configurator to skip all
-         the questions about serial driver options. If unsure, say N.
-
-config SERIAL_8250_MANY_PORTS
-       bool "Support more than 4 legacy serial ports"
-       depends on SERIAL_8250_EXTENDED && !IA64
-       help
-         Say Y here if you have dumb serial boards other than the four
-         standard COM 1/2/3/4 ports. This may happen if you have an AST
-         FourPort, Accent Async, Boca (read the Boca mini-HOWTO, available
-         from <http://www.tldp.org/docs.html#howto>), or other custom
-         serial port hardware which acts similar to standard serial port
-         hardware. If you only use the standard COM 1/2/3/4 ports, you can
-         say N here to save some memory. You can also say Y if you have an
-         "intelligent" multiport card such as Cyclades, Digiboards, etc.
-
-#
-# Multi-port serial cards
-#
-
-config SERIAL_8250_FOURPORT
-       tristate "Support Fourport cards"
-       depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
-       help
-         Say Y here if you have an AST FourPort serial board.
-
-         To compile this driver as a module, choose M here: the module
-         will be called 8250_fourport.
-
-config SERIAL_8250_ACCENT
-       tristate "Support Accent cards"
-       depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
-       help
-         Say Y here if you have an Accent Async serial board.
-
-         To compile this driver as a module, choose M here: the module
-         will be called 8250_accent.
-
-config SERIAL_8250_BOCA
-       tristate "Support Boca cards"
-       depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
-       help
-         Say Y here if you have a Boca serial board.  Please read the Boca
-         mini-HOWTO, available from <http://www.tldp.org/docs.html#howto>
-
-         To compile this driver as a module, choose M here: the module
-         will be called 8250_boca.
-
-config SERIAL_8250_EXAR_ST16C554
-       tristate "Support Exar ST16C554/554D Quad UART"
-       depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
-       help
-         The Uplogix Envoy TU301 uses this Exar Quad UART.  If you are
-         tinkering with your Envoy TU301, or have a machine with this UART,
-         say Y here.
-
-         To compile this driver as a module, choose M here: the module
-         will be called 8250_exar_st16c554.
-
-config SERIAL_8250_HUB6
-       tristate "Support Hub6 cards"
-       depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
-       help
-         Say Y here if you have a HUB6 serial board.
-
-         To compile this driver as a module, choose M here: the module
-         will be called 8250_hub6.
-
-config SERIAL_8250_SHARE_IRQ
-       bool "Support for sharing serial interrupts"
-       depends on SERIAL_8250_EXTENDED
-       help
-         Some serial boards have hardware support which allows multiple dumb
-         serial ports on the same board to share a single IRQ. To enable
-         support for this in the serial driver, say Y here.
-
-config SERIAL_8250_DETECT_IRQ
-       bool "Autodetect IRQ on standard ports (unsafe)"
-       depends on SERIAL_8250_EXTENDED
-       help
-         Say Y here if you want the kernel to try to guess which IRQ
-         to use for your serial port.
-
-         This is considered unsafe; it is far better to configure the IRQ in
-         a boot script using the setserial command.
-
-         If unsure, say N.
-
-config SERIAL_8250_RSA
-       bool "Support RSA serial ports"
-       depends on SERIAL_8250_EXTENDED
-       help
-         ::: To be written :::
-
-config SERIAL_8250_MCA
-       tristate "Support 8250-type ports on MCA buses"
-       depends on SERIAL_8250 != n && MCA
-       help
-         Say Y here if you have a MCA serial ports.
-
-         To compile this driver as a module, choose M here: the module
-         will be called 8250_mca.
-
-config SERIAL_8250_ACORN
-       tristate "Acorn expansion card serial port support"
-       depends on ARCH_ACORN && SERIAL_8250
-       help
-         If you have an Atomwide Serial card or Serial Port card for an Acorn
-         system, say Y to this option.  The driver can handle 1, 2, or 3 port
-         cards.  If unsure, say N.
-
-config SERIAL_8250_RM9K
-       bool "Support for MIPS RM9xxx integrated serial port"
-       depends on SERIAL_8250 != n && SERIAL_RM9000
-       select SERIAL_8250_SHARE_IRQ
-       help
-         Selecting this option will add support for the integrated serial
-         port hardware found on MIPS RM9122 and similar processors.
-         If unsure, say N.
-
-comment "Non-8250 serial port support"
-
-config SERIAL_AMBA_PL010
-       tristate "ARM AMBA PL010 serial port support"
-       depends on ARM_AMBA && (BROKEN || !ARCH_VERSATILE)
-       select SERIAL_CORE
-       help
-         This selects the ARM(R) AMBA(R) PrimeCell PL010 UART.  If you have
-         an Integrator/AP or Integrator/PP2 platform, or if you have a
-         Cirrus Logic EP93xx CPU, say Y or M here.
-
-         If unsure, say N.
-
-config SERIAL_AMBA_PL010_CONSOLE
-       bool "Support for console on AMBA serial port"
-       depends on SERIAL_AMBA_PL010=y
-       select SERIAL_CORE_CONSOLE
-       ---help---
-         Say Y here if you wish to use an AMBA PrimeCell UART as the system
-         console (the system console is the device which receives all kernel
-         messages and warnings and which allows logins in single user mode).
-
-         Even if you say Y here, the currently visible framebuffer console
-         (/dev/tty0) will still be used as the system console by default, but
-         you can alter that using a kernel command line option such as
-         "console=ttyAM0". (Try "man bootparam" or see the documentation of
-         your boot loader (lilo or loadlin) about how to pass options to the
-         kernel at boot time.)
-
-config SERIAL_AMBA_PL011
-       tristate "ARM AMBA PL011 serial port support"
-       depends on ARM_AMBA
-       select SERIAL_CORE
-       help
-         This selects the ARM(R) AMBA(R) PrimeCell PL011 UART.  If you have
-         an Integrator/PP2, Integrator/CP or Versatile platform, say Y or M
-         here.
-
-         If unsure, say N.
-
-config SERIAL_AMBA_PL011_CONSOLE
-       bool "Support for console on AMBA serial port"
-       depends on SERIAL_AMBA_PL011=y
-       select SERIAL_CORE_CONSOLE
-       ---help---
-         Say Y here if you wish to use an AMBA PrimeCell UART as the system
-         console (the system console is the device which receives all kernel
-         messages and warnings and which allows logins in single user mode).
-
-         Even if you say Y here, the currently visible framebuffer console
-         (/dev/tty0) will still be used as the system console by default, but
-         you can alter that using a kernel command line option such as
-         "console=ttyAMA0". (Try "man bootparam" or see the documentation of
-         your boot loader (lilo or loadlin) about how to pass options to the
-         kernel at boot time.)
-
-config SERIAL_SB1250_DUART
-       tristate "BCM1xxx on-chip DUART serial support"
-       depends on SIBYTE_SB1xxx_SOC=y
-       select SERIAL_CORE
-       default y
-       ---help---
-         Support for the asynchronous serial interface (DUART) included in
-         the BCM1250 and derived System-On-a-Chip (SOC) devices.  Note that
-         the letter D in DUART stands for "dual", which is how the device
-         is implemented.  Depending on the SOC configuration there may be
-         one or more DUARTs available of which all are handled.
-
-         If unsure, say Y.  To compile this driver as a module, choose M here:
-         the module will be called sb1250-duart.
-
-config SERIAL_SB1250_DUART_CONSOLE
-       bool "Support for console on a BCM1xxx DUART serial port"
-       depends on SERIAL_SB1250_DUART=y
-       select SERIAL_CORE_CONSOLE
-       default y
-       ---help---
-         If you say Y here, it will be possible to use a serial port as the
-         system console (the system console is the device which receives all
-         kernel messages and warnings and which allows logins in single user
-         mode).
-
-         If unsure, say Y.
-
-config SERIAL_ATMEL
-       bool "AT91 / AT32 on-chip serial port support"
-       depends on (ARM && ARCH_AT91) || AVR32
-       select SERIAL_CORE
-       help
-         This enables the driver for the on-chip UARTs of the Atmel
-         AT91 and AT32 processors.
-
-config SERIAL_ATMEL_CONSOLE
-       bool "Support for console on AT91 / AT32 serial port"
-       depends on SERIAL_ATMEL=y
-       select SERIAL_CORE_CONSOLE
-       help
-         Say Y here if you wish to use an on-chip UART on a Atmel
-         AT91 or AT32 processor as the system console (the system
-         console is the device which receives all kernel messages and
-         warnings and which allows logins in single user mode).
-
-config SERIAL_ATMEL_PDC
-       bool "Support DMA transfers on AT91 / AT32 serial port"
-       depends on SERIAL_ATMEL
-       default y
-       help
-         Say Y here if you wish to use the PDC to do DMA transfers to
-         and from the Atmel AT91 / AT32 serial port. In order to
-         actually use DMA transfers, make sure that the use_dma_tx
-         and use_dma_rx members in the atmel_uart_data struct is set
-         appropriately for each port.
-
-         Note that break and error handling currently doesn't work
-         properly when DMA is enabled. Make sure that ports where
-         this matters don't use DMA.
-
-config SERIAL_ATMEL_TTYAT
-       bool "Install as device ttyATn instead of ttySn"
-       depends on SERIAL_ATMEL=y
-       help
-         Say Y here if you wish to have the internal AT91 / AT32 UARTs
-         appear as /dev/ttyATn (major 204, minor starting at 154)
-         instead of the normal /dev/ttySn (major 4, minor starting at
-         64). This is necessary if you also want other UARTs, such as
-         external 8250/16C550 compatible UARTs.
-         The ttySn nodes are legally reserved for the 8250 serial driver
-         but are often misused by other serial drivers.
-
-         To use this, you should create suitable ttyATn device nodes in
-         /dev/, and pass "console=ttyATn" to the kernel.
-
-         Say Y if you have an external 8250/16C550 UART.  If unsure, say N.
-
-config SERIAL_KS8695
-       bool "Micrel KS8695 (Centaur) serial port support"
-       depends on ARCH_KS8695
-       select SERIAL_CORE
-       help
-         This selects the Micrel Centaur KS8695 UART.  Say Y here.
-
-config SERIAL_KS8695_CONSOLE
-       bool "Support for console on KS8695 (Centaur) serial port"
-       depends on SERIAL_KS8695=y
-       select SERIAL_CORE_CONSOLE
-       help
-         Say Y here if you wish to use a KS8695 (Centaur) UART as the
-         system console (the system console is the device which
-         receives all kernel messages and warnings and which allows
-         logins in single user mode).
-
-config SERIAL_CLPS711X
-       tristate "CLPS711X serial port support"
-       depends on ARM && ARCH_CLPS711X
-       select SERIAL_CORE
-       help
-         ::: To be written :::
-
-config SERIAL_CLPS711X_CONSOLE
-       bool "Support for console on CLPS711X serial port"
-       depends on SERIAL_CLPS711X=y
-       select SERIAL_CORE_CONSOLE
-       help
-         Even if you say Y here, the currently visible virtual console
-         (/dev/tty0) will still be used as the system console by default, but
-         you can alter that using a kernel command line option such as
-         "console=ttyCL1". (Try "man bootparam" or see the documentation of
-         your boot loader (lilo or loadlin) about how to pass options to the
-         kernel at boot time.)
-
-config SERIAL_SAMSUNG
-       tristate "Samsung SoC serial support"
-       depends on ARM && PLAT_SAMSUNG
-       select SERIAL_CORE
-       help
-         Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,
-         providing /dev/ttySAC0, 1 and 2 (note, some machines may not
-         provide all of these ports, depending on how the serial port
-         pins are configured.
-
-config SERIAL_SAMSUNG_UARTS_4
-       bool
-       depends on ARM && PLAT_SAMSUNG
-       default y if CPU_S3C2443
-       help
-         Internal node for the common case of 4 Samsung compatible UARTs
-
-config SERIAL_SAMSUNG_UARTS
-       int
-       depends on ARM && PLAT_SAMSUNG
-       default 2 if ARCH_S3C2400
-       default 6 if ARCH_S5P6450
-       default 4 if SERIAL_SAMSUNG_UARTS_4
-       default 3
-       help
-         Select the number of available UART ports for the Samsung S3C
-         serial driver
-       
-config SERIAL_SAMSUNG_DEBUG
-       bool "Samsung SoC serial debug"
-       depends on SERIAL_SAMSUNG && DEBUG_LL
-       help
-         Add support for debugging the serial driver. Since this is
-         generally being used as a console, we use our own output
-         routines that go via the low-level debug printascii()
-         function.
-
-config SERIAL_SAMSUNG_CONSOLE
-       bool "Support for console on Samsung SoC serial port"
-       depends on SERIAL_SAMSUNG=y
-       select SERIAL_CORE_CONSOLE
-       help
-         Allow selection of the S3C24XX on-board serial ports for use as
-         an virtual console.
-
-         Even if you say Y here, the currently visible virtual console
-         (/dev/tty0) will still be used as the system console by default, but
-         you can alter that using a kernel command line option such as
-         "console=ttySACx". (Try "man bootparam" or see the documentation of
-         your boot loader about how to pass options to the kernel at
-         boot time.)
-
-config SERIAL_S3C2400
-       tristate "Samsung S3C2410 Serial port support"
-       depends on ARM && SERIAL_SAMSUNG && CPU_S3C2400
-       default y if CPU_S3C2400
-       help
-         Serial port support for the Samsung S3C2400 SoC
-
-config SERIAL_S3C2410
-       tristate "Samsung S3C2410 Serial port support"
-       depends on SERIAL_SAMSUNG && CPU_S3C2410
-       default y if CPU_S3C2410
-       help
-         Serial port support for the Samsung S3C2410 SoC
-
-config SERIAL_S3C2412
-       tristate "Samsung S3C2412/S3C2413 Serial port support"
-       depends on SERIAL_SAMSUNG && CPU_S3C2412
-       default y if CPU_S3C2412
-       help
-         Serial port support for the Samsung S3C2412 and S3C2413 SoC
-
-config SERIAL_S3C2440
-       tristate "Samsung S3C2440/S3C2442/S3C2416 Serial port support"
-       depends on SERIAL_SAMSUNG && (CPU_S3C2440 || CPU_S3C2442 || CPU_S3C2416)
-       default y if CPU_S3C2440
-       default y if CPU_S3C2442
-       select SERIAL_SAMSUNG_UARTS_4 if CPU_S3C2416
-       help
-         Serial port support for the Samsung S3C2440, S3C2416 and S3C2442 SoC
-
-config SERIAL_S3C24A0
-       tristate "Samsung S3C24A0 Serial port support"
-       depends on SERIAL_SAMSUNG && CPU_S3C24A0
-       default y if CPU_S3C24A0
-       help
-         Serial port support for the Samsung S3C24A0 SoC
-
-config SERIAL_S3C6400
-       tristate "Samsung S3C6400/S3C6410/S5P6440/S5P6450/S5PC100 Serial port support"
-       depends on SERIAL_SAMSUNG && (CPU_S3C6400 || CPU_S3C6410 || CPU_S5P6440 || CPU_S5P6450 || CPU_S5PC100)
-       select SERIAL_SAMSUNG_UARTS_4
-       default y
-       help
-         Serial port support for the Samsung S3C6400, S3C6410, S5P6440, S5P6450
-         and S5PC100 SoCs
-
-config SERIAL_S5PV210
-       tristate "Samsung S5PV210 Serial port support"
-       depends on SERIAL_SAMSUNG && (CPU_S5PV210 || CPU_S5P6442 || CPU_S5PV310)
-       select SERIAL_SAMSUNG_UARTS_4 if (CPU_S5PV210 || CPU_S5PV310)
-       default y
-       help
-         Serial port support for Samsung's S5P Family of SoC's
-
-
-config SERIAL_MAX3100
-       tristate "MAX3100 support"
-       depends on SPI
-       select SERIAL_CORE
-       help
-         MAX3100 chip support
-
-config SERIAL_MAX3107
-       tristate "MAX3107 support"
-       depends on SPI
-       select SERIAL_CORE
-       help
-         MAX3107 chip support
-
-config SERIAL_MAX3107_AAVA
-       tristate "MAX3107 AAVA platform support"
-       depends on X86_MRST && SERIAL_MAX3107 && GPIOLIB
-       select SERIAL_CORE
-       help
-         Support for the MAX3107 chip configuration found on the AAVA
-         platform. Includes the extra initialisation and GPIO support
-         neded for this device.
-
-config SERIAL_DZ
-       bool "DECstation DZ serial driver"
-       depends on MACH_DECSTATION && 32BIT
-       select SERIAL_CORE
-       default y
-       ---help---
-         DZ11-family serial controllers for DECstations and VAXstations,
-         including the DC7085, M7814, and M7819.
-
-config SERIAL_DZ_CONSOLE
-       bool "Support console on DECstation DZ serial driver"
-       depends on SERIAL_DZ=y
-       select SERIAL_CORE_CONSOLE
-       default y
-       ---help---
-         If you say Y here, it will be possible to use a serial port as the
-         system console (the system console is the device which receives all
-         kernel messages and warnings and which allows logins in single user
-         mode).
-
-         Note that the firmware uses ttyS3 as the serial console on
-         DECstations that use this driver.
-
-         If unsure, say Y.
-
-config SERIAL_ZS
-       tristate "DECstation Z85C30 serial support"
-       depends on MACH_DECSTATION
-       select SERIAL_CORE
-       default y
-       ---help---
-         Support for the Zilog 85C350 serial communications controller used
-         for serial ports in newer DECstation systems.  These include the
-         DECsystem 5900 and all models of the DECstation and DECsystem 5000
-         systems except from model 200.
-
-         If unsure, say Y.  To compile this driver as a module, choose M here:
-         the module will be called zs.
-
-config SERIAL_ZS_CONSOLE
-       bool "Support for console on a DECstation Z85C30 serial port"
-       depends on SERIAL_ZS=y
-       select SERIAL_CORE_CONSOLE
-       default y
-       ---help---
-         If you say Y here, it will be possible to use a serial port as the
-         system console (the system console is the device which receives all
-         kernel messages and warnings and which allows logins in single user
-         mode).
-
-         Note that the firmware uses ttyS1 as the serial console on the
-         Maxine and ttyS3 on the others using this driver.
-
-         If unsure, say Y.
-
-config SERIAL_21285
-       tristate "DC21285 serial port support"
-       depends on ARM && FOOTBRIDGE
-       select SERIAL_CORE
-       help
-         If you have a machine based on a 21285 (Footbridge) StrongARM(R)/
-         PCI bridge you can enable its onboard serial port by enabling this
-         option.
-
-config SERIAL_21285_CONSOLE
-       bool "Console on DC21285 serial port"
-       depends on SERIAL_21285=y
-       select SERIAL_CORE_CONSOLE
-       help
-         If you have enabled the serial port on the 21285 footbridge you can
-         make it the console by answering Y to this option.
-
-         Even if you say Y here, the currently visible virtual console
-         (/dev/tty0) will still be used as the system console by default, but
-         you can alter that using a kernel command line option such as
-         "console=ttyFB". (Try "man bootparam" or see the documentation of
-         your boot loader (lilo or loadlin) about how to pass options to the
-         kernel at boot time.)
-
-config SERIAL_MPSC
-       bool "Marvell MPSC serial port support"
-       depends on PPC32 && MV64X60
-       select SERIAL_CORE
-       help
-         Say Y here if you want to use the Marvell MPSC serial controller.
-
-config SERIAL_MPSC_CONSOLE
-       bool "Support for console on Marvell MPSC serial port"
-       depends on SERIAL_MPSC
-       select SERIAL_CORE_CONSOLE
-       help
-         Say Y here if you want to support a serial console on a Marvell MPSC.
-
-config SERIAL_PXA
-       bool "PXA serial port support"
-       depends on ARCH_PXA || ARCH_MMP
-       select SERIAL_CORE
-       help
-         If you have a machine based on an Intel XScale PXA2xx CPU you
-         can enable its onboard serial ports by enabling this option.
-
-config SERIAL_PXA_CONSOLE
-       bool "Console on PXA serial port"
-       depends on SERIAL_PXA
-       select SERIAL_CORE_CONSOLE
-       help
-         If you have enabled the serial port on the Intel XScale PXA
-         CPU you can make it the console by answering Y to this option.
-
-         Even if you say Y here, the currently visible virtual console
-         (/dev/tty0) will still be used as the system console by default, but
-         you can alter that using a kernel command line option such as
-         "console=ttySA0". (Try "man bootparam" or see the documentation of
-         your boot loader (lilo or loadlin) about how to pass options to the
-         kernel at boot time.)
-
-config SERIAL_SA1100
-       bool "SA1100 serial port support"
-       depends on ARM && ARCH_SA1100
-       select SERIAL_CORE
-       help
-         If you have a machine based on a SA1100/SA1110 StrongARM(R) CPU you
-         can enable its onboard serial port by enabling this option.
-         Please read <file:Documentation/arm/SA1100/serial_UART> for further
-         info.
-
-config SERIAL_SA1100_CONSOLE
-       bool "Console on SA1100 serial port"
-       depends on SERIAL_SA1100
-       select SERIAL_CORE_CONSOLE
-       help
-         If you have enabled the serial port on the SA1100/SA1110 StrongARM
-         CPU you can make it the console by answering Y to this option.
-
-         Even if you say Y here, the currently visible virtual console
-         (/dev/tty0) will still be used as the system console by default, but
-         you can alter that using a kernel command line option such as
-         "console=ttySA0". (Try "man bootparam" or see the documentation of
-         your boot loader (lilo or loadlin) about how to pass options to the
-         kernel at boot time.)
-
-config SERIAL_MRST_MAX3110
-       tristate "SPI UART driver for Max3110"
-       depends on SPI_DW_PCI
-       select SERIAL_CORE
-       select SERIAL_CORE_CONSOLE
-       help
-         This is the UART protocol driver for the MAX3110 device on
-         the Intel Moorestown platform. On other systems use the max3100
-         driver.
-
-config SERIAL_MFD_HSU
-       tristate "Medfield High Speed UART support"
-       depends on PCI
-       select SERIAL_CORE
-
-config SERIAL_MFD_HSU_CONSOLE
-       boolean "Medfile HSU serial console support"
-       depends on SERIAL_MFD_HSU=y
-       select SERIAL_CORE_CONSOLE
-
-config SERIAL_BFIN
-       tristate "Blackfin serial port support"
-       depends on BLACKFIN
-       select SERIAL_CORE
-       select SERIAL_BFIN_UART0 if (BF531 || BF532 || BF533 || BF561)
-       help
-         Add support for the built-in UARTs on the Blackfin.
-
-         To compile this driver as a module, choose M here: the
-         module will be called bfin_5xx.
-
-config SERIAL_BFIN_CONSOLE
-       bool "Console on Blackfin serial port"
-       depends on SERIAL_BFIN=y
-       select SERIAL_CORE_CONSOLE
-
-choice
-       prompt "UART Mode"
-       depends on SERIAL_BFIN
-       default SERIAL_BFIN_DMA
-       help
-         This driver supports the built-in serial ports of the Blackfin family
-         of CPUs
-
-config SERIAL_BFIN_DMA
-       bool "DMA mode"
-       depends on !DMA_UNCACHED_NONE && KGDB_SERIAL_CONSOLE=n
-       help
-         This driver works under DMA mode. If this option is selected, the
-         blackfin simple dma driver is also enabled.
-
-config SERIAL_BFIN_PIO
-       bool "PIO mode"
-       help
-         This driver works under PIO mode.
-
-endchoice
-
-config SERIAL_BFIN_UART0
-       bool "Enable UART0"
-       depends on SERIAL_BFIN
-       help
-         Enable UART0
-
-config BFIN_UART0_CTSRTS
-       bool "Enable UART0 hardware flow control"
-       depends on SERIAL_BFIN_UART0
-       help
-         Enable hardware flow control in the driver.
-
-config SERIAL_BFIN_UART1
-       bool "Enable UART1"
-       depends on SERIAL_BFIN && (!BF531 && !BF532 && !BF533 && !BF561)
-       help
-         Enable UART1
-
-config BFIN_UART1_CTSRTS
-       bool "Enable UART1 hardware flow control"
-       depends on SERIAL_BFIN_UART1
-       help
-         Enable hardware flow control in the driver.
-
-config SERIAL_BFIN_UART2
-       bool "Enable UART2"
-       depends on SERIAL_BFIN && (BF54x || BF538 || BF539)
-       help
-         Enable UART2
-
-config BFIN_UART2_CTSRTS
-       bool "Enable UART2 hardware flow control"
-       depends on SERIAL_BFIN_UART2
-       help
-         Enable hardware flow control in the driver.
-
-config SERIAL_BFIN_UART3
-       bool "Enable UART3"
-       depends on SERIAL_BFIN && (BF54x)
-       help
-         Enable UART3
-
-config BFIN_UART3_CTSRTS
-       bool "Enable UART3 hardware flow control"
-       depends on SERIAL_BFIN_UART3
-       help
-         Enable hardware flow control in the driver.
-
-config SERIAL_IMX
-       bool "IMX serial port support"
-       depends on ARM && (ARCH_IMX || ARCH_MXC)
-       select SERIAL_CORE
-       select RATIONAL
-       help
-         If you have a machine based on a Motorola IMX CPU you
-         can enable its onboard serial port by enabling this option.
-
-config SERIAL_IMX_CONSOLE
-       bool "Console on IMX serial port"
-       depends on SERIAL_IMX
-       select SERIAL_CORE_CONSOLE
-       help
-         If you have enabled the serial port on the Motorola IMX
-         CPU you can make it the console by answering Y to this option.
-
-         Even if you say Y here, the currently visible virtual console
-         (/dev/tty0) will still be used as the system console by default, but
-         you can alter that using a kernel command line option such as
-         "console=ttySA0". (Try "man bootparam" or see the documentation of
-         your boot loader (lilo or loadlin) about how to pass options to the
-         kernel at boot time.)
-
-config SERIAL_UARTLITE
-       tristate "Xilinx uartlite serial port support"
-       depends on PPC32 || MICROBLAZE || MFD_TIMBERDALE
-       select SERIAL_CORE
-       help
-         Say Y here if you want to use the Xilinx uartlite serial controller.
-
-         To compile this driver as a module, choose M here: the
-         module will be called uartlite.
-
-config SERIAL_UARTLITE_CONSOLE
-       bool "Support for console on Xilinx uartlite serial port"
-       depends on SERIAL_UARTLITE=y
-       select SERIAL_CORE_CONSOLE
-       help
-         Say Y here if you wish to use a Xilinx uartlite as the system
-         console (the system console is the device which receives all kernel
-         messages and warnings and which allows logins in single user mode).
-
-config SERIAL_SUNCORE
-       bool
-       depends on SPARC
-       select SERIAL_CORE
-       select SERIAL_CORE_CONSOLE
-       default y
-
-config SERIAL_SUNZILOG
-       tristate "Sun Zilog8530 serial support"
-       depends on SPARC
-       help
-         This driver supports the Zilog8530 serial ports found on many Sparc
-         systems.  Say Y or M if you want to be able to these serial ports.
-
-config SERIAL_SUNZILOG_CONSOLE
-       bool "Console on Sun Zilog8530 serial port"
-       depends on SERIAL_SUNZILOG=y
-       help
-         If you would like to be able to use the Zilog8530 serial port
-         on your Sparc system as the console, you can do so by answering
-         Y to this option.
-
-config SERIAL_SUNSU
-       tristate "Sun SU serial support"
-       depends on SPARC && PCI
-       help
-         This driver supports the 8250 serial ports that run the keyboard and
-         mouse on (PCI) UltraSPARC systems.  Say Y or M if you want to be able
-         to these serial ports.
-
-config SERIAL_SUNSU_CONSOLE
-       bool "Console on Sun SU serial port"
-       depends on SERIAL_SUNSU=y
-       help
-         If you would like to be able to use the SU serial port
-         on your Sparc system as the console, you can do so by answering
-         Y to this option.
-
-config SERIAL_MUX
-       tristate "Serial MUX support"
-       depends on GSC
-       select SERIAL_CORE
-       default y
-       ---help---
-         Saying Y here will enable the hardware MUX serial driver for
-         the Nova, K class systems and D class with a 'remote control card'.
-         The hardware MUX is not 8250/16550 compatible therefore the
-         /dev/ttyB0 device is shared between the Serial MUX and the PDC
-         software console. The following steps need to be completed to use
-         the Serial MUX:
-
-           1. create the device entry (mknod /dev/ttyB0 c 11 0)
-           2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0
-           3. Add device ttyB0 to /etc/securetty (if you want to log on as
-                root on this console.)
-           4. Change the kernel command console parameter to: console=ttyB0
-
-config SERIAL_MUX_CONSOLE
-       bool "Support for console on serial MUX"
-       depends on SERIAL_MUX=y
-       select SERIAL_CORE_CONSOLE
-       default y
-
-config PDC_CONSOLE
-       bool "PDC software console support"
-       depends on PARISC && !SERIAL_MUX && VT
-       default n
-       help
-         Saying Y here will enable the software based PDC console to be 
-         used as the system console.  This is useful for machines in 
-         which the hardware based console has not been written yet.  The
-         following steps must be competed to use the PDC console:
-
-           1. create the device entry (mknod /dev/ttyB0 c 11 0)
-           2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0
-           3. Add device ttyB0 to /etc/securetty (if you want to log on as
-                root on this console.)
-           4. Change the kernel command console parameter to: console=ttyB0
-
-config SERIAL_SUNSAB
-       tristate "Sun Siemens SAB82532 serial support"
-       depends on SPARC && PCI
-       help
-         This driver supports the Siemens SAB82532 DUSCC serial ports on newer
-         (PCI) UltraSPARC systems.  Say Y or M if you want to be able to these
-         serial ports.
-
-config SERIAL_SUNSAB_CONSOLE
-       bool "Console on Sun Siemens SAB82532 serial port"
-       depends on SERIAL_SUNSAB=y
-       help
-         If you would like to be able to use the SAB82532 serial port
-         on your Sparc system as the console, you can do so by answering
-         Y to this option.
-
-config SERIAL_SUNHV
-       bool "Sun4v Hypervisor Console support"
-       depends on SPARC64
-       help
-         This driver supports the console device found on SUN4V Sparc
-         systems.  Say Y if you want to be able to use this device.
-
-config SERIAL_IP22_ZILOG
-       tristate "SGI Zilog8530 serial support"
-       depends on SGI_HAS_ZILOG
-       select SERIAL_CORE
-       help
-         This driver supports the Zilog8530 serial ports found on SGI
-         systems.  Say Y or M if you want to be able to these serial ports.
-
-config SERIAL_IP22_ZILOG_CONSOLE
-       bool "Console on SGI Zilog8530 serial port"
-       depends on SERIAL_IP22_ZILOG=y
-       select SERIAL_CORE_CONSOLE
-
-config SERIAL_SH_SCI
-       tristate "SuperH SCI(F) serial port support"
-       depends on HAVE_CLK && (SUPERH || H8300 || ARCH_SHMOBILE)
-       select SERIAL_CORE
-
-config SERIAL_SH_SCI_NR_UARTS
-       int "Maximum number of SCI(F) serial ports"
-       depends on SERIAL_SH_SCI
-       default "2"
-
-config SERIAL_SH_SCI_CONSOLE
-       bool "Support for console on SuperH SCI(F)"
-       depends on SERIAL_SH_SCI=y
-       select SERIAL_CORE_CONSOLE
-
-config SERIAL_SH_SCI_DMA
-       bool "DMA support"
-       depends on SERIAL_SH_SCI && SH_DMAE && EXPERIMENTAL
-
-config SERIAL_PNX8XXX
-       bool "Enable PNX8XXX SoCs' UART Support"
-       depends on MIPS && (SOC_PNX8550 || SOC_PNX833X)
-       select SERIAL_CORE
-       help
-         If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330
-         and you want to use serial ports, say Y.  Otherwise, say N.
-
-config SERIAL_PNX8XXX_CONSOLE
-       bool "Enable PNX8XX0 serial console"
-       depends on SERIAL_PNX8XXX
-       select SERIAL_CORE_CONSOLE
-       help
-         If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330
-         and you want to use serial console, say Y. Otherwise, say N.
-
-config SERIAL_CORE
-       tristate
-
-config SERIAL_CORE_CONSOLE
-       bool
-
-config CONSOLE_POLL
-       bool
-
-config SERIAL_68328
-       bool "68328 serial support"
-       depends on M68328 || M68EZ328 || M68VZ328
-       help
-         This driver supports the built-in serial port of the Motorola 68328
-         (standard, EZ and VZ varieties).
-
-config SERIAL_68328_RTS_CTS
-       bool "Support RTS/CTS on 68328 serial port"
-       depends on SERIAL_68328
-
-config SERIAL_MCF
-       bool "Coldfire serial support"
-       depends on COLDFIRE
-       select SERIAL_CORE
-       help
-         This serial driver supports the Freescale Coldfire serial ports.
-
-config SERIAL_MCF_BAUDRATE
-       int "Default baudrate for Coldfire serial ports"
-       depends on SERIAL_MCF
-       default 19200
-       help
-         This setting lets you define what the default baudrate is for the
-         ColdFire serial ports. The usual default varies from board to board,
-         and this setting is a way of catering for that.
-
-config SERIAL_MCF_CONSOLE
-       bool "Coldfire serial console support"
-       depends on SERIAL_MCF
-       select SERIAL_CORE_CONSOLE
-       help
-         Enable a ColdFire internal serial port to be the system console.
-
-config SERIAL_68360_SMC
-       bool "68360 SMC uart support"
-       depends on M68360
-       help
-         This driver supports the SMC serial ports of the Motorola 68360 CPU.
-
-config SERIAL_68360_SCC
-       bool "68360 SCC uart support"
-       depends on M68360
-       help
-         This driver supports the SCC serial ports of the Motorola 68360 CPU.
-
-config SERIAL_68360
-       bool
-       depends on SERIAL_68360_SMC || SERIAL_68360_SCC
-       default y
-
-config SERIAL_PMACZILOG
-       tristate "Mac or PowerMac z85c30 ESCC support"
-       depends on (M68K && MAC) || (PPC_OF && PPC_PMAC)
-       select SERIAL_CORE
-       help
-         This driver supports the Zilog z85C30 serial ports found on
-         (Power)Mac machines.
-         Say Y or M if you want to be able to these serial ports.
-
-config SERIAL_PMACZILOG_TTYS
-       bool "Use ttySn device nodes for Zilog z85c30"
-       depends on SERIAL_PMACZILOG
-       help
-         The pmac_zilog driver for the z85C30 chip on many powermacs
-         historically used the device numbers for /dev/ttySn.  The
-         8250 serial port driver also uses these numbers, which means
-         the two drivers being unable to coexist; you could not use
-         both z85C30 and 8250 type ports at the same time.
-
-         If this option is not selected, the pmac_zilog driver will
-         use the device numbers allocated for /dev/ttyPZn.  This allows
-         the pmac_zilog and 8250 drivers to co-exist, but may cause
-         existing userspace setups to break.  Programs that need to
-         access the built-in serial ports on powermacs will need to
-         be reconfigured to use /dev/ttyPZn instead of /dev/ttySn.
-
-         If you enable this option, any z85c30 ports in the system will
-         be registered as ttyS0 onwards as in the past, and you will be
-         unable to use the 8250 module for PCMCIA or other 16C550-style
-         UARTs.
-
-         Say N unless you need the z85c30 ports on your (Power)Mac
-         to appear as /dev/ttySn.
-
-config SERIAL_PMACZILOG_CONSOLE
-       bool "Console on Mac or PowerMac z85c30 serial port"
-       depends on SERIAL_PMACZILOG=y
-       select SERIAL_CORE_CONSOLE
-       help
-         If you would like to be able to use the z85c30 serial port
-         on your (Power)Mac as the console, you can do so by answering
-         Y to this option.
-
-config SERIAL_LH7A40X
-       tristate "Sharp LH7A40X embedded UART support"
-       depends on ARM && ARCH_LH7A40X
-       select SERIAL_CORE
-       help
-         This enables support for the three on-board UARTs of the
-         Sharp LH7A40X series CPUs.  Choose Y or M.
-
-config SERIAL_LH7A40X_CONSOLE
-       bool "Support for console on Sharp LH7A40X serial port"
-       depends on SERIAL_LH7A40X=y
-       select SERIAL_CORE_CONSOLE
-       help
-         Say Y here if you wish to use one of the serial ports as the
-         system console--the system console is the device which
-         receives all kernel messages and warnings and which allows
-         logins in single user mode.
-
-         Even if you say Y here, the currently visible framebuffer console
-         (/dev/tty0) will still be used as the default system console, but
-         you can alter that using a kernel command line, for example
-         "console=ttyAM1".
-
-config SERIAL_CPM
-       tristate "CPM SCC/SMC serial port support"
-       depends on CPM2 || 8xx
-       select SERIAL_CORE
-       help
-         This driver supports the SCC and SMC serial ports on Motorola 
-         embedded PowerPC that contain a CPM1 (8xx) or CPM2 (8xxx)
-
-config SERIAL_CPM_CONSOLE
-       bool "Support for console on CPM SCC/SMC serial port"
-       depends on SERIAL_CPM=y
-       select SERIAL_CORE_CONSOLE
-       help
-         Say Y here if you wish to use a SCC or SMC CPM UART as the system
-         console (the system console is the device which receives all kernel
-         messages and warnings and which allows logins in single user mode).
-
-         Even if you say Y here, the currently visible framebuffer console
-         (/dev/tty0) will still be used as the system console by default, but
-         you can alter that using a kernel command line option such as
-         "console=ttyCPM0". (Try "man bootparam" or see the documentation of
-         your boot loader (lilo or loadlin) about how to pass options to the
-         kernel at boot time.)
-
-config SERIAL_SGI_L1_CONSOLE
-       bool "SGI Altix L1 serial console support"
-       depends on IA64_GENERIC || IA64_SGI_SN2
-       select SERIAL_CORE
-       select SERIAL_CORE_CONSOLE
-       help
-               If you have an SGI Altix and you would like to use the system
-               controller serial port as your console (you want this!),
-               say Y.  Otherwise, say N.
-
-config SERIAL_MPC52xx
-       tristate "Freescale MPC52xx/MPC512x family PSC serial support"
-       depends on PPC_MPC52xx || PPC_MPC512x
-       select SERIAL_CORE
-       help
-         This driver supports MPC52xx and MPC512x PSC serial ports. If you would
-         like to use them, you must answer Y or M to this option. Note that
-         for use as console, it must be included in kernel and not as a
-         module.
-
-config SERIAL_MPC52xx_CONSOLE
-       bool "Console on a Freescale MPC52xx/MPC512x family PSC serial port"
-       depends on SERIAL_MPC52xx=y
-       select SERIAL_CORE_CONSOLE
-       help
-         Select this options if you'd like to use one of the PSC serial port
-         of the Freescale MPC52xx family as a console.
-
-config SERIAL_MPC52xx_CONSOLE_BAUD
-       int "Freescale MPC52xx/MPC512x family PSC serial port baud"
-       depends on SERIAL_MPC52xx_CONSOLE=y
-       default "9600"
-       help
-         Select the MPC52xx console baud rate.
-         This value is only used if the bootloader doesn't pass in the
-         console baudrate
-
-config SERIAL_ICOM
-       tristate "IBM Multiport Serial Adapter"
-       depends on PCI && (PPC_ISERIES || PPC_PSERIES)
-       select SERIAL_CORE
-       select FW_LOADER
-       help
-         This driver is for a family of multiport serial adapters
-         including 2 port RVX, 2 port internal modem, 4 port internal
-         modem and a split 1 port RVX and 1 port internal modem.
-
-         This driver can also be built as a module.  If so, the module
-         will be called icom.
-
-config SERIAL_M32R_SIO
-       bool "M32R SIO I/F"
-       depends on M32R
-       default y
-       select SERIAL_CORE
-       help
-         Say Y here if you want to use the M32R serial controller.
-
-config SERIAL_M32R_SIO_CONSOLE
-       bool "use SIO console"
-       depends on SERIAL_M32R_SIO=y
-       select SERIAL_CORE_CONSOLE
-       help
-         Say Y here if you want to support a serial console.
-
-         If you use an M3T-M32700UT or an OPSPUT platform,
-         please say also y for SERIAL_M32R_PLDSIO.
-
-config SERIAL_M32R_PLDSIO
-       bool "M32R SIO I/F on a PLD"
-       depends on SERIAL_M32R_SIO=y && (PLAT_OPSPUT || PLAT_USRV || PLAT_M32700UT)
-       default n
-       help
-         Say Y here if you want to use the M32R serial controller
-         on a PLD (Programmable Logic Device).
-
-         If you use an M3T-M32700UT or an OPSPUT platform,
-         please say Y.
-
-config SERIAL_TXX9
-       bool "TMPTX39XX/49XX SIO support"
-       depends on HAS_TXX9_SERIAL
-       select SERIAL_CORE
-       default y
-
-config HAS_TXX9_SERIAL
-       bool
-
-config SERIAL_TXX9_NR_UARTS
-       int "Maximum number of TMPTX39XX/49XX SIO ports"
-       depends on SERIAL_TXX9
-       default "6"
-
-config SERIAL_TXX9_CONSOLE
-       bool "TMPTX39XX/49XX SIO Console support"
-       depends on SERIAL_TXX9=y
-       select SERIAL_CORE_CONSOLE
-
-config SERIAL_TXX9_STDSERIAL
-       bool "TX39XX/49XX SIO act as standard serial"
-       depends on !SERIAL_8250 && SERIAL_TXX9
-
-config SERIAL_VR41XX
-       tristate "NEC VR4100 series Serial Interface Unit support"
-       depends on CPU_VR41XX
-       select SERIAL_CORE
-       help
-         If you have a NEC VR4100 series processor and you want to use
-         Serial Interface Unit(SIU) or Debug Serial Interface Unit(DSIU)
-         (not include VR4111/VR4121 DSIU), say Y.  Otherwise, say N.
-
-config SERIAL_VR41XX_CONSOLE
-       bool "Enable NEC VR4100 series Serial Interface Unit console"
-       depends on SERIAL_VR41XX=y
-       select SERIAL_CORE_CONSOLE
-       help
-         If you have a NEC VR4100 series processor and you want to use
-         a console on a serial port, say Y.  Otherwise, say N.
-
-config SERIAL_JSM
-       tristate "Digi International NEO PCI Support"
-       depends on PCI
-       select SERIAL_CORE
-       help
-         This is a driver for Digi International's Neo series
-         of cards which provide multiple serial ports. You would need
-         something like this to connect more than two modems to your Linux
-         box, for instance in order to become a dial-in server. This driver
-         supports PCI boards only.
-
-         If you have a card like this, say Y here, otherwise say N.
-
-         To compile this driver as a module, choose M here: the
-         module will be called jsm.
-
-config SERIAL_SGI_IOC4
-       tristate "SGI IOC4 controller serial support"
-       depends on (IA64_GENERIC || IA64_SGI_SN2) && SGI_IOC4
-       select SERIAL_CORE
-       help
-               If you have an SGI Altix with an IOC4 based Base IO card
-               and wish to use the serial ports on this card, say Y.
-               Otherwise, say N.
-
-config SERIAL_SGI_IOC3
-       tristate "SGI Altix IOC3 serial support"
-       depends on (IA64_GENERIC || IA64_SGI_SN2) && SGI_IOC3
-       select SERIAL_CORE
-       help
-         If you have an SGI Altix with an IOC3 serial card,
-         say Y or M.  Otherwise, say N.
-
-config SERIAL_MSM
-       bool "MSM on-chip serial port support"
-       depends on ARM && ARCH_MSM
-       select SERIAL_CORE
-
-config SERIAL_MSM_CONSOLE
-       bool "MSM serial console support"
-       depends on SERIAL_MSM=y
-       select SERIAL_CORE_CONSOLE
-
-config SERIAL_VT8500
-       bool "VIA VT8500 on-chip serial port support"
-       depends on ARM && ARCH_VT8500
-       select SERIAL_CORE
-
-config SERIAL_VT8500_CONSOLE
-       bool "VIA VT8500 serial console support"
-       depends on SERIAL_VT8500=y
-       select SERIAL_CORE_CONSOLE
-
-config SERIAL_NETX
-       tristate "NetX serial port support"
-       depends on ARM && ARCH_NETX
-       select SERIAL_CORE
-       help
-         If you have a machine based on a Hilscher NetX SoC you
-         can enable its onboard serial port by enabling this option.
-
-          To compile this driver as a module, choose M here: the
-          module will be called netx-serial.
-
-config SERIAL_NETX_CONSOLE
-       bool "Console on NetX serial port"
-       depends on SERIAL_NETX=y
-       select SERIAL_CORE_CONSOLE
-       help
-         If you have enabled the serial port on the Hilscher NetX SoC
-         you can make it the console by answering Y to this option.
-
-config SERIAL_OF_PLATFORM
-       tristate "Serial port on Open Firmware platform bus"
-       depends on OF
-       depends on SERIAL_8250 || SERIAL_OF_PLATFORM_NWPSERIAL
-       help
-         If you have a PowerPC based system that has serial ports
-         on a platform specific bus, you should enable this option.
-         Currently, only 8250 compatible ports are supported, but
-         others can easily be added.
-
-config SERIAL_OMAP
-       tristate "OMAP serial port support"
-       depends on ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4
-       select SERIAL_CORE
-       help
-         If you have a machine based on an Texas Instruments OMAP CPU you
-         can enable its onboard serial ports by enabling this option.
-
-         By enabling this option you take advantage of dma feature available
-         with the omap-serial driver. DMA support can be enabled from platform
-         data.
-
-config SERIAL_OMAP_CONSOLE
-       bool "Console on OMAP serial port"
-       depends on SERIAL_OMAP
-       select SERIAL_CORE_CONSOLE
-       help
-         Select this option if you would like to use omap serial port as
-         console.
-
-         Even if you say Y here, the currently visible virtual console
-         (/dev/tty0) will still be used as the system console by default, but
-         you can alter that using a kernel command line option such as
-         "console=ttyOx". (Try "man bootparam" or see the documentation of
-         your boot loader about how to pass options to the kernel at
-         boot time.)
-
-config SERIAL_OF_PLATFORM_NWPSERIAL
-       tristate "NWP serial port driver"
-       depends on PPC_OF && PPC_DCR
-       select SERIAL_OF_PLATFORM
-       select SERIAL_CORE_CONSOLE
-       select SERIAL_CORE
-       help
-         This driver supports the cell network processor nwp serial
-         device.
-
-config SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE
-       bool "Console on NWP serial port"
-       depends on SERIAL_OF_PLATFORM_NWPSERIAL=y
-       select SERIAL_CORE_CONSOLE
-       help
-         Support for Console on the NWP serial ports.
-
-config SERIAL_QE
-       tristate "Freescale QUICC Engine serial port support"
-       depends on QUICC_ENGINE
-       select SERIAL_CORE
-       select FW_LOADER
-       default n
-       help
-         This driver supports the QE serial ports on Freescale embedded
-         PowerPC that contain a QUICC Engine.
-
-config SERIAL_SC26XX
-       tristate "SC2681/SC2692 serial port support"
-       depends on SNI_RM
-       select SERIAL_CORE
-       help
-         This is a driver for the onboard serial ports of
-         older RM400 machines.
-
-config SERIAL_SC26XX_CONSOLE
-       bool "Console on SC2681/SC2692 serial port"
-       depends on SERIAL_SC26XX
-       select SERIAL_CORE_CONSOLE
-       help
-         Support for Console on SC2681/SC2692 serial ports.
-
-config SERIAL_BFIN_SPORT
-       tristate "Blackfin SPORT emulate UART"
-       depends on BLACKFIN
-       select SERIAL_CORE
-       help
-         Enable SPORT emulate UART on Blackfin series.
-
-         To compile this driver as a module, choose M here: the
-         module will be called bfin_sport_uart.
-
-config SERIAL_BFIN_SPORT_CONSOLE
-       bool "Console on Blackfin sport emulated uart"
-       depends on SERIAL_BFIN_SPORT=y
-       select SERIAL_CORE_CONSOLE
-
-config SERIAL_BFIN_SPORT0_UART
-       bool "Enable UART over SPORT0"
-       depends on SERIAL_BFIN_SPORT && !(BF542 || BF544)
-       help
-         Enable UART over SPORT0
-
-config SERIAL_BFIN_SPORT0_UART_CTSRTS
-       bool "Enable UART over SPORT0 hardware flow control"
-       depends on SERIAL_BFIN_SPORT0_UART
-       help
-         Enable hardware flow control in the driver.
-
-config SERIAL_BFIN_SPORT1_UART
-       bool "Enable UART over SPORT1"
-       depends on SERIAL_BFIN_SPORT
-       help
-         Enable UART over SPORT1
-
-config SERIAL_BFIN_SPORT1_UART_CTSRTS
-       bool "Enable UART over SPORT1 hardware flow control"
-       depends on SERIAL_BFIN_SPORT1_UART
-       help
-         Enable hardware flow control in the driver.
-
-config SERIAL_BFIN_SPORT2_UART
-       bool "Enable UART over SPORT2"
-       depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539)
-       help
-         Enable UART over SPORT2
-
-config SERIAL_BFIN_SPORT2_UART_CTSRTS
-       bool "Enable UART over SPORT2 hardware flow control"
-       depends on SERIAL_BFIN_SPORT2_UART
-       help
-         Enable hardware flow control in the driver.
-
-config SERIAL_BFIN_SPORT3_UART
-       bool "Enable UART over SPORT3"
-       depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539)
-       help
-         Enable UART over SPORT3
-
-config SERIAL_BFIN_SPORT3_UART_CTSRTS
-       bool "Enable UART over SPORT3 hardware flow control"
-       depends on SERIAL_BFIN_SPORT3_UART
-       help
-         Enable hardware flow control in the driver.
-
-config SERIAL_TIMBERDALE
-       tristate "Support for timberdale UART"
-       select SERIAL_CORE
-       ---help---
-       Add support for UART controller on timberdale.
-
-config SERIAL_BCM63XX
-       tristate "bcm63xx serial port support"
-       select SERIAL_CORE
-       depends on BCM63XX
-       help
-         If you have a bcm63xx CPU, you can enable its onboard
-         serial port by enabling this options.
-
-          To compile this driver as a module, choose M here: the
-          module will be called bcm963xx_uart.
-
-config SERIAL_BCM63XX_CONSOLE
-       bool "Console on bcm63xx serial port"
-       depends on SERIAL_BCM63XX=y
-       select SERIAL_CORE_CONSOLE
-       help
-         If you have enabled the serial port on the bcm63xx CPU
-         you can make it the console by answering Y to this option.
-
-config SERIAL_GRLIB_GAISLER_APBUART
-       tristate "GRLIB APBUART serial support"
-       depends on OF
-       ---help---
-       Add support for the GRLIB APBUART serial port.
-
-config SERIAL_GRLIB_GAISLER_APBUART_CONSOLE
-       bool "Console on GRLIB APBUART serial port"
-       depends on SERIAL_GRLIB_GAISLER_APBUART=y
-       select SERIAL_CORE_CONSOLE
-       help
-       Support for running a console on the GRLIB APBUART
-
-config SERIAL_ALTERA_JTAGUART
-       tristate "Altera JTAG UART support"
-       select SERIAL_CORE
-       help
-         This driver supports the Altera JTAG UART port.
-
-config SERIAL_ALTERA_JTAGUART_CONSOLE
-       bool "Altera JTAG UART console support"
-       depends on SERIAL_ALTERA_JTAGUART=y
-       select SERIAL_CORE_CONSOLE
-       help
-         Enable a Altera JTAG UART port to be the system console.
-
-config SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS
-       bool "Bypass output when no connection"
-       depends on SERIAL_ALTERA_JTAGUART_CONSOLE
-       select SERIAL_CORE_CONSOLE
-       help
-         Bypass console output and keep going even if there is no
-         JTAG terminal connection with the host.
-
-config SERIAL_ALTERA_UART
-       tristate "Altera UART support"
-       select SERIAL_CORE
-       help
-         This driver supports the Altera softcore UART port.
-
-config SERIAL_ALTERA_UART_MAXPORTS
-       int "Maximum number of Altera UART ports"
-       depends on SERIAL_ALTERA_UART
-       default 4
-       help
-         This setting lets you define the maximum number of the Altera
-         UART ports. The usual default varies from board to board, and
-         this setting is a way of catering for that.
-
-config SERIAL_ALTERA_UART_BAUDRATE
-       int "Default baudrate for Altera UART ports"
-       depends on SERIAL_ALTERA_UART
-       default 115200
-       help
-         This setting lets you define what the default baudrate is for the
-         Altera UART ports. The usual default varies from board to board,
-         and this setting is a way of catering for that.
-
-config SERIAL_ALTERA_UART_CONSOLE
-       bool "Altera UART console support"
-       depends on SERIAL_ALTERA_UART=y
-       select SERIAL_CORE_CONSOLE
-       help
-         Enable a Altera UART port to be the system console.
-
-config SERIAL_IFX6X60
-        tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)"
-       depends on GPIOLIB && SPI && EXPERIMENTAL
-       help
-         Support for the IFX6x60 modem devices on Intel MID platforms.
-
-config SERIAL_PCH_UART
-       tristate "Intel EG20T PCH UART"
-       depends on PCI && DMADEVICES
-       select SERIAL_CORE
-       select PCH_DMA
-       help
-         This driver is for PCH(Platform controller Hub) UART of Intel EG20T
-         which is an IOH(Input/Output Hub) for x86 embedded processor.
-         Enabling PCH_DMA, this PCH UART works as DMA mode.
-endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
deleted file mode 100644 (file)
index 8ea92e9..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-#
-# Makefile for the kernel serial device drivers.
-#
-
-obj-$(CONFIG_SERIAL_CORE) += serial_core.o
-obj-$(CONFIG_SERIAL_21285) += 21285.o
-
-# These Sparc drivers have to appear before others such as 8250
-# which share ttySx minor node space.  Otherwise console device
-# names change and other unplesantries.
-obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
-obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o
-obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o
-obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o
-obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o
-
-obj-$(CONFIG_SERIAL_8250) += 8250.o
-obj-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
-obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o
-obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o
-obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
-obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o
-obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o
-obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o
-obj-$(CONFIG_SERIAL_8250_FOURPORT) += 8250_fourport.o
-obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o
-obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o
-obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o
-obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
-obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o
-obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o
-obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
-obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
-obj-$(CONFIG_SERIAL_PXA) += pxa.o
-obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o
-obj-$(CONFIG_SERIAL_SA1100) += sa1100.o
-obj-$(CONFIG_SERIAL_BCM63XX) += bcm63xx_uart.o
-obj-$(CONFIG_SERIAL_BFIN) += bfin_5xx.o
-obj-$(CONFIG_SERIAL_BFIN_SPORT) += bfin_sport_uart.o
-obj-$(CONFIG_SERIAL_SAMSUNG) += samsung.o
-obj-$(CONFIG_SERIAL_S3C2400) += s3c2400.o
-obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o
-obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o
-obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o
-obj-$(CONFIG_SERIAL_S3C24A0) += s3c24a0.o
-obj-$(CONFIG_SERIAL_S3C6400) += s3c6400.o
-obj-$(CONFIG_SERIAL_S5PV210) += s5pv210.o
-obj-$(CONFIG_SERIAL_MAX3100) += max3100.o
-obj-$(CONFIG_SERIAL_MAX3107) += max3107.o
-obj-$(CONFIG_SERIAL_MAX3107_AAVA) += max3107-aava.o
-obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
-obj-$(CONFIG_SERIAL_MUX) += mux.o
-obj-$(CONFIG_SERIAL_68328) += 68328serial.o
-obj-$(CONFIG_SERIAL_68360) += 68360serial.o
-obj-$(CONFIG_SERIAL_MCF) += mcf.o
-obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
-obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o
-obj-$(CONFIG_SERIAL_DZ) += dz.o
-obj-$(CONFIG_SERIAL_ZS) += zs.o
-obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
-obj-$(CONFIG_SERIAL_SGI_L1_CONSOLE) += sn_console.o
-obj-$(CONFIG_SERIAL_CPM) += cpm_uart/
-obj-$(CONFIG_SERIAL_IMX) += imx.o
-obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o
-obj-$(CONFIG_SERIAL_ICOM) += icom.o
-obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o
-obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
-obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
-obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
-obj-$(CONFIG_SERIAL_SC26XX) += sc26xx.o
-obj-$(CONFIG_SERIAL_JSM) += jsm/
-obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
-obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
-obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
-obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
-obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
-obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
-obj-$(CONFIG_SERIAL_MSM) += msm_serial.o
-obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
-obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
-obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
-obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
-obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
-obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
-obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
-obj-$(CONFIG_SERIAL_TIMBERDALE)        += timbuart.o
-obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
-obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
-obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
-obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o
-obj-$(CONFIG_SERIAL_MRST_MAX3110)      += mrst_max3110.o
-obj-$(CONFIG_SERIAL_MFD_HSU)   += mfd.o
-obj-$(CONFIG_SERIAL_IFX6X60)   += ifx6x60.o
-obj-$(CONFIG_SERIAL_PCH_UART)  += pch_uart.o
diff --git a/drivers/serial/altera_jtaguart.c b/drivers/serial/altera_jtaguart.c
deleted file mode 100644 (file)
index f9b49b5..0000000
+++ /dev/null
@@ -1,504 +0,0 @@
-/*
- * altera_jtaguart.c -- Altera JTAG UART driver
- *
- * Based on mcf.c -- Freescale ColdFire UART driver
- *
- * (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
- * (C) Copyright 2008, Thomas Chou <thomas@wytron.com.tw>
- * (C) Copyright 2010, Tobias Klauser <tklauser@distanz.ch>
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/console.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/altera_jtaguart.h>
-
-#define DRV_NAME "altera_jtaguart"
-
-/*
- * Altera JTAG UART register definitions according to the Altera JTAG UART
- * datasheet: http://www.altera.com/literature/hb/nios2/n2cpu_nii51009.pdf
- */
-
-#define ALTERA_JTAGUART_SIZE                   8
-
-#define ALTERA_JTAGUART_DATA_REG               0
-
-#define ALTERA_JTAGUART_DATA_DATA_MSK          0x000000FF
-#define ALTERA_JTAGUART_DATA_RVALID_MSK                0x00008000
-#define ALTERA_JTAGUART_DATA_RAVAIL_MSK                0xFFFF0000
-#define ALTERA_JTAGUART_DATA_RAVAIL_OFF                16
-
-#define ALTERA_JTAGUART_CONTROL_REG            4
-
-#define ALTERA_JTAGUART_CONTROL_RE_MSK         0x00000001
-#define ALTERA_JTAGUART_CONTROL_WE_MSK         0x00000002
-#define ALTERA_JTAGUART_CONTROL_RI_MSK         0x00000100
-#define ALTERA_JTAGUART_CONTROL_RI_OFF         8
-#define ALTERA_JTAGUART_CONTROL_WI_MSK         0x00000200
-#define ALTERA_JTAGUART_CONTROL_AC_MSK         0x00000400
-#define ALTERA_JTAGUART_CONTROL_WSPACE_MSK     0xFFFF0000
-#define ALTERA_JTAGUART_CONTROL_WSPACE_OFF     16
-
-/*
- * Local per-uart structure.
- */
-struct altera_jtaguart {
-       struct uart_port port;
-       unsigned int sigs;      /* Local copy of line sigs */
-       unsigned long imr;      /* Local IMR mirror */
-};
-
-static unsigned int altera_jtaguart_tx_empty(struct uart_port *port)
-{
-       return (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
-               ALTERA_JTAGUART_CONTROL_WSPACE_MSK) ? TIOCSER_TEMT : 0;
-}
-
-static unsigned int altera_jtaguart_get_mctrl(struct uart_port *port)
-{
-       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
-}
-
-static void altera_jtaguart_set_mctrl(struct uart_port *port, unsigned int sigs)
-{
-}
-
-static void altera_jtaguart_start_tx(struct uart_port *port)
-{
-       struct altera_jtaguart *pp =
-           container_of(port, struct altera_jtaguart, port);
-
-       pp->imr |= ALTERA_JTAGUART_CONTROL_WE_MSK;
-       writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
-}
-
-static void altera_jtaguart_stop_tx(struct uart_port *port)
-{
-       struct altera_jtaguart *pp =
-           container_of(port, struct altera_jtaguart, port);
-
-       pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK;
-       writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
-}
-
-static void altera_jtaguart_stop_rx(struct uart_port *port)
-{
-       struct altera_jtaguart *pp =
-           container_of(port, struct altera_jtaguart, port);
-
-       pp->imr &= ~ALTERA_JTAGUART_CONTROL_RE_MSK;
-       writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
-}
-
-static void altera_jtaguart_break_ctl(struct uart_port *port, int break_state)
-{
-}
-
-static void altera_jtaguart_enable_ms(struct uart_port *port)
-{
-}
-
-static void altera_jtaguart_set_termios(struct uart_port *port,
-                                       struct ktermios *termios,
-                                       struct ktermios *old)
-{
-       /* Just copy the old termios settings back */
-       if (old)
-               tty_termios_copy_hw(termios, old);
-}
-
-static void altera_jtaguart_rx_chars(struct altera_jtaguart *pp)
-{
-       struct uart_port *port = &pp->port;
-       unsigned char ch, flag;
-       unsigned long status;
-
-       while ((status = readl(port->membase + ALTERA_JTAGUART_DATA_REG)) &
-              ALTERA_JTAGUART_DATA_RVALID_MSK) {
-               ch = status & ALTERA_JTAGUART_DATA_DATA_MSK;
-               flag = TTY_NORMAL;
-               port->icount.rx++;
-
-               if (uart_handle_sysrq_char(port, ch))
-                       continue;
-               uart_insert_char(port, 0, 0, ch, flag);
-       }
-
-       tty_flip_buffer_push(port->state->port.tty);
-}
-
-static void altera_jtaguart_tx_chars(struct altera_jtaguart *pp)
-{
-       struct uart_port *port = &pp->port;
-       struct circ_buf *xmit = &port->state->xmit;
-       unsigned int pending, count;
-
-       if (port->x_char) {
-               /* Send special char - probably flow control */
-               writel(port->x_char, port->membase + ALTERA_JTAGUART_DATA_REG);
-               port->x_char = 0;
-               port->icount.tx++;
-               return;
-       }
-
-       pending = uart_circ_chars_pending(xmit);
-       if (pending > 0) {
-               count = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
-                               ALTERA_JTAGUART_CONTROL_WSPACE_MSK) >>
-                       ALTERA_JTAGUART_CONTROL_WSPACE_OFF;
-               if (count > pending)
-                       count = pending;
-               if (count > 0) {
-                       pending -= count;
-                       while (count--) {
-                               writel(xmit->buf[xmit->tail],
-                                      port->membase + ALTERA_JTAGUART_DATA_REG);
-                               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-                               port->icount.tx++;
-                       }
-                       if (pending < WAKEUP_CHARS)
-                               uart_write_wakeup(port);
-               }
-       }
-
-       if (pending == 0) {
-               pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK;
-               writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
-       }
-}
-
-static irqreturn_t altera_jtaguart_interrupt(int irq, void *data)
-{
-       struct uart_port *port = data;
-       struct altera_jtaguart *pp =
-           container_of(port, struct altera_jtaguart, port);
-       unsigned int isr;
-
-       isr = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) >>
-              ALTERA_JTAGUART_CONTROL_RI_OFF) & pp->imr;
-
-       spin_lock(&port->lock);
-
-       if (isr & ALTERA_JTAGUART_CONTROL_RE_MSK)
-               altera_jtaguart_rx_chars(pp);
-       if (isr & ALTERA_JTAGUART_CONTROL_WE_MSK)
-               altera_jtaguart_tx_chars(pp);
-
-       spin_unlock(&port->lock);
-
-       return IRQ_RETVAL(isr);
-}
-
-static void altera_jtaguart_config_port(struct uart_port *port, int flags)
-{
-       port->type = PORT_ALTERA_JTAGUART;
-
-       /* Clear mask, so no surprise interrupts. */
-       writel(0, port->membase + ALTERA_JTAGUART_CONTROL_REG);
-}
-
-static int altera_jtaguart_startup(struct uart_port *port)
-{
-       struct altera_jtaguart *pp =
-           container_of(port, struct altera_jtaguart, port);
-       unsigned long flags;
-       int ret;
-
-       ret = request_irq(port->irq, altera_jtaguart_interrupt, IRQF_DISABLED,
-                       DRV_NAME, port);
-       if (ret) {
-               pr_err(DRV_NAME ": unable to attach Altera JTAG UART %d "
-                      "interrupt vector=%d\n", port->line, port->irq);
-               return ret;
-       }
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /* Enable RX interrupts now */
-       pp->imr = ALTERA_JTAGUART_CONTROL_RE_MSK;
-       writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       return 0;
-}
-
-static void altera_jtaguart_shutdown(struct uart_port *port)
-{
-       struct altera_jtaguart *pp =
-           container_of(port, struct altera_jtaguart, port);
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /* Disable all interrupts now */
-       pp->imr = 0;
-       writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       free_irq(port->irq, port);
-}
-
-static const char *altera_jtaguart_type(struct uart_port *port)
-{
-       return (port->type == PORT_ALTERA_JTAGUART) ? "Altera JTAG UART" : NULL;
-}
-
-static int altera_jtaguart_request_port(struct uart_port *port)
-{
-       /* UARTs always present */
-       return 0;
-}
-
-static void altera_jtaguart_release_port(struct uart_port *port)
-{
-       /* Nothing to release... */
-}
-
-static int altera_jtaguart_verify_port(struct uart_port *port,
-                                      struct serial_struct *ser)
-{
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_ALTERA_JTAGUART)
-               return -EINVAL;
-       return 0;
-}
-
-/*
- *     Define the basic serial functions we support.
- */
-static struct uart_ops altera_jtaguart_ops = {
-       .tx_empty       = altera_jtaguart_tx_empty,
-       .get_mctrl      = altera_jtaguart_get_mctrl,
-       .set_mctrl      = altera_jtaguart_set_mctrl,
-       .start_tx       = altera_jtaguart_start_tx,
-       .stop_tx        = altera_jtaguart_stop_tx,
-       .stop_rx        = altera_jtaguart_stop_rx,
-       .enable_ms      = altera_jtaguart_enable_ms,
-       .break_ctl      = altera_jtaguart_break_ctl,
-       .startup        = altera_jtaguart_startup,
-       .shutdown       = altera_jtaguart_shutdown,
-       .set_termios    = altera_jtaguart_set_termios,
-       .type           = altera_jtaguart_type,
-       .request_port   = altera_jtaguart_request_port,
-       .release_port   = altera_jtaguart_release_port,
-       .config_port    = altera_jtaguart_config_port,
-       .verify_port    = altera_jtaguart_verify_port,
-};
-
-#define ALTERA_JTAGUART_MAXPORTS 1
-static struct altera_jtaguart altera_jtaguart_ports[ALTERA_JTAGUART_MAXPORTS];
-
-#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE)
-
-int __init early_altera_jtaguart_setup(struct altera_jtaguart_platform_uart
-                                      *platp)
-{
-       struct uart_port *port;
-       int i;
-
-       for (i = 0; i < ALTERA_JTAGUART_MAXPORTS && platp[i].mapbase; i++) {
-               port = &altera_jtaguart_ports[i].port;
-
-               port->line = i;
-               port->type = PORT_ALTERA_JTAGUART;
-               port->mapbase = platp[i].mapbase;
-               port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE);
-               port->iotype = SERIAL_IO_MEM;
-               port->irq = platp[i].irq;
-               port->flags = ASYNC_BOOT_AUTOCONF;
-               port->ops = &altera_jtaguart_ops;
-       }
-
-       return 0;
-}
-
-#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS)
-static void altera_jtaguart_console_putc(struct console *co, const char c)
-{
-       struct uart_port *port = &(altera_jtaguart_ports + co->index)->port;
-       unsigned long status;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       while (((status = readl(port->membase + ALTERA_JTAGUART_CONTROL_REG)) &
-               ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) {
-               if ((status & ALTERA_JTAGUART_CONTROL_AC_MSK) == 0) {
-                       spin_unlock_irqrestore(&port->lock, flags);
-                       return; /* no connection activity */
-               }
-               spin_unlock_irqrestore(&port->lock, flags);
-               cpu_relax();
-               spin_lock_irqsave(&port->lock, flags);
-       }
-       writel(c, port->membase + ALTERA_JTAGUART_DATA_REG);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-#else
-static void altera_jtaguart_console_putc(struct console *co, const char c)
-{
-       struct uart_port *port = &(altera_jtaguart_ports + co->index)->port;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       while ((readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
-               ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) {
-               spin_unlock_irqrestore(&port->lock, flags);
-               cpu_relax();
-               spin_lock_irqsave(&port->lock, flags);
-       }
-       writel(c, port->membase + ALTERA_JTAGUART_DATA_REG);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-#endif
-
-static void altera_jtaguart_console_write(struct console *co, const char *s,
-                                         unsigned int count)
-{
-       for (; count; count--, s++) {
-               altera_jtaguart_console_putc(co, *s);
-               if (*s == '\n')
-                       altera_jtaguart_console_putc(co, '\r');
-       }
-}
-
-static int __init altera_jtaguart_console_setup(struct console *co,
-                                               char *options)
-{
-       struct uart_port *port;
-
-       if (co->index < 0 || co->index >= ALTERA_JTAGUART_MAXPORTS)
-               return -EINVAL;
-       port = &altera_jtaguart_ports[co->index].port;
-       if (port->membase == 0)
-               return -ENODEV;
-       return 0;
-}
-
-static struct uart_driver altera_jtaguart_driver;
-
-static struct console altera_jtaguart_console = {
-       .name   = "ttyJ",
-       .write  = altera_jtaguart_console_write,
-       .device = uart_console_device,
-       .setup  = altera_jtaguart_console_setup,
-       .flags  = CON_PRINTBUFFER,
-       .index  = -1,
-       .data   = &altera_jtaguart_driver,
-};
-
-static int __init altera_jtaguart_console_init(void)
-{
-       register_console(&altera_jtaguart_console);
-       return 0;
-}
-
-console_initcall(altera_jtaguart_console_init);
-
-#define        ALTERA_JTAGUART_CONSOLE (&altera_jtaguart_console)
-
-#else
-
-#define        ALTERA_JTAGUART_CONSOLE NULL
-
-#endif /* CONFIG_ALTERA_JTAGUART_CONSOLE */
-
-static struct uart_driver altera_jtaguart_driver = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "altera_jtaguart",
-       .dev_name       = "ttyJ",
-       .major          = ALTERA_JTAGUART_MAJOR,
-       .minor          = ALTERA_JTAGUART_MINOR,
-       .nr             = ALTERA_JTAGUART_MAXPORTS,
-       .cons           = ALTERA_JTAGUART_CONSOLE,
-};
-
-static int __devinit altera_jtaguart_probe(struct platform_device *pdev)
-{
-       struct altera_jtaguart_platform_uart *platp = pdev->dev.platform_data;
-       struct uart_port *port;
-       int i;
-
-       for (i = 0; i < ALTERA_JTAGUART_MAXPORTS && platp[i].mapbase; i++) {
-               port = &altera_jtaguart_ports[i].port;
-
-               port->line = i;
-               port->type = PORT_ALTERA_JTAGUART;
-               port->mapbase = platp[i].mapbase;
-               port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE);
-               port->iotype = SERIAL_IO_MEM;
-               port->irq = platp[i].irq;
-               port->ops = &altera_jtaguart_ops;
-               port->flags = ASYNC_BOOT_AUTOCONF;
-
-               uart_add_one_port(&altera_jtaguart_driver, port);
-       }
-
-       return 0;
-}
-
-static int __devexit altera_jtaguart_remove(struct platform_device *pdev)
-{
-       struct uart_port *port;
-       int i;
-
-       for (i = 0; i < ALTERA_JTAGUART_MAXPORTS; i++) {
-               port = &altera_jtaguart_ports[i].port;
-               if (port)
-                       uart_remove_one_port(&altera_jtaguart_driver, port);
-       }
-
-       return 0;
-}
-
-static struct platform_driver altera_jtaguart_platform_driver = {
-       .probe  = altera_jtaguart_probe,
-       .remove = __devexit_p(altera_jtaguart_remove),
-       .driver = {
-               .name   = DRV_NAME,
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init altera_jtaguart_init(void)
-{
-       int rc;
-
-       rc = uart_register_driver(&altera_jtaguart_driver);
-       if (rc)
-               return rc;
-       rc = platform_driver_register(&altera_jtaguart_platform_driver);
-       if (rc) {
-               uart_unregister_driver(&altera_jtaguart_driver);
-               return rc;
-       }
-       return 0;
-}
-
-static void __exit altera_jtaguart_exit(void)
-{
-       platform_driver_unregister(&altera_jtaguart_platform_driver);
-       uart_unregister_driver(&altera_jtaguart_driver);
-}
-
-module_init(altera_jtaguart_init);
-module_exit(altera_jtaguart_exit);
-
-MODULE_DESCRIPTION("Altera JTAG UART driver");
-MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/serial/altera_uart.c b/drivers/serial/altera_uart.c
deleted file mode 100644 (file)
index 7212162..0000000
+++ /dev/null
@@ -1,608 +0,0 @@
-/*
- * altera_uart.c -- Altera UART driver
- *
- * Based on mcf.c -- Freescale ColdFire UART driver
- *
- * (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
- * (C) Copyright 2008, Thomas Chou <thomas@wytron.com.tw>
- * (C) Copyright 2010, Tobias Klauser <tklauser@distanz.ch>
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/console.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/altera_uart.h>
-
-#define DRV_NAME "altera_uart"
-#define SERIAL_ALTERA_MAJOR 204
-#define SERIAL_ALTERA_MINOR 213
-
-/*
- * Altera UART register definitions according to the Nios UART datasheet:
- * http://www.altera.com/literature/ds/ds_nios_uart.pdf
- */
-
-#define ALTERA_UART_SIZE               32
-
-#define ALTERA_UART_RXDATA_REG         0
-#define ALTERA_UART_TXDATA_REG         4
-#define ALTERA_UART_STATUS_REG         8
-#define ALTERA_UART_CONTROL_REG                12
-#define ALTERA_UART_DIVISOR_REG                16
-#define ALTERA_UART_EOP_REG            20
-
-#define ALTERA_UART_STATUS_PE_MSK      0x0001  /* parity error */
-#define ALTERA_UART_STATUS_FE_MSK      0x0002  /* framing error */
-#define ALTERA_UART_STATUS_BRK_MSK     0x0004  /* break */
-#define ALTERA_UART_STATUS_ROE_MSK     0x0008  /* RX overrun error */
-#define ALTERA_UART_STATUS_TOE_MSK     0x0010  /* TX overrun error */
-#define ALTERA_UART_STATUS_TMT_MSK     0x0020  /* TX shift register state */
-#define ALTERA_UART_STATUS_TRDY_MSK    0x0040  /* TX ready */
-#define ALTERA_UART_STATUS_RRDY_MSK    0x0080  /* RX ready */
-#define ALTERA_UART_STATUS_E_MSK       0x0100  /* exception condition */
-#define ALTERA_UART_STATUS_DCTS_MSK    0x0400  /* CTS logic-level change */
-#define ALTERA_UART_STATUS_CTS_MSK     0x0800  /* CTS logic state */
-#define ALTERA_UART_STATUS_EOP_MSK     0x1000  /* EOP written/read */
-
-                                               /* Enable interrupt on... */
-#define ALTERA_UART_CONTROL_PE_MSK     0x0001  /* ...parity error */
-#define ALTERA_UART_CONTROL_FE_MSK     0x0002  /* ...framing error */
-#define ALTERA_UART_CONTROL_BRK_MSK    0x0004  /* ...break */
-#define ALTERA_UART_CONTROL_ROE_MSK    0x0008  /* ...RX overrun */
-#define ALTERA_UART_CONTROL_TOE_MSK    0x0010  /* ...TX overrun */
-#define ALTERA_UART_CONTROL_TMT_MSK    0x0020  /* ...TX shift register empty */
-#define ALTERA_UART_CONTROL_TRDY_MSK   0x0040  /* ...TX ready */
-#define ALTERA_UART_CONTROL_RRDY_MSK   0x0080  /* ...RX ready */
-#define ALTERA_UART_CONTROL_E_MSK      0x0100  /* ...exception*/
-
-#define ALTERA_UART_CONTROL_TRBK_MSK   0x0200  /* TX break */
-#define ALTERA_UART_CONTROL_DCTS_MSK   0x0400  /* Interrupt on CTS change */
-#define ALTERA_UART_CONTROL_RTS_MSK    0x0800  /* RTS signal */
-#define ALTERA_UART_CONTROL_EOP_MSK    0x1000  /* Interrupt on EOP */
-
-/*
- * Local per-uart structure.
- */
-struct altera_uart {
-       struct uart_port port;
-       struct timer_list tmr;
-       unsigned int sigs;      /* Local copy of line sigs */
-       unsigned short imr;     /* Local IMR mirror */
-};
-
-static u32 altera_uart_readl(struct uart_port *port, int reg)
-{
-       struct altera_uart_platform_uart *platp = port->private_data;
-
-       return readl(port->membase + (reg << platp->bus_shift));
-}
-
-static void altera_uart_writel(struct uart_port *port, u32 dat, int reg)
-{
-       struct altera_uart_platform_uart *platp = port->private_data;
-
-       writel(dat, port->membase + (reg << platp->bus_shift));
-}
-
-static unsigned int altera_uart_tx_empty(struct uart_port *port)
-{
-       return (altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
-               ALTERA_UART_STATUS_TMT_MSK) ? TIOCSER_TEMT : 0;
-}
-
-static unsigned int altera_uart_get_mctrl(struct uart_port *port)
-{
-       struct altera_uart *pp = container_of(port, struct altera_uart, port);
-       unsigned int sigs;
-
-       sigs = (altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
-            ALTERA_UART_STATUS_CTS_MSK) ? TIOCM_CTS : 0;
-       sigs |= (pp->sigs & TIOCM_RTS);
-
-       return sigs;
-}
-
-static void altera_uart_set_mctrl(struct uart_port *port, unsigned int sigs)
-{
-       struct altera_uart *pp = container_of(port, struct altera_uart, port);
-
-       pp->sigs = sigs;
-       if (sigs & TIOCM_RTS)
-               pp->imr |= ALTERA_UART_CONTROL_RTS_MSK;
-       else
-               pp->imr &= ~ALTERA_UART_CONTROL_RTS_MSK;
-       altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
-}
-
-static void altera_uart_start_tx(struct uart_port *port)
-{
-       struct altera_uart *pp = container_of(port, struct altera_uart, port);
-
-       pp->imr |= ALTERA_UART_CONTROL_TRDY_MSK;
-       altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
-}
-
-static void altera_uart_stop_tx(struct uart_port *port)
-{
-       struct altera_uart *pp = container_of(port, struct altera_uart, port);
-
-       pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK;
-       altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
-}
-
-static void altera_uart_stop_rx(struct uart_port *port)
-{
-       struct altera_uart *pp = container_of(port, struct altera_uart, port);
-
-       pp->imr &= ~ALTERA_UART_CONTROL_RRDY_MSK;
-       altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
-}
-
-static void altera_uart_break_ctl(struct uart_port *port, int break_state)
-{
-       struct altera_uart *pp = container_of(port, struct altera_uart, port);
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       if (break_state == -1)
-               pp->imr |= ALTERA_UART_CONTROL_TRBK_MSK;
-       else
-               pp->imr &= ~ALTERA_UART_CONTROL_TRBK_MSK;
-       altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void altera_uart_enable_ms(struct uart_port *port)
-{
-}
-
-static void altera_uart_set_termios(struct uart_port *port,
-                                   struct ktermios *termios,
-                                   struct ktermios *old)
-{
-       unsigned long flags;
-       unsigned int baud, baudclk;
-
-       baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
-       baudclk = port->uartclk / baud;
-
-       if (old)
-               tty_termios_copy_hw(termios, old);
-       tty_termios_encode_baud_rate(termios, baud, baud);
-
-       spin_lock_irqsave(&port->lock, flags);
-       uart_update_timeout(port, termios->c_cflag, baud);
-       altera_uart_writel(port, baudclk, ALTERA_UART_DIVISOR_REG);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void altera_uart_rx_chars(struct altera_uart *pp)
-{
-       struct uart_port *port = &pp->port;
-       unsigned char ch, flag;
-       unsigned short status;
-
-       while ((status = altera_uart_readl(port, ALTERA_UART_STATUS_REG)) &
-              ALTERA_UART_STATUS_RRDY_MSK) {
-               ch = altera_uart_readl(port, ALTERA_UART_RXDATA_REG);
-               flag = TTY_NORMAL;
-               port->icount.rx++;
-
-               if (status & ALTERA_UART_STATUS_E_MSK) {
-                       altera_uart_writel(port, status,
-                                          ALTERA_UART_STATUS_REG);
-
-                       if (status & ALTERA_UART_STATUS_BRK_MSK) {
-                               port->icount.brk++;
-                               if (uart_handle_break(port))
-                                       continue;
-                       } else if (status & ALTERA_UART_STATUS_PE_MSK) {
-                               port->icount.parity++;
-                       } else if (status & ALTERA_UART_STATUS_ROE_MSK) {
-                               port->icount.overrun++;
-                       } else if (status & ALTERA_UART_STATUS_FE_MSK) {
-                               port->icount.frame++;
-                       }
-
-                       status &= port->read_status_mask;
-
-                       if (status & ALTERA_UART_STATUS_BRK_MSK)
-                               flag = TTY_BREAK;
-                       else if (status & ALTERA_UART_STATUS_PE_MSK)
-                               flag = TTY_PARITY;
-                       else if (status & ALTERA_UART_STATUS_FE_MSK)
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(port, ch))
-                       continue;
-               uart_insert_char(port, status, ALTERA_UART_STATUS_ROE_MSK, ch,
-                                flag);
-       }
-
-       tty_flip_buffer_push(port->state->port.tty);
-}
-
-static void altera_uart_tx_chars(struct altera_uart *pp)
-{
-       struct uart_port *port = &pp->port;
-       struct circ_buf *xmit = &port->state->xmit;
-
-       if (port->x_char) {
-               /* Send special char - probably flow control */
-               altera_uart_writel(port, port->x_char, ALTERA_UART_TXDATA_REG);
-               port->x_char = 0;
-               port->icount.tx++;
-               return;
-       }
-
-       while (altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
-              ALTERA_UART_STATUS_TRDY_MSK) {
-               if (xmit->head == xmit->tail)
-                       break;
-               altera_uart_writel(port, xmit->buf[xmit->tail],
-                      ALTERA_UART_TXDATA_REG);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (xmit->head == xmit->tail) {
-               pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK;
-               altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
-       }
-}
-
-static irqreturn_t altera_uart_interrupt(int irq, void *data)
-{
-       struct uart_port *port = data;
-       struct altera_uart *pp = container_of(port, struct altera_uart, port);
-       unsigned int isr;
-
-       isr = altera_uart_readl(port, ALTERA_UART_STATUS_REG) & pp->imr;
-
-       spin_lock(&port->lock);
-       if (isr & ALTERA_UART_STATUS_RRDY_MSK)
-               altera_uart_rx_chars(pp);
-       if (isr & ALTERA_UART_STATUS_TRDY_MSK)
-               altera_uart_tx_chars(pp);
-       spin_unlock(&port->lock);
-
-       return IRQ_RETVAL(isr);
-}
-
-static void altera_uart_timer(unsigned long data)
-{
-       struct uart_port *port = (void *)data;
-       struct altera_uart *pp = container_of(port, struct altera_uart, port);
-
-       altera_uart_interrupt(0, port);
-       mod_timer(&pp->tmr, jiffies + uart_poll_timeout(port));
-}
-
-static void altera_uart_config_port(struct uart_port *port, int flags)
-{
-       port->type = PORT_ALTERA_UART;
-
-       /* Clear mask, so no surprise interrupts. */
-       altera_uart_writel(port, 0, ALTERA_UART_CONTROL_REG);
-       /* Clear status register */
-       altera_uart_writel(port, 0, ALTERA_UART_STATUS_REG);
-}
-
-static int altera_uart_startup(struct uart_port *port)
-{
-       struct altera_uart *pp = container_of(port, struct altera_uart, port);
-       unsigned long flags;
-       int ret;
-
-       if (!port->irq) {
-               setup_timer(&pp->tmr, altera_uart_timer, (unsigned long)port);
-               mod_timer(&pp->tmr, jiffies + uart_poll_timeout(port));
-               return 0;
-       }
-
-       ret = request_irq(port->irq, altera_uart_interrupt, IRQF_DISABLED,
-                       DRV_NAME, port);
-       if (ret) {
-               pr_err(DRV_NAME ": unable to attach Altera UART %d "
-                      "interrupt vector=%d\n", port->line, port->irq);
-               return ret;
-       }
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /* Enable RX interrupts now */
-       pp->imr = ALTERA_UART_CONTROL_RRDY_MSK;
-       writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       return 0;
-}
-
-static void altera_uart_shutdown(struct uart_port *port)
-{
-       struct altera_uart *pp = container_of(port, struct altera_uart, port);
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /* Disable all interrupts now */
-       pp->imr = 0;
-       writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       if (port->irq)
-               free_irq(port->irq, port);
-       else
-               del_timer_sync(&pp->tmr);
-}
-
-static const char *altera_uart_type(struct uart_port *port)
-{
-       return (port->type == PORT_ALTERA_UART) ? "Altera UART" : NULL;
-}
-
-static int altera_uart_request_port(struct uart_port *port)
-{
-       /* UARTs always present */
-       return 0;
-}
-
-static void altera_uart_release_port(struct uart_port *port)
-{
-       /* Nothing to release... */
-}
-
-static int altera_uart_verify_port(struct uart_port *port,
-                                  struct serial_struct *ser)
-{
-       if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_ALTERA_UART))
-               return -EINVAL;
-       return 0;
-}
-
-/*
- *     Define the basic serial functions we support.
- */
-static struct uart_ops altera_uart_ops = {
-       .tx_empty       = altera_uart_tx_empty,
-       .get_mctrl      = altera_uart_get_mctrl,
-       .set_mctrl      = altera_uart_set_mctrl,
-       .start_tx       = altera_uart_start_tx,
-       .stop_tx        = altera_uart_stop_tx,
-       .stop_rx        = altera_uart_stop_rx,
-       .enable_ms      = altera_uart_enable_ms,
-       .break_ctl      = altera_uart_break_ctl,
-       .startup        = altera_uart_startup,
-       .shutdown       = altera_uart_shutdown,
-       .set_termios    = altera_uart_set_termios,
-       .type           = altera_uart_type,
-       .request_port   = altera_uart_request_port,
-       .release_port   = altera_uart_release_port,
-       .config_port    = altera_uart_config_port,
-       .verify_port    = altera_uart_verify_port,
-};
-
-static struct altera_uart altera_uart_ports[CONFIG_SERIAL_ALTERA_UART_MAXPORTS];
-
-#if defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE)
-
-int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp)
-{
-       struct uart_port *port;
-       int i;
-
-       for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS && platp[i].mapbase; i++) {
-               port = &altera_uart_ports[i].port;
-
-               port->line = i;
-               port->type = PORT_ALTERA_UART;
-               port->mapbase = platp[i].mapbase;
-               port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE);
-               port->iotype = SERIAL_IO_MEM;
-               port->irq = platp[i].irq;
-               port->uartclk = platp[i].uartclk;
-               port->flags = UPF_BOOT_AUTOCONF;
-               port->ops = &altera_uart_ops;
-               port->private_data = platp;
-       }
-
-       return 0;
-}
-
-static void altera_uart_console_putc(struct uart_port *port, const char c)
-{
-       while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
-                ALTERA_UART_STATUS_TRDY_MSK))
-               cpu_relax();
-
-       writel(c, port->membase + ALTERA_UART_TXDATA_REG);
-}
-
-static void altera_uart_console_write(struct console *co, const char *s,
-                                     unsigned int count)
-{
-       struct uart_port *port = &(altera_uart_ports + co->index)->port;
-
-       for (; count; count--, s++) {
-               altera_uart_console_putc(port, *s);
-               if (*s == '\n')
-                       altera_uart_console_putc(port, '\r');
-       }
-}
-
-static int __init altera_uart_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port;
-       int baud = CONFIG_SERIAL_ALTERA_UART_BAUDRATE;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       if (co->index < 0 || co->index >= CONFIG_SERIAL_ALTERA_UART_MAXPORTS)
-               return -EINVAL;
-       port = &altera_uart_ports[co->index].port;
-       if (!port->membase)
-               return -ENODEV;
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver altera_uart_driver;
-
-static struct console altera_uart_console = {
-       .name   = "ttyAL",
-       .write  = altera_uart_console_write,
-       .device = uart_console_device,
-       .setup  = altera_uart_console_setup,
-       .flags  = CON_PRINTBUFFER,
-       .index  = -1,
-       .data   = &altera_uart_driver,
-};
-
-static int __init altera_uart_console_init(void)
-{
-       register_console(&altera_uart_console);
-       return 0;
-}
-
-console_initcall(altera_uart_console_init);
-
-#define        ALTERA_UART_CONSOLE     (&altera_uart_console)
-
-#else
-
-#define        ALTERA_UART_CONSOLE     NULL
-
-#endif /* CONFIG_ALTERA_UART_CONSOLE */
-
-/*
- *     Define the altera_uart UART driver structure.
- */
-static struct uart_driver altera_uart_driver = {
-       .owner          = THIS_MODULE,
-       .driver_name    = DRV_NAME,
-       .dev_name       = "ttyAL",
-       .major          = SERIAL_ALTERA_MAJOR,
-       .minor          = SERIAL_ALTERA_MINOR,
-       .nr             = CONFIG_SERIAL_ALTERA_UART_MAXPORTS,
-       .cons           = ALTERA_UART_CONSOLE,
-};
-
-static int __devinit altera_uart_probe(struct platform_device *pdev)
-{
-       struct altera_uart_platform_uart *platp = pdev->dev.platform_data;
-       struct uart_port *port;
-       struct resource *res_mem;
-       struct resource *res_irq;
-       int i = pdev->id;
-
-       /* -1 emphasizes that the platform must have one port, no .N suffix */
-       if (i == -1)
-               i = 0;
-
-       if (i >= CONFIG_SERIAL_ALTERA_UART_MAXPORTS)
-               return -EINVAL;
-
-       port = &altera_uart_ports[i].port;
-
-       res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (res_mem)
-               port->mapbase = res_mem->start;
-       else if (platp->mapbase)
-               port->mapbase = platp->mapbase;
-       else
-               return -EINVAL;
-
-       res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (res_irq)
-               port->irq = res_irq->start;
-       else if (platp->irq)
-               port->irq = platp->irq;
-
-       port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE);
-       if (!port->membase)
-               return -ENOMEM;
-
-       port->line = i;
-       port->type = PORT_ALTERA_UART;
-       port->iotype = SERIAL_IO_MEM;
-       port->uartclk = platp->uartclk;
-       port->ops = &altera_uart_ops;
-       port->flags = UPF_BOOT_AUTOCONF;
-       port->private_data = platp;
-
-       uart_add_one_port(&altera_uart_driver, port);
-
-       return 0;
-}
-
-static int __devexit altera_uart_remove(struct platform_device *pdev)
-{
-       struct uart_port *port = &altera_uart_ports[pdev->id].port;
-
-       uart_remove_one_port(&altera_uart_driver, port);
-       return 0;
-}
-
-static struct platform_driver altera_uart_platform_driver = {
-       .probe  = altera_uart_probe,
-       .remove = __devexit_p(altera_uart_remove),
-       .driver = {
-               .name   = DRV_NAME,
-               .owner  = THIS_MODULE,
-               .pm     = NULL,
-       },
-};
-
-static int __init altera_uart_init(void)
-{
-       int rc;
-
-       rc = uart_register_driver(&altera_uart_driver);
-       if (rc)
-               return rc;
-       rc = platform_driver_register(&altera_uart_platform_driver);
-       if (rc) {
-               uart_unregister_driver(&altera_uart_driver);
-               return rc;
-       }
-       return 0;
-}
-
-static void __exit altera_uart_exit(void)
-{
-       platform_driver_unregister(&altera_uart_platform_driver);
-       uart_unregister_driver(&altera_uart_driver);
-}
-
-module_init(altera_uart_init);
-module_exit(altera_uart_exit);
-
-MODULE_DESCRIPTION("Altera UART driver");
-MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
-MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_ALTERA_MAJOR);
diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c
deleted file mode 100644 (file)
index 2904aa0..0000000
+++ /dev/null
@@ -1,825 +0,0 @@
-/*
- *  linux/drivers/char/amba.c
- *
- *  Driver for AMBA serial ports
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *
- *  Copyright 1999 ARM Limited
- *  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
- *
- * This is a generic driver for ARM AMBA-type serial ports.  They
- * have a lot of 16550-like features, but are not register compatible.
- * Note that although they do have CTS, DCD and DSR inputs, they do
- * not have an RI input, nor do they have DTR or RTS outputs.  If
- * required, these have to be supplied via some other means (eg, GPIO)
- * and hooked into this driver.
- */
-
-#if defined(CONFIG_SERIAL_AMBA_PL010_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/amba/bus.h>
-#include <linux/amba/serial.h>
-#include <linux/clk.h>
-#include <linux/slab.h>
-
-#include <asm/io.h>
-
-#define UART_NR                8
-
-#define SERIAL_AMBA_MAJOR      204
-#define SERIAL_AMBA_MINOR      16
-#define SERIAL_AMBA_NR         UART_NR
-
-#define AMBA_ISR_PASS_LIMIT    256
-
-#define UART_RX_DATA(s)                (((s) & UART01x_FR_RXFE) == 0)
-#define UART_TX_READY(s)       (((s) & UART01x_FR_TXFF) == 0)
-
-#define UART_DUMMY_RSR_RX      256
-#define UART_PORT_SIZE         64
-
-/*
- * We wrap our port structure around the generic uart_port.
- */
-struct uart_amba_port {
-       struct uart_port        port;
-       struct clk              *clk;
-       struct amba_device      *dev;
-       struct amba_pl010_data  *data;
-       unsigned int            old_status;
-};
-
-static void pl010_stop_tx(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int cr;
-
-       cr = readb(uap->port.membase + UART010_CR);
-       cr &= ~UART010_CR_TIE;
-       writel(cr, uap->port.membase + UART010_CR);
-}
-
-static void pl010_start_tx(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int cr;
-
-       cr = readb(uap->port.membase + UART010_CR);
-       cr |= UART010_CR_TIE;
-       writel(cr, uap->port.membase + UART010_CR);
-}
-
-static void pl010_stop_rx(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int cr;
-
-       cr = readb(uap->port.membase + UART010_CR);
-       cr &= ~(UART010_CR_RIE | UART010_CR_RTIE);
-       writel(cr, uap->port.membase + UART010_CR);
-}
-
-static void pl010_enable_ms(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int cr;
-
-       cr = readb(uap->port.membase + UART010_CR);
-       cr |= UART010_CR_MSIE;
-       writel(cr, uap->port.membase + UART010_CR);
-}
-
-static void pl010_rx_chars(struct uart_amba_port *uap)
-{
-       struct tty_struct *tty = uap->port.state->port.tty;
-       unsigned int status, ch, flag, rsr, max_count = 256;
-
-       status = readb(uap->port.membase + UART01x_FR);
-       while (UART_RX_DATA(status) && max_count--) {
-               ch = readb(uap->port.membase + UART01x_DR);
-               flag = TTY_NORMAL;
-
-               uap->port.icount.rx++;
-
-               /*
-                * Note that the error handling code is
-                * out of the main execution path
-                */
-               rsr = readb(uap->port.membase + UART01x_RSR) | UART_DUMMY_RSR_RX;
-               if (unlikely(rsr & UART01x_RSR_ANY)) {
-                       writel(0, uap->port.membase + UART01x_ECR);
-
-                       if (rsr & UART01x_RSR_BE) {
-                               rsr &= ~(UART01x_RSR_FE | UART01x_RSR_PE);
-                               uap->port.icount.brk++;
-                               if (uart_handle_break(&uap->port))
-                                       goto ignore_char;
-                       } else if (rsr & UART01x_RSR_PE)
-                               uap->port.icount.parity++;
-                       else if (rsr & UART01x_RSR_FE)
-                               uap->port.icount.frame++;
-                       if (rsr & UART01x_RSR_OE)
-                               uap->port.icount.overrun++;
-
-                       rsr &= uap->port.read_status_mask;
-
-                       if (rsr & UART01x_RSR_BE)
-                               flag = TTY_BREAK;
-                       else if (rsr & UART01x_RSR_PE)
-                               flag = TTY_PARITY;
-                       else if (rsr & UART01x_RSR_FE)
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(&uap->port, ch))
-                       goto ignore_char;
-
-               uart_insert_char(&uap->port, rsr, UART01x_RSR_OE, ch, flag);
-
-       ignore_char:
-               status = readb(uap->port.membase + UART01x_FR);
-       }
-       spin_unlock(&uap->port.lock);
-       tty_flip_buffer_push(tty);
-       spin_lock(&uap->port.lock);
-}
-
-static void pl010_tx_chars(struct uart_amba_port *uap)
-{
-       struct circ_buf *xmit = &uap->port.state->xmit;
-       int count;
-
-       if (uap->port.x_char) {
-               writel(uap->port.x_char, uap->port.membase + UART01x_DR);
-               uap->port.icount.tx++;
-               uap->port.x_char = 0;
-               return;
-       }
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) {
-               pl010_stop_tx(&uap->port);
-               return;
-       }
-
-       count = uap->port.fifosize >> 1;
-       do {
-               writel(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               uap->port.icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (--count > 0);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&uap->port);
-
-       if (uart_circ_empty(xmit))
-               pl010_stop_tx(&uap->port);
-}
-
-static void pl010_modem_status(struct uart_amba_port *uap)
-{
-       unsigned int status, delta;
-
-       writel(0, uap->port.membase + UART010_ICR);
-
-       status = readb(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
-
-       delta = status ^ uap->old_status;
-       uap->old_status = status;
-
-       if (!delta)
-               return;
-
-       if (delta & UART01x_FR_DCD)
-               uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD);
-
-       if (delta & UART01x_FR_DSR)
-               uap->port.icount.dsr++;
-
-       if (delta & UART01x_FR_CTS)
-               uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS);
-
-       wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
-}
-
-static irqreturn_t pl010_int(int irq, void *dev_id)
-{
-       struct uart_amba_port *uap = dev_id;
-       unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
-       int handled = 0;
-
-       spin_lock(&uap->port.lock);
-
-       status = readb(uap->port.membase + UART010_IIR);
-       if (status) {
-               do {
-                       if (status & (UART010_IIR_RTIS | UART010_IIR_RIS))
-                               pl010_rx_chars(uap);
-                       if (status & UART010_IIR_MIS)
-                               pl010_modem_status(uap);
-                       if (status & UART010_IIR_TIS)
-                               pl010_tx_chars(uap);
-
-                       if (pass_counter-- == 0)
-                               break;
-
-                       status = readb(uap->port.membase + UART010_IIR);
-               } while (status & (UART010_IIR_RTIS | UART010_IIR_RIS |
-                                  UART010_IIR_TIS));
-               handled = 1;
-       }
-
-       spin_unlock(&uap->port.lock);
-
-       return IRQ_RETVAL(handled);
-}
-
-static unsigned int pl010_tx_empty(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int status = readb(uap->port.membase + UART01x_FR);
-       return status & UART01x_FR_BUSY ? 0 : TIOCSER_TEMT;
-}
-
-static unsigned int pl010_get_mctrl(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int result = 0;
-       unsigned int status;
-
-       status = readb(uap->port.membase + UART01x_FR);
-       if (status & UART01x_FR_DCD)
-               result |= TIOCM_CAR;
-       if (status & UART01x_FR_DSR)
-               result |= TIOCM_DSR;
-       if (status & UART01x_FR_CTS)
-               result |= TIOCM_CTS;
-
-       return result;
-}
-
-static void pl010_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-
-       if (uap->data)
-               uap->data->set_mctrl(uap->dev, uap->port.membase, mctrl);
-}
-
-static void pl010_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned long flags;
-       unsigned int lcr_h;
-
-       spin_lock_irqsave(&uap->port.lock, flags);
-       lcr_h = readb(uap->port.membase + UART010_LCRH);
-       if (break_state == -1)
-               lcr_h |= UART01x_LCRH_BRK;
-       else
-               lcr_h &= ~UART01x_LCRH_BRK;
-       writel(lcr_h, uap->port.membase + UART010_LCRH);
-       spin_unlock_irqrestore(&uap->port.lock, flags);
-}
-
-static int pl010_startup(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       int retval;
-
-       /*
-        * Try to enable the clock producer.
-        */
-       retval = clk_enable(uap->clk);
-       if (retval)
-               goto out;
-
-       uap->port.uartclk = clk_get_rate(uap->clk);
-
-       /*
-        * Allocate the IRQ
-        */
-       retval = request_irq(uap->port.irq, pl010_int, 0, "uart-pl010", uap);
-       if (retval)
-               goto clk_dis;
-
-       /*
-        * initialise the old status of the modem signals
-        */
-       uap->old_status = readb(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
-
-       /*
-        * Finally, enable interrupts
-        */
-       writel(UART01x_CR_UARTEN | UART010_CR_RIE | UART010_CR_RTIE,
-              uap->port.membase + UART010_CR);
-
-       return 0;
-
- clk_dis:
-       clk_disable(uap->clk);
- out:
-       return retval;
-}
-
-static void pl010_shutdown(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-
-       /*
-        * Free the interrupt
-        */
-       free_irq(uap->port.irq, uap);
-
-       /*
-        * disable all interrupts, disable the port
-        */
-       writel(0, uap->port.membase + UART010_CR);
-
-       /* disable break condition and fifos */
-       writel(readb(uap->port.membase + UART010_LCRH) &
-               ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN),
-              uap->port.membase + UART010_LCRH);
-
-       /*
-        * Shut down the clock producer
-        */
-       clk_disable(uap->clk);
-}
-
-static void
-pl010_set_termios(struct uart_port *port, struct ktermios *termios,
-                    struct ktermios *old)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int lcr_h, old_cr;
-       unsigned long flags;
-       unsigned int baud, quot;
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old, 0, uap->port.uartclk/16); 
-       quot = uart_get_divisor(port, baud);
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               lcr_h = UART01x_LCRH_WLEN_5;
-               break;
-       case CS6:
-               lcr_h = UART01x_LCRH_WLEN_6;
-               break;
-       case CS7:
-               lcr_h = UART01x_LCRH_WLEN_7;
-               break;
-       default: // CS8
-               lcr_h = UART01x_LCRH_WLEN_8;
-               break;
-       }
-       if (termios->c_cflag & CSTOPB)
-               lcr_h |= UART01x_LCRH_STP2;
-       if (termios->c_cflag & PARENB) {
-               lcr_h |= UART01x_LCRH_PEN;
-               if (!(termios->c_cflag & PARODD))
-                       lcr_h |= UART01x_LCRH_EPS;
-       }
-       if (uap->port.fifosize > 1)
-               lcr_h |= UART01x_LCRH_FEN;
-
-       spin_lock_irqsave(&uap->port.lock, flags);
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       uap->port.read_status_mask = UART01x_RSR_OE;
-       if (termios->c_iflag & INPCK)
-               uap->port.read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               uap->port.read_status_mask |= UART01x_RSR_BE;
-
-       /*
-        * Characters to ignore
-        */
-       uap->port.ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               uap->port.ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
-       if (termios->c_iflag & IGNBRK) {
-               uap->port.ignore_status_mask |= UART01x_RSR_BE;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       uap->port.ignore_status_mask |= UART01x_RSR_OE;
-       }
-
-       /*
-        * Ignore all characters if CREAD is not set.
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               uap->port.ignore_status_mask |= UART_DUMMY_RSR_RX;
-
-       /* first, disable everything */
-       old_cr = readb(uap->port.membase + UART010_CR) & ~UART010_CR_MSIE;
-
-       if (UART_ENABLE_MS(port, termios->c_cflag))
-               old_cr |= UART010_CR_MSIE;
-
-       writel(0, uap->port.membase + UART010_CR);
-
-       /* Set baud rate */
-       quot -= 1;
-       writel((quot & 0xf00) >> 8, uap->port.membase + UART010_LCRM);
-       writel(quot & 0xff, uap->port.membase + UART010_LCRL);
-
-       /*
-        * ----------v----------v----------v----------v-----
-        * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
-        * ----------^----------^----------^----------^-----
-        */
-       writel(lcr_h, uap->port.membase + UART010_LCRH);
-       writel(old_cr, uap->port.membase + UART010_CR);
-
-       spin_unlock_irqrestore(&uap->port.lock, flags);
-}
-
-static void pl010_set_ldisc(struct uart_port *port, int new)
-{
-       if (new == N_PPS) {
-               port->flags |= UPF_HARDPPS_CD;
-               pl010_enable_ms(port);
-       } else
-               port->flags &= ~UPF_HARDPPS_CD;
-}
-
-static const char *pl010_type(struct uart_port *port)
-{
-       return port->type == PORT_AMBA ? "AMBA" : NULL;
-}
-
-/*
- * Release the memory region(s) being used by 'port'
- */
-static void pl010_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 pl010_request_port(struct uart_port *port)
-{
-       return request_mem_region(port->mapbase, UART_PORT_SIZE, "uart-pl010")
-                       != NULL ? 0 : -EBUSY;
-}
-
-/*
- * Configure/autoconfigure the port.
- */
-static void pl010_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE) {
-               port->type = PORT_AMBA;
-               pl010_request_port(port);
-       }
-}
-
-/*
- * verify the new serial_struct (for TIOCSSERIAL).
- */
-static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       int ret = 0;
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
-               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 amba_pl010_pops = {
-       .tx_empty       = pl010_tx_empty,
-       .set_mctrl      = pl010_set_mctrl,
-       .get_mctrl      = pl010_get_mctrl,
-       .stop_tx        = pl010_stop_tx,
-       .start_tx       = pl010_start_tx,
-       .stop_rx        = pl010_stop_rx,
-       .enable_ms      = pl010_enable_ms,
-       .break_ctl      = pl010_break_ctl,
-       .startup        = pl010_startup,
-       .shutdown       = pl010_shutdown,
-       .set_termios    = pl010_set_termios,
-       .set_ldisc      = pl010_set_ldisc,
-       .type           = pl010_type,
-       .release_port   = pl010_release_port,
-       .request_port   = pl010_request_port,
-       .config_port    = pl010_config_port,
-       .verify_port    = pl010_verify_port,
-};
-
-static struct uart_amba_port *amba_ports[UART_NR];
-
-#ifdef CONFIG_SERIAL_AMBA_PL010_CONSOLE
-
-static void pl010_console_putchar(struct uart_port *port, int ch)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int status;
-
-       do {
-               status = readb(uap->port.membase + UART01x_FR);
-               barrier();
-       } while (!UART_TX_READY(status));
-       writel(ch, uap->port.membase + UART01x_DR);
-}
-
-static void
-pl010_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct uart_amba_port *uap = amba_ports[co->index];
-       unsigned int status, old_cr;
-
-       clk_enable(uap->clk);
-
-       /*
-        *      First save the CR then disable the interrupts
-        */
-       old_cr = readb(uap->port.membase + UART010_CR);
-       writel(UART01x_CR_UARTEN, uap->port.membase + UART010_CR);
-
-       uart_console_write(&uap->port, s, count, pl010_console_putchar);
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore the TCR
-        */
-       do {
-               status = readb(uap->port.membase + UART01x_FR);
-               barrier();
-       } while (status & UART01x_FR_BUSY);
-       writel(old_cr, uap->port.membase + UART010_CR);
-
-       clk_disable(uap->clk);
-}
-
-static void __init
-pl010_console_get_options(struct uart_amba_port *uap, int *baud,
-                            int *parity, int *bits)
-{
-       if (readb(uap->port.membase + UART010_CR) & UART01x_CR_UARTEN) {
-               unsigned int lcr_h, quot;
-               lcr_h = readb(uap->port.membase + UART010_LCRH);
-
-               *parity = 'n';
-               if (lcr_h & UART01x_LCRH_PEN) {
-                       if (lcr_h & UART01x_LCRH_EPS)
-                               *parity = 'e';
-                       else
-                               *parity = 'o';
-               }
-
-               if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7)
-                       *bits = 7;
-               else
-                       *bits = 8;
-
-               quot = readb(uap->port.membase + UART010_LCRL) |
-                      readb(uap->port.membase + UART010_LCRM) << 8;
-               *baud = uap->port.uartclk / (16 * (quot + 1));
-       }
-}
-
-static int __init pl010_console_setup(struct console *co, char *options)
-{
-       struct uart_amba_port *uap;
-       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.
-        */
-       if (co->index >= UART_NR)
-               co->index = 0;
-       uap = amba_ports[co->index];
-       if (!uap)
-               return -ENODEV;
-
-       uap->port.uartclk = clk_get_rate(uap->clk);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               pl010_console_get_options(uap, &baud, &parity, &bits);
-
-       return uart_set_options(&uap->port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver amba_reg;
-static struct console amba_console = {
-       .name           = "ttyAM",
-       .write          = pl010_console_write,
-       .device         = uart_console_device,
-       .setup          = pl010_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &amba_reg,
-};
-
-#define AMBA_CONSOLE   &amba_console
-#else
-#define AMBA_CONSOLE   NULL
-#endif
-
-static struct uart_driver amba_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "ttyAM",
-       .dev_name               = "ttyAM",
-       .major                  = SERIAL_AMBA_MAJOR,
-       .minor                  = SERIAL_AMBA_MINOR,
-       .nr                     = UART_NR,
-       .cons                   = AMBA_CONSOLE,
-};
-
-static int pl010_probe(struct amba_device *dev, struct amba_id *id)
-{
-       struct uart_amba_port *uap;
-       void __iomem *base;
-       int i, ret;
-
-       for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
-               if (amba_ports[i] == NULL)
-                       break;
-
-       if (i == ARRAY_SIZE(amba_ports)) {
-               ret = -EBUSY;
-               goto out;
-       }
-
-       uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
-       if (!uap) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       base = ioremap(dev->res.start, resource_size(&dev->res));
-       if (!base) {
-               ret = -ENOMEM;
-               goto free;
-       }
-
-       uap->clk = clk_get(&dev->dev, NULL);
-       if (IS_ERR(uap->clk)) {
-               ret = PTR_ERR(uap->clk);
-               goto unmap;
-       }
-
-       uap->port.dev = &dev->dev;
-       uap->port.mapbase = dev->res.start;
-       uap->port.membase = base;
-       uap->port.iotype = UPIO_MEM;
-       uap->port.irq = dev->irq[0];
-       uap->port.fifosize = 16;
-       uap->port.ops = &amba_pl010_pops;
-       uap->port.flags = UPF_BOOT_AUTOCONF;
-       uap->port.line = i;
-       uap->dev = dev;
-       uap->data = dev->dev.platform_data;
-
-       amba_ports[i] = uap;
-
-       amba_set_drvdata(dev, uap);
-       ret = uart_add_one_port(&amba_reg, &uap->port);
-       if (ret) {
-               amba_set_drvdata(dev, NULL);
-               amba_ports[i] = NULL;
-               clk_put(uap->clk);
- unmap:
-               iounmap(base);
- free:
-               kfree(uap);
-       }
- out:
-       return ret;
-}
-
-static int pl010_remove(struct amba_device *dev)
-{
-       struct uart_amba_port *uap = amba_get_drvdata(dev);
-       int i;
-
-       amba_set_drvdata(dev, NULL);
-
-       uart_remove_one_port(&amba_reg, &uap->port);
-
-       for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
-               if (amba_ports[i] == uap)
-                       amba_ports[i] = NULL;
-
-       iounmap(uap->port.membase);
-       clk_put(uap->clk);
-       kfree(uap);
-       return 0;
-}
-
-static int pl010_suspend(struct amba_device *dev, pm_message_t state)
-{
-       struct uart_amba_port *uap = amba_get_drvdata(dev);
-
-       if (uap)
-               uart_suspend_port(&amba_reg, &uap->port);
-
-       return 0;
-}
-
-static int pl010_resume(struct amba_device *dev)
-{
-       struct uart_amba_port *uap = amba_get_drvdata(dev);
-
-       if (uap)
-               uart_resume_port(&amba_reg, &uap->port);
-
-       return 0;
-}
-
-static struct amba_id pl010_ids[] = {
-       {
-               .id     = 0x00041010,
-               .mask   = 0x000fffff,
-       },
-       { 0, 0 },
-};
-
-static struct amba_driver pl010_driver = {
-       .drv = {
-               .name   = "uart-pl010",
-       },
-       .id_table       = pl010_ids,
-       .probe          = pl010_probe,
-       .remove         = pl010_remove,
-       .suspend        = pl010_suspend,
-       .resume         = pl010_resume,
-};
-
-static int __init pl010_init(void)
-{
-       int ret;
-
-       printk(KERN_INFO "Serial: AMBA driver\n");
-
-       ret = uart_register_driver(&amba_reg);
-       if (ret == 0) {
-               ret = amba_driver_register(&pl010_driver);
-               if (ret)
-                       uart_unregister_driver(&amba_reg);
-       }
-       return ret;
-}
-
-static void __exit pl010_exit(void)
-{
-       amba_driver_unregister(&pl010_driver);
-       uart_unregister_driver(&amba_reg);
-}
-
-module_init(pl010_init);
-module_exit(pl010_exit);
-
-MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd");
-MODULE_DESCRIPTION("ARM AMBA serial port driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
deleted file mode 100644 (file)
index e76d7d0..0000000
+++ /dev/null
@@ -1,1519 +0,0 @@
-/*
- *  linux/drivers/char/amba.c
- *
- *  Driver for AMBA serial ports
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *
- *  Copyright 1999 ARM Limited
- *  Copyright (C) 2000 Deep Blue Solutions Ltd.
- *  Copyright (C) 2010 ST-Ericsson SA
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * This is a generic driver for ARM AMBA-type serial ports.  They
- * have a lot of 16550-like features, but are not register compatible.
- * Note that although they do have CTS, DCD and DSR inputs, they do
- * not have an RI input, nor do they have DTR or RTS outputs.  If
- * required, these have to be supplied via some other means (eg, GPIO)
- * and hooked into this driver.
- */
-
-#if defined(CONFIG_SERIAL_AMBA_PL011_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/amba/bus.h>
-#include <linux/amba/serial.h>
-#include <linux/clk.h>
-#include <linux/slab.h>
-#include <linux/dmaengine.h>
-#include <linux/dma-mapping.h>
-#include <linux/scatterlist.h>
-
-#include <asm/io.h>
-#include <asm/sizes.h>
-
-#define UART_NR                        14
-
-#define SERIAL_AMBA_MAJOR      204
-#define SERIAL_AMBA_MINOR      64
-#define SERIAL_AMBA_NR         UART_NR
-
-#define AMBA_ISR_PASS_LIMIT    256
-
-#define UART_DR_ERROR          (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)
-#define UART_DUMMY_DR_RX       (1 << 16)
-
-/* There is by now at least one vendor with differing details, so handle it */
-struct vendor_data {
-       unsigned int            ifls;
-       unsigned int            fifosize;
-       unsigned int            lcrh_tx;
-       unsigned int            lcrh_rx;
-       bool                    oversampling;
-       bool                    dma_threshold;
-};
-
-static struct vendor_data vendor_arm = {
-       .ifls                   = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
-       .fifosize               = 16,
-       .lcrh_tx                = UART011_LCRH,
-       .lcrh_rx                = UART011_LCRH,
-       .oversampling           = false,
-       .dma_threshold          = false,
-};
-
-static struct vendor_data vendor_st = {
-       .ifls                   = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF,
-       .fifosize               = 64,
-       .lcrh_tx                = ST_UART011_LCRH_TX,
-       .lcrh_rx                = ST_UART011_LCRH_RX,
-       .oversampling           = true,
-       .dma_threshold          = true,
-};
-
-/* Deals with DMA transactions */
-struct pl011_dmatx_data {
-       struct dma_chan         *chan;
-       struct scatterlist      sg;
-       char                    *buf;
-       bool                    queued;
-};
-
-/*
- * We wrap our port structure around the generic uart_port.
- */
-struct uart_amba_port {
-       struct uart_port        port;
-       struct clk              *clk;
-       const struct vendor_data *vendor;
-       unsigned int            dmacr;          /* dma control reg */
-       unsigned int            im;             /* interrupt mask */
-       unsigned int            old_status;
-       unsigned int            fifosize;       /* vendor-specific */
-       unsigned int            lcrh_tx;        /* vendor-specific */
-       unsigned int            lcrh_rx;        /* vendor-specific */
-       bool                    autorts;
-       char                    type[12];
-#ifdef CONFIG_DMA_ENGINE
-       /* DMA stuff */
-       bool                    using_dma;
-       struct pl011_dmatx_data dmatx;
-#endif
-};
-
-/*
- * All the DMA operation mode stuff goes inside this ifdef.
- * This assumes that you have a generic DMA device interface,
- * no custom DMA interfaces are supported.
- */
-#ifdef CONFIG_DMA_ENGINE
-
-#define PL011_DMA_BUFFER_SIZE PAGE_SIZE
-
-static void pl011_dma_probe_initcall(struct uart_amba_port *uap)
-{
-       /* DMA is the sole user of the platform data right now */
-       struct amba_pl011_data *plat = uap->port.dev->platform_data;
-       struct dma_slave_config tx_conf = {
-               .dst_addr = uap->port.mapbase + UART01x_DR,
-               .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
-               .direction = DMA_TO_DEVICE,
-               .dst_maxburst = uap->fifosize >> 1,
-       };
-       struct dma_chan *chan;
-       dma_cap_mask_t mask;
-
-       /* We need platform data */
-       if (!plat || !plat->dma_filter) {
-               dev_info(uap->port.dev, "no DMA platform data\n");
-               return;
-       }
-
-       /* Try to acquire a generic DMA engine slave channel */
-       dma_cap_zero(mask);
-       dma_cap_set(DMA_SLAVE, mask);
-
-       chan = dma_request_channel(mask, plat->dma_filter, plat->dma_tx_param);
-       if (!chan) {
-               dev_err(uap->port.dev, "no TX DMA channel!\n");
-               return;
-       }
-
-       dmaengine_slave_config(chan, &tx_conf);
-       uap->dmatx.chan = chan;
-
-       dev_info(uap->port.dev, "DMA channel TX %s\n",
-                dma_chan_name(uap->dmatx.chan));
-}
-
-#ifndef MODULE
-/*
- * Stack up the UARTs and let the above initcall be done at device
- * initcall time, because the serial driver is called as an arch
- * initcall, and at this time the DMA subsystem is not yet registered.
- * At this point the driver will switch over to using DMA where desired.
- */
-struct dma_uap {
-       struct list_head node;
-       struct uart_amba_port *uap;
-};
-
-static LIST_HEAD(pl011_dma_uarts);
-
-static int __init pl011_dma_initcall(void)
-{
-       struct list_head *node, *tmp;
-
-       list_for_each_safe(node, tmp, &pl011_dma_uarts) {
-               struct dma_uap *dmau = list_entry(node, struct dma_uap, node);
-               pl011_dma_probe_initcall(dmau->uap);
-               list_del(node);
-               kfree(dmau);
-       }
-       return 0;
-}
-
-device_initcall(pl011_dma_initcall);
-
-static void pl011_dma_probe(struct uart_amba_port *uap)
-{
-       struct dma_uap *dmau = kzalloc(sizeof(struct dma_uap), GFP_KERNEL);
-       if (dmau) {
-               dmau->uap = uap;
-               list_add_tail(&dmau->node, &pl011_dma_uarts);
-       }
-}
-#else
-static void pl011_dma_probe(struct uart_amba_port *uap)
-{
-       pl011_dma_probe_initcall(uap);
-}
-#endif
-
-static void pl011_dma_remove(struct uart_amba_port *uap)
-{
-       /* TODO: remove the initcall if it has not yet executed */
-       if (uap->dmatx.chan)
-               dma_release_channel(uap->dmatx.chan);
-}
-
-
-/* Forward declare this for the refill routine */
-static int pl011_dma_tx_refill(struct uart_amba_port *uap);
-
-/*
- * The current DMA TX buffer has been sent.
- * Try to queue up another DMA buffer.
- */
-static void pl011_dma_tx_callback(void *data)
-{
-       struct uart_amba_port *uap = data;
-       struct pl011_dmatx_data *dmatx = &uap->dmatx;
-       unsigned long flags;
-       u16 dmacr;
-
-       spin_lock_irqsave(&uap->port.lock, flags);
-       if (uap->dmatx.queued)
-               dma_unmap_sg(dmatx->chan->device->dev, &dmatx->sg, 1,
-                            DMA_TO_DEVICE);
-
-       dmacr = uap->dmacr;
-       uap->dmacr = dmacr & ~UART011_TXDMAE;
-       writew(uap->dmacr, uap->port.membase + UART011_DMACR);
-
-       /*
-        * If TX DMA was disabled, it means that we've stopped the DMA for
-        * some reason (eg, XOFF received, or we want to send an X-char.)
-        *
-        * Note: we need to be careful here of a potential race between DMA
-        * and the rest of the driver - if the driver disables TX DMA while
-        * a TX buffer completing, we must update the tx queued status to
-        * get further refills (hence we check dmacr).
-        */
-       if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) ||
-           uart_circ_empty(&uap->port.state->xmit)) {
-               uap->dmatx.queued = false;
-               spin_unlock_irqrestore(&uap->port.lock, flags);
-               return;
-       }
-
-       if (pl011_dma_tx_refill(uap) <= 0) {
-               /*
-                * We didn't queue a DMA buffer for some reason, but we
-                * have data pending to be sent.  Re-enable the TX IRQ.
-                */
-               uap->im |= UART011_TXIM;
-               writew(uap->im, uap->port.membase + UART011_IMSC);
-       }
-       spin_unlock_irqrestore(&uap->port.lock, flags);
-}
-
-/*
- * Try to refill the TX DMA buffer.
- * Locking: called with port lock held and IRQs disabled.
- * Returns:
- *   1 if we queued up a TX DMA buffer.
- *   0 if we didn't want to handle this by DMA
- *  <0 on error
- */
-static int pl011_dma_tx_refill(struct uart_amba_port *uap)
-{
-       struct pl011_dmatx_data *dmatx = &uap->dmatx;
-       struct dma_chan *chan = dmatx->chan;
-       struct dma_device *dma_dev = chan->device;
-       struct dma_async_tx_descriptor *desc;
-       struct circ_buf *xmit = &uap->port.state->xmit;
-       unsigned int count;
-
-       /*
-        * Try to avoid the overhead involved in using DMA if the
-        * transaction fits in the first half of the FIFO, by using
-        * the standard interrupt handling.  This ensures that we
-        * issue a uart_write_wakeup() at the appropriate time.
-        */
-       count = uart_circ_chars_pending(xmit);
-       if (count < (uap->fifosize >> 1)) {
-               uap->dmatx.queued = false;
-               return 0;
-       }
-
-       /*
-        * Bodge: don't send the last character by DMA, as this
-        * will prevent XON from notifying us to restart DMA.
-        */
-       count -= 1;
-
-       /* Else proceed to copy the TX chars to the DMA buffer and fire DMA */
-       if (count > PL011_DMA_BUFFER_SIZE)
-               count = PL011_DMA_BUFFER_SIZE;
-
-       if (xmit->tail < xmit->head)
-               memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], count);
-       else {
-               size_t first = UART_XMIT_SIZE - xmit->tail;
-               size_t second = xmit->head;
-
-               memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], first);
-               if (second)
-                       memcpy(&dmatx->buf[first], &xmit->buf[0], second);
-       }
-
-       dmatx->sg.length = count;
-
-       if (dma_map_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE) != 1) {
-               uap->dmatx.queued = false;
-               dev_dbg(uap->port.dev, "unable to map TX DMA\n");
-               return -EBUSY;
-       }
-
-       desc = dma_dev->device_prep_slave_sg(chan, &dmatx->sg, 1, DMA_TO_DEVICE,
-                                            DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-       if (!desc) {
-               dma_unmap_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE);
-               uap->dmatx.queued = false;
-               /*
-                * If DMA cannot be used right now, we complete this
-                * transaction via IRQ and let the TTY layer retry.
-                */
-               dev_dbg(uap->port.dev, "TX DMA busy\n");
-               return -EBUSY;
-       }
-
-       /* Some data to go along to the callback */
-       desc->callback = pl011_dma_tx_callback;
-       desc->callback_param = uap;
-
-       /* All errors should happen at prepare time */
-       dmaengine_submit(desc);
-
-       /* Fire the DMA transaction */
-       dma_dev->device_issue_pending(chan);
-
-       uap->dmacr |= UART011_TXDMAE;
-       writew(uap->dmacr, uap->port.membase + UART011_DMACR);
-       uap->dmatx.queued = true;
-
-       /*
-        * Now we know that DMA will fire, so advance the ring buffer
-        * with the stuff we just dispatched.
-        */
-       xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
-       uap->port.icount.tx += count;
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&uap->port);
-
-       return 1;
-}
-
-/*
- * We received a transmit interrupt without a pending X-char but with
- * pending characters.
- * Locking: called with port lock held and IRQs disabled.
- * Returns:
- *   false if we want to use PIO to transmit
- *   true if we queued a DMA buffer
- */
-static bool pl011_dma_tx_irq(struct uart_amba_port *uap)
-{
-       if (!uap->using_dma)
-               return false;
-
-       /*
-        * If we already have a TX buffer queued, but received a
-        * TX interrupt, it will be because we've just sent an X-char.
-        * Ensure the TX DMA is enabled and the TX IRQ is disabled.
-        */
-       if (uap->dmatx.queued) {
-               uap->dmacr |= UART011_TXDMAE;
-               writew(uap->dmacr, uap->port.membase + UART011_DMACR);
-               uap->im &= ~UART011_TXIM;
-               writew(uap->im, uap->port.membase + UART011_IMSC);
-               return true;
-       }
-
-       /*
-        * We don't have a TX buffer queued, so try to queue one.
-        * If we succesfully queued a buffer, mask the TX IRQ.
-        */
-       if (pl011_dma_tx_refill(uap) > 0) {
-               uap->im &= ~UART011_TXIM;
-               writew(uap->im, uap->port.membase + UART011_IMSC);
-               return true;
-       }
-       return false;
-}
-
-/*
- * Stop the DMA transmit (eg, due to received XOFF).
- * Locking: called with port lock held and IRQs disabled.
- */
-static inline void pl011_dma_tx_stop(struct uart_amba_port *uap)
-{
-       if (uap->dmatx.queued) {
-               uap->dmacr &= ~UART011_TXDMAE;
-               writew(uap->dmacr, uap->port.membase + UART011_DMACR);
-       }
-}
-
-/*
- * Try to start a DMA transmit, or in the case of an XON/OFF
- * character queued for send, try to get that character out ASAP.
- * Locking: called with port lock held and IRQs disabled.
- * Returns:
- *   false if we want the TX IRQ to be enabled
- *   true if we have a buffer queued
- */
-static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
-{
-       u16 dmacr;
-
-       if (!uap->using_dma)
-               return false;
-
-       if (!uap->port.x_char) {
-               /* no X-char, try to push chars out in DMA mode */
-               bool ret = true;
-
-               if (!uap->dmatx.queued) {
-                       if (pl011_dma_tx_refill(uap) > 0) {
-                               uap->im &= ~UART011_TXIM;
-                               ret = true;
-                       } else {
-                               uap->im |= UART011_TXIM;
-                               ret = false;
-                       }
-                       writew(uap->im, uap->port.membase + UART011_IMSC);
-               } else if (!(uap->dmacr & UART011_TXDMAE)) {
-                       uap->dmacr |= UART011_TXDMAE;
-                       writew(uap->dmacr,
-                                      uap->port.membase + UART011_DMACR);
-               }
-               return ret;
-       }
-
-       /*
-        * We have an X-char to send.  Disable DMA to prevent it loading
-        * the TX fifo, and then see if we can stuff it into the FIFO.
-        */
-       dmacr = uap->dmacr;
-       uap->dmacr &= ~UART011_TXDMAE;
-       writew(uap->dmacr, uap->port.membase + UART011_DMACR);
-
-       if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) {
-               /*
-                * No space in the FIFO, so enable the transmit interrupt
-                * so we know when there is space.  Note that once we've
-                * loaded the character, we should just re-enable DMA.
-                */
-               return false;
-       }
-
-       writew(uap->port.x_char, uap->port.membase + UART01x_DR);
-       uap->port.icount.tx++;
-       uap->port.x_char = 0;
-
-       /* Success - restore the DMA state */
-       uap->dmacr = dmacr;
-       writew(dmacr, uap->port.membase + UART011_DMACR);
-
-       return true;
-}
-
-/*
- * Flush the transmit buffer.
- * Locking: called with port lock held and IRQs disabled.
- */
-static void pl011_dma_flush_buffer(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-
-       if (!uap->using_dma)
-               return;
-
-       /* Avoid deadlock with the DMA engine callback */
-       spin_unlock(&uap->port.lock);
-       dmaengine_terminate_all(uap->dmatx.chan);
-       spin_lock(&uap->port.lock);
-       if (uap->dmatx.queued) {
-               dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1,
-                            DMA_TO_DEVICE);
-               uap->dmatx.queued = false;
-               uap->dmacr &= ~UART011_TXDMAE;
-               writew(uap->dmacr, uap->port.membase + UART011_DMACR);
-       }
-}
-
-
-static void pl011_dma_startup(struct uart_amba_port *uap)
-{
-       if (!uap->dmatx.chan)
-               return;
-
-       uap->dmatx.buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL);
-       if (!uap->dmatx.buf) {
-               dev_err(uap->port.dev, "no memory for DMA TX buffer\n");
-               uap->port.fifosize = uap->fifosize;
-               return;
-       }
-
-       sg_init_one(&uap->dmatx.sg, uap->dmatx.buf, PL011_DMA_BUFFER_SIZE);
-
-       /* The DMA buffer is now the FIFO the TTY subsystem can use */
-       uap->port.fifosize = PL011_DMA_BUFFER_SIZE;
-       uap->using_dma = true;
-
-       /* Turn on DMA error (RX/TX will be enabled on demand) */
-       uap->dmacr |= UART011_DMAONERR;
-       writew(uap->dmacr, uap->port.membase + UART011_DMACR);
-
-       /*
-        * ST Micro variants has some specific dma burst threshold
-        * compensation. Set this to 16 bytes, so burst will only
-        * be issued above/below 16 bytes.
-        */
-       if (uap->vendor->dma_threshold)
-               writew(ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16,
-                              uap->port.membase + ST_UART011_DMAWM);
-}
-
-static void pl011_dma_shutdown(struct uart_amba_port *uap)
-{
-       if (!uap->using_dma)
-               return;
-
-       /* Disable RX and TX DMA */
-       while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
-               barrier();
-
-       spin_lock_irq(&uap->port.lock);
-       uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE);
-       writew(uap->dmacr, uap->port.membase + UART011_DMACR);
-       spin_unlock_irq(&uap->port.lock);
-
-       /* In theory, this should already be done by pl011_dma_flush_buffer */
-       dmaengine_terminate_all(uap->dmatx.chan);
-       if (uap->dmatx.queued) {
-               dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1,
-                            DMA_TO_DEVICE);
-               uap->dmatx.queued = false;
-       }
-
-       kfree(uap->dmatx.buf);
-
-       uap->using_dma = false;
-}
-
-#else
-/* Blank functions if the DMA engine is not available */
-static inline void pl011_dma_probe(struct uart_amba_port *uap)
-{
-}
-
-static inline void pl011_dma_remove(struct uart_amba_port *uap)
-{
-}
-
-static inline void pl011_dma_startup(struct uart_amba_port *uap)
-{
-}
-
-static inline void pl011_dma_shutdown(struct uart_amba_port *uap)
-{
-}
-
-static inline bool pl011_dma_tx_irq(struct uart_amba_port *uap)
-{
-       return false;
-}
-
-static inline void pl011_dma_tx_stop(struct uart_amba_port *uap)
-{
-}
-
-static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
-{
-       return false;
-}
-
-#define pl011_dma_flush_buffer NULL
-#endif
-
-
-static void pl011_stop_tx(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-
-       uap->im &= ~UART011_TXIM;
-       writew(uap->im, uap->port.membase + UART011_IMSC);
-       pl011_dma_tx_stop(uap);
-}
-
-static void pl011_start_tx(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-
-       if (!pl011_dma_tx_start(uap)) {
-               uap->im |= UART011_TXIM;
-               writew(uap->im, uap->port.membase + UART011_IMSC);
-       }
-}
-
-static void pl011_stop_rx(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-
-       uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM|
-                    UART011_PEIM|UART011_BEIM|UART011_OEIM);
-       writew(uap->im, uap->port.membase + UART011_IMSC);
-}
-
-static void pl011_enable_ms(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-
-       uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM;
-       writew(uap->im, uap->port.membase + UART011_IMSC);
-}
-
-static void pl011_rx_chars(struct uart_amba_port *uap)
-{
-       struct tty_struct *tty = uap->port.state->port.tty;
-       unsigned int status, ch, flag, max_count = 256;
-
-       status = readw(uap->port.membase + UART01x_FR);
-       while ((status & UART01x_FR_RXFE) == 0 && max_count--) {
-               ch = readw(uap->port.membase + UART01x_DR) | UART_DUMMY_DR_RX;
-               flag = TTY_NORMAL;
-               uap->port.icount.rx++;
-
-               /*
-                * Note that the error handling code is
-                * out of the main execution path
-                */
-               if (unlikely(ch & UART_DR_ERROR)) {
-                       if (ch & UART011_DR_BE) {
-                               ch &= ~(UART011_DR_FE | UART011_DR_PE);
-                               uap->port.icount.brk++;
-                               if (uart_handle_break(&uap->port))
-                                       goto ignore_char;
-                       } else if (ch & UART011_DR_PE)
-                               uap->port.icount.parity++;
-                       else if (ch & UART011_DR_FE)
-                               uap->port.icount.frame++;
-                       if (ch & UART011_DR_OE)
-                               uap->port.icount.overrun++;
-
-                       ch &= uap->port.read_status_mask;
-
-                       if (ch & UART011_DR_BE)
-                               flag = TTY_BREAK;
-                       else if (ch & UART011_DR_PE)
-                               flag = TTY_PARITY;
-                       else if (ch & UART011_DR_FE)
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(&uap->port, ch & 255))
-                       goto ignore_char;
-
-               uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag);
-
-       ignore_char:
-               status = readw(uap->port.membase + UART01x_FR);
-       }
-       spin_unlock(&uap->port.lock);
-       tty_flip_buffer_push(tty);
-       spin_lock(&uap->port.lock);
-}
-
-static void pl011_tx_chars(struct uart_amba_port *uap)
-{
-       struct circ_buf *xmit = &uap->port.state->xmit;
-       int count;
-
-       if (uap->port.x_char) {
-               writew(uap->port.x_char, uap->port.membase + UART01x_DR);
-               uap->port.icount.tx++;
-               uap->port.x_char = 0;
-               return;
-       }
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) {
-               pl011_stop_tx(&uap->port);
-               return;
-       }
-
-       /* If we are using DMA mode, try to send some characters. */
-       if (pl011_dma_tx_irq(uap))
-               return;
-
-       count = uap->fifosize >> 1;
-       do {
-               writew(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               uap->port.icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (--count > 0);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&uap->port);
-
-       if (uart_circ_empty(xmit))
-               pl011_stop_tx(&uap->port);
-}
-
-static void pl011_modem_status(struct uart_amba_port *uap)
-{
-       unsigned int status, delta;
-
-       status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
-
-       delta = status ^ uap->old_status;
-       uap->old_status = status;
-
-       if (!delta)
-               return;
-
-       if (delta & UART01x_FR_DCD)
-               uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD);
-
-       if (delta & UART01x_FR_DSR)
-               uap->port.icount.dsr++;
-
-       if (delta & UART01x_FR_CTS)
-               uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS);
-
-       wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
-}
-
-static irqreturn_t pl011_int(int irq, void *dev_id)
-{
-       struct uart_amba_port *uap = dev_id;
-       unsigned long flags;
-       unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
-       int handled = 0;
-
-       spin_lock_irqsave(&uap->port.lock, flags);
-
-       status = readw(uap->port.membase + UART011_MIS);
-       if (status) {
-               do {
-                       writew(status & ~(UART011_TXIS|UART011_RTIS|
-                                         UART011_RXIS),
-                              uap->port.membase + UART011_ICR);
-
-                       if (status & (UART011_RTIS|UART011_RXIS))
-                               pl011_rx_chars(uap);
-                       if (status & (UART011_DSRMIS|UART011_DCDMIS|
-                                     UART011_CTSMIS|UART011_RIMIS))
-                               pl011_modem_status(uap);
-                       if (status & UART011_TXIS)
-                               pl011_tx_chars(uap);
-
-                       if (pass_counter-- == 0)
-                               break;
-
-                       status = readw(uap->port.membase + UART011_MIS);
-               } while (status != 0);
-               handled = 1;
-       }
-
-       spin_unlock_irqrestore(&uap->port.lock, flags);
-
-       return IRQ_RETVAL(handled);
-}
-
-static unsigned int pl01x_tx_empty(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int status = readw(uap->port.membase + UART01x_FR);
-       return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT;
-}
-
-static unsigned int pl01x_get_mctrl(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int result = 0;
-       unsigned int status = readw(uap->port.membase + UART01x_FR);
-
-#define TIOCMBIT(uartbit, tiocmbit)    \
-       if (status & uartbit)           \
-               result |= tiocmbit
-
-       TIOCMBIT(UART01x_FR_DCD, TIOCM_CAR);
-       TIOCMBIT(UART01x_FR_DSR, TIOCM_DSR);
-       TIOCMBIT(UART01x_FR_CTS, TIOCM_CTS);
-       TIOCMBIT(UART011_FR_RI, TIOCM_RNG);
-#undef TIOCMBIT
-       return result;
-}
-
-static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int cr;
-
-       cr = readw(uap->port.membase + UART011_CR);
-
-#define        TIOCMBIT(tiocmbit, uartbit)             \
-       if (mctrl & tiocmbit)           \
-               cr |= uartbit;          \
-       else                            \
-               cr &= ~uartbit
-
-       TIOCMBIT(TIOCM_RTS, UART011_CR_RTS);
-       TIOCMBIT(TIOCM_DTR, UART011_CR_DTR);
-       TIOCMBIT(TIOCM_OUT1, UART011_CR_OUT1);
-       TIOCMBIT(TIOCM_OUT2, UART011_CR_OUT2);
-       TIOCMBIT(TIOCM_LOOP, UART011_CR_LBE);
-
-       if (uap->autorts) {
-               /* We need to disable auto-RTS if we want to turn RTS off */
-               TIOCMBIT(TIOCM_RTS, UART011_CR_RTSEN);
-       }
-#undef TIOCMBIT
-
-       writew(cr, uap->port.membase + UART011_CR);
-}
-
-static void pl011_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned long flags;
-       unsigned int lcr_h;
-
-       spin_lock_irqsave(&uap->port.lock, flags);
-       lcr_h = readw(uap->port.membase + uap->lcrh_tx);
-       if (break_state == -1)
-               lcr_h |= UART01x_LCRH_BRK;
-       else
-               lcr_h &= ~UART01x_LCRH_BRK;
-       writew(lcr_h, uap->port.membase + uap->lcrh_tx);
-       spin_unlock_irqrestore(&uap->port.lock, flags);
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-static int pl010_get_poll_char(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int status;
-
-       status = readw(uap->port.membase + UART01x_FR);
-       if (status & UART01x_FR_RXFE)
-               return NO_POLL_CHAR;
-
-       return readw(uap->port.membase + UART01x_DR);
-}
-
-static void pl010_put_poll_char(struct uart_port *port,
-                        unsigned char ch)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-
-       while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
-               barrier();
-
-       writew(ch, uap->port.membase + UART01x_DR);
-}
-
-#endif /* CONFIG_CONSOLE_POLL */
-
-static int pl011_startup(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int cr;
-       int retval;
-
-       /*
-        * Try to enable the clock producer.
-        */
-       retval = clk_enable(uap->clk);
-       if (retval)
-               goto out;
-
-       uap->port.uartclk = clk_get_rate(uap->clk);
-
-       /*
-        * Allocate the IRQ
-        */
-       retval = request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
-       if (retval)
-               goto clk_dis;
-
-       writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS);
-
-       /*
-        * Provoke TX FIFO interrupt into asserting.
-        */
-       cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE;
-       writew(cr, uap->port.membase + UART011_CR);
-       writew(0, uap->port.membase + UART011_FBRD);
-       writew(1, uap->port.membase + UART011_IBRD);
-       writew(0, uap->port.membase + uap->lcrh_rx);
-       if (uap->lcrh_tx != uap->lcrh_rx) {
-               int i;
-               /*
-                * Wait 10 PCLKs before writing LCRH_TX register,
-                * to get this delay write read only register 10 times
-                */
-               for (i = 0; i < 10; ++i)
-                       writew(0xff, uap->port.membase + UART011_MIS);
-               writew(0, uap->port.membase + uap->lcrh_tx);
-       }
-       writew(0, uap->port.membase + UART01x_DR);
-       while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
-               barrier();
-
-       cr = UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE;
-       writew(cr, uap->port.membase + UART011_CR);
-
-       /* Clear pending error interrupts */
-       writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS,
-              uap->port.membase + UART011_ICR);
-
-       /*
-        * initialise the old status of the modem signals
-        */
-       uap->old_status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
-
-       /* Startup DMA */
-       pl011_dma_startup(uap);
-
-       /*
-        * Finally, enable interrupts
-        */
-       spin_lock_irq(&uap->port.lock);
-       uap->im = UART011_RXIM | UART011_RTIM;
-       writew(uap->im, uap->port.membase + UART011_IMSC);
-       spin_unlock_irq(&uap->port.lock);
-
-       return 0;
-
- clk_dis:
-       clk_disable(uap->clk);
- out:
-       return retval;
-}
-
-static void pl011_shutdown_channel(struct uart_amba_port *uap,
-                                       unsigned int lcrh)
-{
-      unsigned long val;
-
-      val = readw(uap->port.membase + lcrh);
-      val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN);
-      writew(val, uap->port.membase + lcrh);
-}
-
-static void pl011_shutdown(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-
-       /*
-        * disable all interrupts
-        */
-       spin_lock_irq(&uap->port.lock);
-       uap->im = 0;
-       writew(uap->im, uap->port.membase + UART011_IMSC);
-       writew(0xffff, uap->port.membase + UART011_ICR);
-       spin_unlock_irq(&uap->port.lock);
-
-       pl011_dma_shutdown(uap);
-
-       /*
-        * Free the interrupt
-        */
-       free_irq(uap->port.irq, uap);
-
-       /*
-        * disable the port
-        */
-       uap->autorts = false;
-       writew(UART01x_CR_UARTEN | UART011_CR_TXE, uap->port.membase + UART011_CR);
-
-       /*
-        * disable break condition and fifos
-        */
-       pl011_shutdown_channel(uap, uap->lcrh_rx);
-       if (uap->lcrh_rx != uap->lcrh_tx)
-               pl011_shutdown_channel(uap, uap->lcrh_tx);
-
-       /*
-        * Shut down the clock producer
-        */
-       clk_disable(uap->clk);
-}
-
-static void
-pl011_set_termios(struct uart_port *port, struct ktermios *termios,
-                    struct ktermios *old)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int lcr_h, old_cr;
-       unsigned long flags;
-       unsigned int baud, quot, clkdiv;
-
-       if (uap->vendor->oversampling)
-               clkdiv = 8;
-       else
-               clkdiv = 16;
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old, 0,
-                                 port->uartclk / clkdiv);
-
-       if (baud > port->uartclk/16)
-               quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud);
-       else
-               quot = DIV_ROUND_CLOSEST(port->uartclk * 4, baud);
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               lcr_h = UART01x_LCRH_WLEN_5;
-               break;
-       case CS6:
-               lcr_h = UART01x_LCRH_WLEN_6;
-               break;
-       case CS7:
-               lcr_h = UART01x_LCRH_WLEN_7;
-               break;
-       default: // CS8
-               lcr_h = UART01x_LCRH_WLEN_8;
-               break;
-       }
-       if (termios->c_cflag & CSTOPB)
-               lcr_h |= UART01x_LCRH_STP2;
-       if (termios->c_cflag & PARENB) {
-               lcr_h |= UART01x_LCRH_PEN;
-               if (!(termios->c_cflag & PARODD))
-                       lcr_h |= UART01x_LCRH_EPS;
-       }
-       if (uap->fifosize > 1)
-               lcr_h |= UART01x_LCRH_FEN;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       port->read_status_mask = UART011_DR_OE | 255;
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= UART011_DR_FE | UART011_DR_PE;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               port->read_status_mask |= UART011_DR_BE;
-
-       /*
-        * Characters to ignore
-        */
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= UART011_DR_FE | UART011_DR_PE;
-       if (termios->c_iflag & IGNBRK) {
-               port->ignore_status_mask |= UART011_DR_BE;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       port->ignore_status_mask |= UART011_DR_OE;
-       }
-
-       /*
-        * Ignore all characters if CREAD is not set.
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               port->ignore_status_mask |= UART_DUMMY_DR_RX;
-
-       if (UART_ENABLE_MS(port, termios->c_cflag))
-               pl011_enable_ms(port);
-
-       /* first, disable everything */
-       old_cr = readw(port->membase + UART011_CR);
-       writew(0, port->membase + UART011_CR);
-
-       if (termios->c_cflag & CRTSCTS) {
-               if (old_cr & UART011_CR_RTS)
-                       old_cr |= UART011_CR_RTSEN;
-
-               old_cr |= UART011_CR_CTSEN;
-               uap->autorts = true;
-       } else {
-               old_cr &= ~(UART011_CR_CTSEN | UART011_CR_RTSEN);
-               uap->autorts = false;
-       }
-
-       if (uap->vendor->oversampling) {
-               if (baud > port->uartclk / 16)
-                       old_cr |= ST_UART011_CR_OVSFACT;
-               else
-                       old_cr &= ~ST_UART011_CR_OVSFACT;
-       }
-
-       /* Set baud rate */
-       writew(quot & 0x3f, port->membase + UART011_FBRD);
-       writew(quot >> 6, port->membase + UART011_IBRD);
-
-       /*
-        * ----------v----------v----------v----------v-----
-        * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
-        * ----------^----------^----------^----------^-----
-        */
-       writew(lcr_h, port->membase + uap->lcrh_rx);
-       if (uap->lcrh_rx != uap->lcrh_tx) {
-               int i;
-               /*
-                * Wait 10 PCLKs before writing LCRH_TX register,
-                * to get this delay write read only register 10 times
-                */
-               for (i = 0; i < 10; ++i)
-                       writew(0xff, uap->port.membase + UART011_MIS);
-               writew(lcr_h, port->membase + uap->lcrh_tx);
-       }
-       writew(old_cr, port->membase + UART011_CR);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *pl011_type(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       return uap->port.type == PORT_AMBA ? uap->type : NULL;
-}
-
-/*
- * Release the memory region(s) being used by 'port'
- */
-static void pl010_release_port(struct uart_port *port)
-{
-       release_mem_region(port->mapbase, SZ_4K);
-}
-
-/*
- * Request the memory region(s) being used by 'port'
- */
-static int pl010_request_port(struct uart_port *port)
-{
-       return request_mem_region(port->mapbase, SZ_4K, "uart-pl011")
-                       != NULL ? 0 : -EBUSY;
-}
-
-/*
- * Configure/autoconfigure the port.
- */
-static void pl010_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE) {
-               port->type = PORT_AMBA;
-               pl010_request_port(port);
-       }
-}
-
-/*
- * verify the new serial_struct (for TIOCSSERIAL).
- */
-static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       int ret = 0;
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
-               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 amba_pl011_pops = {
-       .tx_empty       = pl01x_tx_empty,
-       .set_mctrl      = pl011_set_mctrl,
-       .get_mctrl      = pl01x_get_mctrl,
-       .stop_tx        = pl011_stop_tx,
-       .start_tx       = pl011_start_tx,
-       .stop_rx        = pl011_stop_rx,
-       .enable_ms      = pl011_enable_ms,
-       .break_ctl      = pl011_break_ctl,
-       .startup        = pl011_startup,
-       .shutdown       = pl011_shutdown,
-       .flush_buffer   = pl011_dma_flush_buffer,
-       .set_termios    = pl011_set_termios,
-       .type           = pl011_type,
-       .release_port   = pl010_release_port,
-       .request_port   = pl010_request_port,
-       .config_port    = pl010_config_port,
-       .verify_port    = pl010_verify_port,
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_get_char = pl010_get_poll_char,
-       .poll_put_char = pl010_put_poll_char,
-#endif
-};
-
-static struct uart_amba_port *amba_ports[UART_NR];
-
-#ifdef CONFIG_SERIAL_AMBA_PL011_CONSOLE
-
-static void pl011_console_putchar(struct uart_port *port, int ch)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-
-       while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
-               barrier();
-       writew(ch, uap->port.membase + UART01x_DR);
-}
-
-static void
-pl011_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct uart_amba_port *uap = amba_ports[co->index];
-       unsigned int status, old_cr, new_cr;
-
-       clk_enable(uap->clk);
-
-       /*
-        *      First save the CR then disable the interrupts
-        */
-       old_cr = readw(uap->port.membase + UART011_CR);
-       new_cr = old_cr & ~UART011_CR_CTSEN;
-       new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
-       writew(new_cr, uap->port.membase + UART011_CR);
-
-       uart_console_write(&uap->port, s, count, pl011_console_putchar);
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore the TCR
-        */
-       do {
-               status = readw(uap->port.membase + UART01x_FR);
-       } while (status & UART01x_FR_BUSY);
-       writew(old_cr, uap->port.membase + UART011_CR);
-
-       clk_disable(uap->clk);
-}
-
-static void __init
-pl011_console_get_options(struct uart_amba_port *uap, int *baud,
-                            int *parity, int *bits)
-{
-       if (readw(uap->port.membase + UART011_CR) & UART01x_CR_UARTEN) {
-               unsigned int lcr_h, ibrd, fbrd;
-
-               lcr_h = readw(uap->port.membase + uap->lcrh_tx);
-
-               *parity = 'n';
-               if (lcr_h & UART01x_LCRH_PEN) {
-                       if (lcr_h & UART01x_LCRH_EPS)
-                               *parity = 'e';
-                       else
-                               *parity = 'o';
-               }
-
-               if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7)
-                       *bits = 7;
-               else
-                       *bits = 8;
-
-               ibrd = readw(uap->port.membase + UART011_IBRD);
-               fbrd = readw(uap->port.membase + UART011_FBRD);
-
-               *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd);
-
-               if (uap->vendor->oversampling) {
-                       if (readw(uap->port.membase + UART011_CR)
-                                 & ST_UART011_CR_OVSFACT)
-                               *baud *= 2;
-               }
-       }
-}
-
-static int __init pl011_console_setup(struct console *co, char *options)
-{
-       struct uart_amba_port *uap;
-       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.
-        */
-       if (co->index >= UART_NR)
-               co->index = 0;
-       uap = amba_ports[co->index];
-       if (!uap)
-               return -ENODEV;
-
-       uap->port.uartclk = clk_get_rate(uap->clk);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               pl011_console_get_options(uap, &baud, &parity, &bits);
-
-       return uart_set_options(&uap->port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver amba_reg;
-static struct console amba_console = {
-       .name           = "ttyAMA",
-       .write          = pl011_console_write,
-       .device         = uart_console_device,
-       .setup          = pl011_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &amba_reg,
-};
-
-#define AMBA_CONSOLE   (&amba_console)
-#else
-#define AMBA_CONSOLE   NULL
-#endif
-
-static struct uart_driver amba_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "ttyAMA",
-       .dev_name               = "ttyAMA",
-       .major                  = SERIAL_AMBA_MAJOR,
-       .minor                  = SERIAL_AMBA_MINOR,
-       .nr                     = UART_NR,
-       .cons                   = AMBA_CONSOLE,
-};
-
-static int pl011_probe(struct amba_device *dev, struct amba_id *id)
-{
-       struct uart_amba_port *uap;
-       struct vendor_data *vendor = id->data;
-       void __iomem *base;
-       int i, ret;
-
-       for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
-               if (amba_ports[i] == NULL)
-                       break;
-
-       if (i == ARRAY_SIZE(amba_ports)) {
-               ret = -EBUSY;
-               goto out;
-       }
-
-       uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
-       if (uap == NULL) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       base = ioremap(dev->res.start, resource_size(&dev->res));
-       if (!base) {
-               ret = -ENOMEM;
-               goto free;
-       }
-
-       uap->clk = clk_get(&dev->dev, NULL);
-       if (IS_ERR(uap->clk)) {
-               ret = PTR_ERR(uap->clk);
-               goto unmap;
-       }
-
-       uap->vendor = vendor;
-       uap->lcrh_rx = vendor->lcrh_rx;
-       uap->lcrh_tx = vendor->lcrh_tx;
-       uap->fifosize = vendor->fifosize;
-       uap->port.dev = &dev->dev;
-       uap->port.mapbase = dev->res.start;
-       uap->port.membase = base;
-       uap->port.iotype = UPIO_MEM;
-       uap->port.irq = dev->irq[0];
-       uap->port.fifosize = uap->fifosize;
-       uap->port.ops = &amba_pl011_pops;
-       uap->port.flags = UPF_BOOT_AUTOCONF;
-       uap->port.line = i;
-       pl011_dma_probe(uap);
-
-       snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev));
-
-       amba_ports[i] = uap;
-
-       amba_set_drvdata(dev, uap);
-       ret = uart_add_one_port(&amba_reg, &uap->port);
-       if (ret) {
-               amba_set_drvdata(dev, NULL);
-               amba_ports[i] = NULL;
-               pl011_dma_remove(uap);
-               clk_put(uap->clk);
- unmap:
-               iounmap(base);
- free:
-               kfree(uap);
-       }
- out:
-       return ret;
-}
-
-static int pl011_remove(struct amba_device *dev)
-{
-       struct uart_amba_port *uap = amba_get_drvdata(dev);
-       int i;
-
-       amba_set_drvdata(dev, NULL);
-
-       uart_remove_one_port(&amba_reg, &uap->port);
-
-       for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
-               if (amba_ports[i] == uap)
-                       amba_ports[i] = NULL;
-
-       pl011_dma_remove(uap);
-       iounmap(uap->port.membase);
-       clk_put(uap->clk);
-       kfree(uap);
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int pl011_suspend(struct amba_device *dev, pm_message_t state)
-{
-       struct uart_amba_port *uap = amba_get_drvdata(dev);
-
-       if (!uap)
-               return -EINVAL;
-
-       return uart_suspend_port(&amba_reg, &uap->port);
-}
-
-static int pl011_resume(struct amba_device *dev)
-{
-       struct uart_amba_port *uap = amba_get_drvdata(dev);
-
-       if (!uap)
-               return -EINVAL;
-
-       return uart_resume_port(&amba_reg, &uap->port);
-}
-#endif
-
-static struct amba_id pl011_ids[] = {
-       {
-               .id     = 0x00041011,
-               .mask   = 0x000fffff,
-               .data   = &vendor_arm,
-       },
-       {
-               .id     = 0x00380802,
-               .mask   = 0x00ffffff,
-               .data   = &vendor_st,
-       },
-       { 0, 0 },
-};
-
-static struct amba_driver pl011_driver = {
-       .drv = {
-               .name   = "uart-pl011",
-       },
-       .id_table       = pl011_ids,
-       .probe          = pl011_probe,
-       .remove         = pl011_remove,
-#ifdef CONFIG_PM
-       .suspend        = pl011_suspend,
-       .resume         = pl011_resume,
-#endif
-};
-
-static int __init pl011_init(void)
-{
-       int ret;
-       printk(KERN_INFO "Serial: AMBA PL011 UART driver\n");
-
-       ret = uart_register_driver(&amba_reg);
-       if (ret == 0) {
-               ret = amba_driver_register(&pl011_driver);
-               if (ret)
-                       uart_unregister_driver(&amba_reg);
-       }
-       return ret;
-}
-
-static void __exit pl011_exit(void)
-{
-       amba_driver_unregister(&pl011_driver);
-       uart_unregister_driver(&amba_reg);
-}
-
-/*
- * While this can be a module, if builtin it's most likely the console
- * So let's leave module_exit but move module_init to an earlier place
- */
-arch_initcall(pl011_init);
-module_exit(pl011_exit);
-
-MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd");
-MODULE_DESCRIPTION("ARM AMBA serial port driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/apbuart.c b/drivers/serial/apbuart.c
deleted file mode 100644 (file)
index 095a5d5..0000000
+++ /dev/null
@@ -1,709 +0,0 @@
-/*
- *  Driver for GRLIB serial ports (APBUART)
- *
- *  Based on linux/drivers/serial/amba.c
- *
- *  Copyright (C) 2000 Deep Blue Solutions Ltd.
- *  Copyright (C) 2003 Konrad Eisele <eiselekd@web.de>
- *  Copyright (C) 2006 Daniel Hellstrom <daniel@gaisler.com>, Aeroflex Gaisler AB
- *  Copyright (C) 2008 Gilead Kutnick <kutnickg@zin-tech.com>
- *  Copyright (C) 2009 Kristoffer Glembo <kristoffer@gaisler.com>, Aeroflex Gaisler AB
- */
-
-#if defined(CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/serial.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/kthread.h>
-#include <linux/device.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
-#include <linux/of_irq.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/serial_core.h>
-#include <asm/irq.h>
-
-#include "apbuart.h"
-
-#define SERIAL_APBUART_MAJOR   TTY_MAJOR
-#define SERIAL_APBUART_MINOR   64
-#define UART_DUMMY_RSR_RX      0x8000  /* for ignore all read */
-
-static void apbuart_tx_chars(struct uart_port *port);
-
-static void apbuart_stop_tx(struct uart_port *port)
-{
-       unsigned int cr;
-
-       cr = UART_GET_CTRL(port);
-       cr &= ~UART_CTRL_TI;
-       UART_PUT_CTRL(port, cr);
-}
-
-static void apbuart_start_tx(struct uart_port *port)
-{
-       unsigned int cr;
-
-       cr = UART_GET_CTRL(port);
-       cr |= UART_CTRL_TI;
-       UART_PUT_CTRL(port, cr);
-
-       if (UART_GET_STATUS(port) & UART_STATUS_THE)
-               apbuart_tx_chars(port);
-}
-
-static void apbuart_stop_rx(struct uart_port *port)
-{
-       unsigned int cr;
-
-       cr = UART_GET_CTRL(port);
-       cr &= ~(UART_CTRL_RI);
-       UART_PUT_CTRL(port, cr);
-}
-
-static void apbuart_enable_ms(struct uart_port *port)
-{
-       /* No modem status change interrupts for APBUART */
-}
-
-static void apbuart_rx_chars(struct uart_port *port)
-{
-       struct tty_struct *tty = port->state->port.tty;
-       unsigned int status, ch, rsr, flag;
-       unsigned int max_chars = port->fifosize;
-
-       status = UART_GET_STATUS(port);
-
-       while (UART_RX_DATA(status) && (max_chars--)) {
-
-               ch = UART_GET_CHAR(port);
-               flag = TTY_NORMAL;
-
-               port->icount.rx++;
-
-               rsr = UART_GET_STATUS(port) | UART_DUMMY_RSR_RX;
-               UART_PUT_STATUS(port, 0);
-               if (rsr & UART_STATUS_ERR) {
-
-                       if (rsr & UART_STATUS_BR) {
-                               rsr &= ~(UART_STATUS_FE | UART_STATUS_PE);
-                               port->icount.brk++;
-                               if (uart_handle_break(port))
-                                       goto ignore_char;
-                       } else if (rsr & UART_STATUS_PE) {
-                               port->icount.parity++;
-                       } else if (rsr & UART_STATUS_FE) {
-                               port->icount.frame++;
-                       }
-                       if (rsr & UART_STATUS_OE)
-                               port->icount.overrun++;
-
-                       rsr &= port->read_status_mask;
-
-                       if (rsr & UART_STATUS_PE)
-                               flag = TTY_PARITY;
-                       else if (rsr & UART_STATUS_FE)
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(port, ch))
-                       goto ignore_char;
-
-               uart_insert_char(port, rsr, UART_STATUS_OE, ch, flag);
-
-
-             ignore_char:
-               status = UART_GET_STATUS(port);
-       }
-
-       tty_flip_buffer_push(tty);
-}
-
-static void apbuart_tx_chars(struct uart_port *port)
-{
-       struct circ_buf *xmit = &port->state->xmit;
-       int count;
-
-       if (port->x_char) {
-               UART_PUT_CHAR(port, port->x_char);
-               port->icount.tx++;
-               port->x_char = 0;
-               return;
-       }
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               apbuart_stop_tx(port);
-               return;
-       }
-
-       /* amba: fill FIFO */
-       count = port->fifosize >> 1;
-       do {
-               UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (--count > 0);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (uart_circ_empty(xmit))
-               apbuart_stop_tx(port);
-}
-
-static irqreturn_t apbuart_int(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       unsigned int status;
-
-       spin_lock(&port->lock);
-
-       status = UART_GET_STATUS(port);
-       if (status & UART_STATUS_DR)
-               apbuart_rx_chars(port);
-       if (status & UART_STATUS_THE)
-               apbuart_tx_chars(port);
-
-       spin_unlock(&port->lock);
-
-       return IRQ_HANDLED;
-}
-
-static unsigned int apbuart_tx_empty(struct uart_port *port)
-{
-       unsigned int status = UART_GET_STATUS(port);
-       return status & UART_STATUS_THE ? TIOCSER_TEMT : 0;
-}
-
-static unsigned int apbuart_get_mctrl(struct uart_port *port)
-{
-       /* The GRLIB APBUART handles flow control in hardware */
-       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
-}
-
-static void apbuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       /* The GRLIB APBUART handles flow control in hardware */
-}
-
-static void apbuart_break_ctl(struct uart_port *port, int break_state)
-{
-       /* We don't support sending break */
-}
-
-static int apbuart_startup(struct uart_port *port)
-{
-       int retval;
-       unsigned int cr;
-
-       /* Allocate the IRQ */
-       retval = request_irq(port->irq, apbuart_int, 0, "apbuart", port);
-       if (retval)
-               return retval;
-
-       /* Finally, enable interrupts */
-       cr = UART_GET_CTRL(port);
-       UART_PUT_CTRL(port,
-                     cr | UART_CTRL_RE | UART_CTRL_TE |
-                     UART_CTRL_RI | UART_CTRL_TI);
-
-       return 0;
-}
-
-static void apbuart_shutdown(struct uart_port *port)
-{
-       unsigned int cr;
-
-       /* disable all interrupts, disable the port */
-       cr = UART_GET_CTRL(port);
-       UART_PUT_CTRL(port,
-                     cr & ~(UART_CTRL_RE | UART_CTRL_TE |
-                            UART_CTRL_RI | UART_CTRL_TI));
-
-       /* Free the interrupt */
-       free_irq(port->irq, port);
-}
-
-static void apbuart_set_termios(struct uart_port *port,
-                               struct ktermios *termios, struct ktermios *old)
-{
-       unsigned int cr;
-       unsigned long flags;
-       unsigned int baud, quot;
-
-       /* Ask the core to calculate the divisor for us. */
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
-       if (baud == 0)
-               panic("invalid baudrate %i\n", port->uartclk / 16);
-
-       /* uart_get_divisor calc a *16 uart freq, apbuart is *8 */
-       quot = (uart_get_divisor(port, baud)) * 2;
-       cr = UART_GET_CTRL(port);
-       cr &= ~(UART_CTRL_PE | UART_CTRL_PS);
-
-       if (termios->c_cflag & PARENB) {
-               cr |= UART_CTRL_PE;
-               if ((termios->c_cflag & PARODD))
-                       cr |= UART_CTRL_PS;
-       }
-
-       /* Enable flow control. */
-       if (termios->c_cflag & CRTSCTS)
-               cr |= UART_CTRL_FL;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /* Update the per-port timeout. */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       port->read_status_mask = UART_STATUS_OE;
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= UART_STATUS_FE | UART_STATUS_PE;
-
-       /* Characters to ignore */
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= UART_STATUS_FE | UART_STATUS_PE;
-
-       /* Ignore all characters if CREAD is not set. */
-       if ((termios->c_cflag & CREAD) == 0)
-               port->ignore_status_mask |= UART_DUMMY_RSR_RX;
-
-       /* Set baud rate */
-       quot -= 1;
-       UART_PUT_SCAL(port, quot);
-       UART_PUT_CTRL(port, cr);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *apbuart_type(struct uart_port *port)
-{
-       return port->type == PORT_APBUART ? "GRLIB/APBUART" : NULL;
-}
-
-static void apbuart_release_port(struct uart_port *port)
-{
-       release_mem_region(port->mapbase, 0x100);
-}
-
-static int apbuart_request_port(struct uart_port *port)
-{
-       return request_mem_region(port->mapbase, 0x100, "grlib-apbuart")
-           != NULL ? 0 : -EBUSY;
-       return 0;
-}
-
-/* Configure/autoconfigure the port */
-static void apbuart_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE) {
-               port->type = PORT_APBUART;
-               apbuart_request_port(port);
-       }
-}
-
-/* Verify the new serial_struct (for TIOCSSERIAL) */
-static int apbuart_verify_port(struct uart_port *port,
-                              struct serial_struct *ser)
-{
-       int ret = 0;
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_APBUART)
-               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 grlib_apbuart_ops = {
-       .tx_empty = apbuart_tx_empty,
-       .set_mctrl = apbuart_set_mctrl,
-       .get_mctrl = apbuart_get_mctrl,
-       .stop_tx = apbuart_stop_tx,
-       .start_tx = apbuart_start_tx,
-       .stop_rx = apbuart_stop_rx,
-       .enable_ms = apbuart_enable_ms,
-       .break_ctl = apbuart_break_ctl,
-       .startup = apbuart_startup,
-       .shutdown = apbuart_shutdown,
-       .set_termios = apbuart_set_termios,
-       .type = apbuart_type,
-       .release_port = apbuart_release_port,
-       .request_port = apbuart_request_port,
-       .config_port = apbuart_config_port,
-       .verify_port = apbuart_verify_port,
-};
-
-static struct uart_port grlib_apbuart_ports[UART_NR];
-static struct device_node *grlib_apbuart_nodes[UART_NR];
-
-static int apbuart_scan_fifo_size(struct uart_port *port, int portnumber)
-{
-       int ctrl, loop = 0;
-       int status;
-       int fifosize;
-       unsigned long flags;
-
-       ctrl = UART_GET_CTRL(port);
-
-       /*
-        * Enable the transceiver and wait for it to be ready to send data.
-        * Clear interrupts so that this process will not be externally
-        * interrupted in the middle (which can cause the transceiver to
-        * drain prematurely).
-        */
-
-       local_irq_save(flags);
-
-       UART_PUT_CTRL(port, ctrl | UART_CTRL_TE);
-
-       while (!UART_TX_READY(UART_GET_STATUS(port)))
-               loop++;
-
-       /*
-        * Disable the transceiver so data isn't actually sent during the
-        * actual test.
-        */
-
-       UART_PUT_CTRL(port, ctrl & ~(UART_CTRL_TE));
-
-       fifosize = 1;
-       UART_PUT_CHAR(port, 0);
-
-       /*
-        * So long as transmitting a character increments the tranceivier FIFO
-        * length the FIFO must be at least that big. These bytes will
-        * automatically drain off of the FIFO.
-        */
-
-       status = UART_GET_STATUS(port);
-       while (((status >> 20) & 0x3F) == fifosize) {
-               fifosize++;
-               UART_PUT_CHAR(port, 0);
-               status = UART_GET_STATUS(port);
-       }
-
-       fifosize--;
-
-       UART_PUT_CTRL(port, ctrl);
-       local_irq_restore(flags);
-
-       if (fifosize == 0)
-               fifosize = 1;
-
-       return fifosize;
-}
-
-static void apbuart_flush_fifo(struct uart_port *port)
-{
-       int i;
-
-       for (i = 0; i < port->fifosize; i++)
-               UART_GET_CHAR(port);
-}
-
-
-/* ======================================================================== */
-/* Console driver, if enabled                                               */
-/* ======================================================================== */
-
-#ifdef CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE
-
-static void apbuart_console_putchar(struct uart_port *port, int ch)
-{
-       unsigned int status;
-       do {
-               status = UART_GET_STATUS(port);
-       } while (!UART_TX_READY(status));
-       UART_PUT_CHAR(port, ch);
-}
-
-static void
-apbuart_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct uart_port *port = &grlib_apbuart_ports[co->index];
-       unsigned int status, old_cr, new_cr;
-
-       /* First save the CR then disable the interrupts */
-       old_cr = UART_GET_CTRL(port);
-       new_cr = old_cr & ~(UART_CTRL_RI | UART_CTRL_TI);
-       UART_PUT_CTRL(port, new_cr);
-
-       uart_console_write(port, s, count, apbuart_console_putchar);
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore the TCR
-        */
-       do {
-               status = UART_GET_STATUS(port);
-       } while (!UART_TX_READY(status));
-       UART_PUT_CTRL(port, old_cr);
-}
-
-static void __init
-apbuart_console_get_options(struct uart_port *port, int *baud,
-                           int *parity, int *bits)
-{
-       if (UART_GET_CTRL(port) & (UART_CTRL_RE | UART_CTRL_TE)) {
-
-               unsigned int quot, status;
-               status = UART_GET_STATUS(port);
-
-               *parity = 'n';
-               if (status & UART_CTRL_PE) {
-                       if ((status & UART_CTRL_PS) == 0)
-                               *parity = 'e';
-                       else
-                               *parity = 'o';
-               }
-
-               *bits = 8;
-               quot = UART_GET_SCAL(port) / 8;
-               *baud = port->uartclk / (16 * (quot + 1));
-       }
-}
-
-static int __init apbuart_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port;
-       int baud = 38400;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       pr_debug("apbuart_console_setup co=%p, co->index=%i, options=%s\n",
-                co, co->index, options);
-
-       /*
-        * Check whether an invalid uart number has been specified, and
-        * if so, search for the first available port that does have
-        * console support.
-        */
-       if (co->index >= grlib_apbuart_port_nr)
-               co->index = 0;
-
-       port = &grlib_apbuart_ports[co->index];
-
-       spin_lock_init(&port->lock);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               apbuart_console_get_options(port, &baud, &parity, &bits);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver grlib_apbuart_driver;
-
-static struct console grlib_apbuart_console = {
-       .name = "ttyS",
-       .write = apbuart_console_write,
-       .device = uart_console_device,
-       .setup = apbuart_console_setup,
-       .flags = CON_PRINTBUFFER,
-       .index = -1,
-       .data = &grlib_apbuart_driver,
-};
-
-
-static int grlib_apbuart_configure(void);
-
-static int __init apbuart_console_init(void)
-{
-       if (grlib_apbuart_configure())
-               return -ENODEV;
-       register_console(&grlib_apbuart_console);
-       return 0;
-}
-
-console_initcall(apbuart_console_init);
-
-#define APBUART_CONSOLE        (&grlib_apbuart_console)
-#else
-#define APBUART_CONSOLE        NULL
-#endif
-
-static struct uart_driver grlib_apbuart_driver = {
-       .owner = THIS_MODULE,
-       .driver_name = "serial",
-       .dev_name = "ttyS",
-       .major = SERIAL_APBUART_MAJOR,
-       .minor = SERIAL_APBUART_MINOR,
-       .nr = UART_NR,
-       .cons = APBUART_CONSOLE,
-};
-
-
-/* ======================================================================== */
-/* OF Platform Driver                                                       */
-/* ======================================================================== */
-
-static int __devinit apbuart_probe(struct platform_device *op,
-                                  const struct of_device_id *match)
-{
-       int i = -1;
-       struct uart_port *port = NULL;
-
-       i = 0;
-       for (i = 0; i < grlib_apbuart_port_nr; i++) {
-               if (op->dev.of_node == grlib_apbuart_nodes[i])
-                       break;
-       }
-
-       port = &grlib_apbuart_ports[i];
-       port->dev = &op->dev;
-
-       uart_add_one_port(&grlib_apbuart_driver, (struct uart_port *) port);
-
-       apbuart_flush_fifo((struct uart_port *) port);
-
-       printk(KERN_INFO "grlib-apbuart at 0x%llx, irq %d\n",
-              (unsigned long long) port->mapbase, port->irq);
-       return 0;
-}
-
-static struct of_device_id __initdata apbuart_match[] = {
-       {
-        .name = "GAISLER_APBUART",
-        },
-       {
-        .name = "01_00c",
-        },
-       {},
-};
-
-static struct of_platform_driver grlib_apbuart_of_driver = {
-       .probe = apbuart_probe,
-       .driver = {
-               .owner = THIS_MODULE,
-               .name = "grlib-apbuart",
-               .of_match_table = apbuart_match,
-       },
-};
-
-
-static int grlib_apbuart_configure(void)
-{
-       struct device_node *np, *rp;
-       const u32 *prop;
-       int freq_khz, line = 0;
-
-       /* Get bus frequency */
-       rp = of_find_node_by_path("/");
-       if (!rp)
-               return -ENODEV;
-       rp = of_get_next_child(rp, NULL);
-       if (!rp)
-               return -ENODEV;
-       prop = of_get_property(rp, "clock-frequency", NULL);
-       if (!prop)
-               return -ENODEV;
-       freq_khz = *prop;
-
-       for_each_matching_node(np, apbuart_match) {
-               const int *irqs, *ampopts;
-               const struct amba_prom_registers *regs;
-               struct uart_port *port;
-               unsigned long addr;
-
-               ampopts = of_get_property(np, "ampopts", NULL);
-               if (ampopts && (*ampopts == 0))
-                       continue; /* Ignore if used by another OS instance */
-
-               irqs = of_get_property(np, "interrupts", NULL);
-               regs = of_get_property(np, "reg", NULL);
-
-               if (!irqs || !regs)
-                       continue;
-
-               grlib_apbuart_nodes[line] = np;
-
-               addr = regs->phys_addr;
-
-               port = &grlib_apbuart_ports[line];
-
-               port->mapbase = addr;
-               port->membase = ioremap(addr, sizeof(struct grlib_apbuart_regs_map));
-               port->irq = *irqs;
-               port->iotype = UPIO_MEM;
-               port->ops = &grlib_apbuart_ops;
-               port->flags = UPF_BOOT_AUTOCONF;
-               port->line = line;
-               port->uartclk = freq_khz * 1000;
-               port->fifosize = apbuart_scan_fifo_size((struct uart_port *) port, line);
-               line++;
-
-               /* We support maximum UART_NR uarts ... */
-               if (line == UART_NR)
-                       break;
-       }
-
-       grlib_apbuart_driver.nr = grlib_apbuart_port_nr = line;
-       return line ? 0 : -ENODEV;
-}
-
-static int __init grlib_apbuart_init(void)
-{
-       int ret;
-
-       /* Find all APBUARTS in device the tree and initialize their ports */
-       ret = grlib_apbuart_configure();
-       if (ret)
-               return ret;
-
-       printk(KERN_INFO "Serial: GRLIB APBUART driver\n");
-
-       ret = uart_register_driver(&grlib_apbuart_driver);
-
-       if (ret) {
-               printk(KERN_ERR "%s: uart_register_driver failed (%i)\n",
-                      __FILE__, ret);
-               return ret;
-       }
-
-       ret = of_register_platform_driver(&grlib_apbuart_of_driver);
-       if (ret) {
-               printk(KERN_ERR
-                      "%s: of_register_platform_driver failed (%i)\n",
-                      __FILE__, ret);
-               uart_unregister_driver(&grlib_apbuart_driver);
-               return ret;
-       }
-
-       return ret;
-}
-
-static void __exit grlib_apbuart_exit(void)
-{
-       int i;
-
-       for (i = 0; i < grlib_apbuart_port_nr; i++)
-               uart_remove_one_port(&grlib_apbuart_driver,
-                                    &grlib_apbuart_ports[i]);
-
-       uart_unregister_driver(&grlib_apbuart_driver);
-       of_unregister_platform_driver(&grlib_apbuart_of_driver);
-}
-
-module_init(grlib_apbuart_init);
-module_exit(grlib_apbuart_exit);
-
-MODULE_AUTHOR("Aeroflex Gaisler AB");
-MODULE_DESCRIPTION("GRLIB APBUART serial driver");
-MODULE_VERSION("2.1");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/apbuart.h b/drivers/serial/apbuart.h
deleted file mode 100644 (file)
index 5faf87c..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef __GRLIB_APBUART_H__
-#define __GRLIB_APBUART_H__
-
-#include <asm/io.h>
-
-#define UART_NR                8
-static int grlib_apbuart_port_nr;
-
-struct grlib_apbuart_regs_map {
-       u32 data;
-       u32 status;
-       u32 ctrl;
-       u32 scaler;
-};
-
-struct amba_prom_registers {
-       unsigned int phys_addr;
-       unsigned int reg_size;
-};
-
-/*
- *  The following defines the bits in the APBUART Status Registers.
- */
-#define UART_STATUS_DR   0x00000001    /* Data Ready */
-#define UART_STATUS_TSE  0x00000002    /* TX Send Register Empty */
-#define UART_STATUS_THE  0x00000004    /* TX Hold Register Empty */
-#define UART_STATUS_BR   0x00000008    /* Break Error */
-#define UART_STATUS_OE   0x00000010    /* RX Overrun Error */
-#define UART_STATUS_PE   0x00000020    /* RX Parity Error */
-#define UART_STATUS_FE   0x00000040    /* RX Framing Error */
-#define UART_STATUS_ERR  0x00000078    /* Error Mask */
-
-/*
- *  The following defines the bits in the APBUART Ctrl Registers.
- */
-#define UART_CTRL_RE     0x00000001    /* Receiver enable */
-#define UART_CTRL_TE     0x00000002    /* Transmitter enable */
-#define UART_CTRL_RI     0x00000004    /* Receiver interrupt enable */
-#define UART_CTRL_TI     0x00000008    /* Transmitter irq */
-#define UART_CTRL_PS     0x00000010    /* Parity select */
-#define UART_CTRL_PE     0x00000020    /* Parity enable */
-#define UART_CTRL_FL     0x00000040    /* Flow control enable */
-#define UART_CTRL_LB     0x00000080    /* Loopback enable */
-
-#define APBBASE(port) ((struct grlib_apbuart_regs_map *)((port)->membase))
-
-#define APBBASE_DATA_P(port)   (&(APBBASE(port)->data))
-#define APBBASE_STATUS_P(port) (&(APBBASE(port)->status))
-#define APBBASE_CTRL_P(port)   (&(APBBASE(port)->ctrl))
-#define APBBASE_SCALAR_P(port) (&(APBBASE(port)->scaler))
-
-#define UART_GET_CHAR(port)    (__raw_readl(APBBASE_DATA_P(port)))
-#define UART_PUT_CHAR(port, v) (__raw_writel(v, APBBASE_DATA_P(port)))
-#define UART_GET_STATUS(port)  (__raw_readl(APBBASE_STATUS_P(port)))
-#define UART_PUT_STATUS(port, v)(__raw_writel(v, APBBASE_STATUS_P(port)))
-#define UART_GET_CTRL(port)    (__raw_readl(APBBASE_CTRL_P(port)))
-#define UART_PUT_CTRL(port, v) (__raw_writel(v, APBBASE_CTRL_P(port)))
-#define UART_GET_SCAL(port)    (__raw_readl(APBBASE_SCALAR_P(port)))
-#define UART_PUT_SCAL(port, v) (__raw_writel(v, APBBASE_SCALAR_P(port)))
-
-#define UART_RX_DATA(s)                (((s) & UART_STATUS_DR) != 0)
-#define UART_TX_READY(s)       (((s) & UART_STATUS_THE) != 0)
-
-#endif /* __GRLIB_APBUART_H__ */
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
deleted file mode 100644 (file)
index 3892666..0000000
+++ /dev/null
@@ -1,1808 +0,0 @@
-/*
- *  linux/drivers/char/atmel_serial.c
- *
- *  Driver for Atmel AT91 / AT32 Serial ports
- *  Copyright (C) 2003 Rick Bronson
- *
- *  Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd.
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *
- *  DMA support added by Chip Coldwell.
- *
- * 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/module.h>
-#include <linux/tty.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/serial.h>
-#include <linux/clk.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/tty_flip.h>
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/atmel_pdc.h>
-#include <linux/atmel_serial.h>
-#include <linux/uaccess.h>
-
-#include <asm/io.h>
-#include <asm/ioctls.h>
-
-#include <asm/mach/serial_at91.h>
-#include <mach/board.h>
-
-#ifdef CONFIG_ARM
-#include <mach/cpu.h>
-#include <mach/gpio.h>
-#endif
-
-#define PDC_BUFFER_SIZE                512
-/* Revisit: We should calculate this based on the actual port settings */
-#define PDC_RX_TIMEOUT         (3 * 10)                /* 3 bytes */
-
-#if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
-static void atmel_start_rx(struct uart_port *port);
-static void atmel_stop_rx(struct uart_port *port);
-
-#ifdef CONFIG_SERIAL_ATMEL_TTYAT
-
-/* Use device name ttyAT, major 204 and minor 154-169.  This is necessary if we
- * should coexist with the 8250 driver, such as if we have an external 16C550
- * UART. */
-#define SERIAL_ATMEL_MAJOR     204
-#define MINOR_START            154
-#define ATMEL_DEVICENAME       "ttyAT"
-
-#else
-
-/* Use device name ttyS, major 4, minor 64-68.  This is the usual serial port
- * name, but it is legally reserved for the 8250 driver. */
-#define SERIAL_ATMEL_MAJOR     TTY_MAJOR
-#define MINOR_START            64
-#define ATMEL_DEVICENAME       "ttyS"
-
-#endif
-
-#define ATMEL_ISR_PASS_LIMIT   256
-
-/* UART registers. CR is write-only, hence no GET macro */
-#define UART_PUT_CR(port,v)    __raw_writel(v, (port)->membase + ATMEL_US_CR)
-#define UART_GET_MR(port)      __raw_readl((port)->membase + ATMEL_US_MR)
-#define UART_PUT_MR(port,v)    __raw_writel(v, (port)->membase + ATMEL_US_MR)
-#define UART_PUT_IER(port,v)   __raw_writel(v, (port)->membase + ATMEL_US_IER)
-#define UART_PUT_IDR(port,v)   __raw_writel(v, (port)->membase + ATMEL_US_IDR)
-#define UART_GET_IMR(port)     __raw_readl((port)->membase + ATMEL_US_IMR)
-#define UART_GET_CSR(port)     __raw_readl((port)->membase + ATMEL_US_CSR)
-#define UART_GET_CHAR(port)    __raw_readl((port)->membase + ATMEL_US_RHR)
-#define UART_PUT_CHAR(port,v)  __raw_writel(v, (port)->membase + ATMEL_US_THR)
-#define UART_GET_BRGR(port)    __raw_readl((port)->membase + ATMEL_US_BRGR)
-#define UART_PUT_BRGR(port,v)  __raw_writel(v, (port)->membase + ATMEL_US_BRGR)
-#define UART_PUT_RTOR(port,v)  __raw_writel(v, (port)->membase + ATMEL_US_RTOR)
-#define UART_PUT_TTGR(port, v) __raw_writel(v, (port)->membase + ATMEL_US_TTGR)
-
- /* PDC registers */
-#define UART_PUT_PTCR(port,v)  __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR)
-#define UART_GET_PTSR(port)    __raw_readl((port)->membase + ATMEL_PDC_PTSR)
-
-#define UART_PUT_RPR(port,v)   __raw_writel(v, (port)->membase + ATMEL_PDC_RPR)
-#define UART_GET_RPR(port)     __raw_readl((port)->membase + ATMEL_PDC_RPR)
-#define UART_PUT_RCR(port,v)   __raw_writel(v, (port)->membase + ATMEL_PDC_RCR)
-#define UART_PUT_RNPR(port,v)  __raw_writel(v, (port)->membase + ATMEL_PDC_RNPR)
-#define UART_PUT_RNCR(port,v)  __raw_writel(v, (port)->membase + ATMEL_PDC_RNCR)
-
-#define UART_PUT_TPR(port,v)   __raw_writel(v, (port)->membase + ATMEL_PDC_TPR)
-#define UART_PUT_TCR(port,v)   __raw_writel(v, (port)->membase + ATMEL_PDC_TCR)
-#define UART_GET_TCR(port)     __raw_readl((port)->membase + ATMEL_PDC_TCR)
-
-static int (*atmel_open_hook)(struct uart_port *);
-static void (*atmel_close_hook)(struct uart_port *);
-
-struct atmel_dma_buffer {
-       unsigned char   *buf;
-       dma_addr_t      dma_addr;
-       unsigned int    dma_size;
-       unsigned int    ofs;
-};
-
-struct atmel_uart_char {
-       u16             status;
-       u16             ch;
-};
-
-#define ATMEL_SERIAL_RINGSIZE 1024
-
-/*
- * We wrap our port structure around the generic uart_port.
- */
-struct atmel_uart_port {
-       struct uart_port        uart;           /* uart */
-       struct clk              *clk;           /* uart clock */
-       int                     may_wakeup;     /* cached value of device_may_wakeup for times we need to disable it */
-       u32                     backup_imr;     /* IMR saved during suspend */
-       int                     break_active;   /* break being received */
-
-       short                   use_dma_rx;     /* enable PDC receiver */
-       short                   pdc_rx_idx;     /* current PDC RX buffer */
-       struct atmel_dma_buffer pdc_rx[2];      /* PDC receier */
-
-       short                   use_dma_tx;     /* enable PDC transmitter */
-       struct atmel_dma_buffer pdc_tx;         /* PDC transmitter */
-
-       struct tasklet_struct   tasklet;
-       unsigned int            irq_status;
-       unsigned int            irq_status_prev;
-
-       struct circ_buf         rx_ring;
-
-       struct serial_rs485     rs485;          /* rs485 settings */
-       unsigned int            tx_done_mask;
-};
-
-static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
-
-#ifdef SUPPORT_SYSRQ
-static struct console atmel_console;
-#endif
-
-static inline struct atmel_uart_port *
-to_atmel_uart_port(struct uart_port *uart)
-{
-       return container_of(uart, struct atmel_uart_port, uart);
-}
-
-#ifdef CONFIG_SERIAL_ATMEL_PDC
-static bool atmel_use_dma_rx(struct uart_port *port)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       return atmel_port->use_dma_rx;
-}
-
-static bool atmel_use_dma_tx(struct uart_port *port)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       return atmel_port->use_dma_tx;
-}
-#else
-static bool atmel_use_dma_rx(struct uart_port *port)
-{
-       return false;
-}
-
-static bool atmel_use_dma_tx(struct uart_port *port)
-{
-       return false;
-}
-#endif
-
-/* Enable or disable the rs485 support */
-void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       unsigned int mode;
-
-       spin_lock(&port->lock);
-
-       /* Disable interrupts */
-       UART_PUT_IDR(port, atmel_port->tx_done_mask);
-
-       mode = UART_GET_MR(port);
-
-       /* Resetting serial mode to RS232 (0x0) */
-       mode &= ~ATMEL_US_USMODE;
-
-       atmel_port->rs485 = *rs485conf;
-
-       if (rs485conf->flags & SER_RS485_ENABLED) {
-               dev_dbg(port->dev, "Setting UART to RS485\n");
-               atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
-               if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND)
-                       UART_PUT_TTGR(port, rs485conf->delay_rts_after_send);
-               mode |= ATMEL_US_USMODE_RS485;
-       } else {
-               dev_dbg(port->dev, "Setting UART to RS232\n");
-               if (atmel_use_dma_tx(port))
-                       atmel_port->tx_done_mask = ATMEL_US_ENDTX |
-                               ATMEL_US_TXBUFE;
-               else
-                       atmel_port->tx_done_mask = ATMEL_US_TXRDY;
-       }
-       UART_PUT_MR(port, mode);
-
-       /* Enable interrupts */
-       UART_PUT_IER(port, atmel_port->tx_done_mask);
-
-       spin_unlock(&port->lock);
-
-}
-
-/*
- * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
- */
-static u_int atmel_tx_empty(struct uart_port *port)
-{
-       return (UART_GET_CSR(port) & ATMEL_US_TXEMPTY) ? TIOCSER_TEMT : 0;
-}
-
-/*
- * Set state of the modem control output lines
- */
-static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
-{
-       unsigned int control = 0;
-       unsigned int mode;
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-#ifdef CONFIG_ARCH_AT91RM9200
-       if (cpu_is_at91rm9200()) {
-               /*
-                * AT91RM9200 Errata #39: RTS0 is not internally connected
-                * to PA21. We need to drive the pin manually.
-                */
-               if (port->mapbase == AT91RM9200_BASE_US0) {
-                       if (mctrl & TIOCM_RTS)
-                               at91_set_gpio_value(AT91_PIN_PA21, 0);
-                       else
-                               at91_set_gpio_value(AT91_PIN_PA21, 1);
-               }
-       }
-#endif
-
-       if (mctrl & TIOCM_RTS)
-               control |= ATMEL_US_RTSEN;
-       else
-               control |= ATMEL_US_RTSDIS;
-
-       if (mctrl & TIOCM_DTR)
-               control |= ATMEL_US_DTREN;
-       else
-               control |= ATMEL_US_DTRDIS;
-
-       UART_PUT_CR(port, control);
-
-       /* Local loopback mode? */
-       mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE;
-       if (mctrl & TIOCM_LOOP)
-               mode |= ATMEL_US_CHMODE_LOC_LOOP;
-       else
-               mode |= ATMEL_US_CHMODE_NORMAL;
-
-       /* Resetting serial mode to RS232 (0x0) */
-       mode &= ~ATMEL_US_USMODE;
-
-       if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
-               dev_dbg(port->dev, "Setting UART to RS485\n");
-               if (atmel_port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
-                       UART_PUT_TTGR(port,
-                                       atmel_port->rs485.delay_rts_after_send);
-               mode |= ATMEL_US_USMODE_RS485;
-       } else {
-               dev_dbg(port->dev, "Setting UART to RS232\n");
-       }
-       UART_PUT_MR(port, mode);
-}
-
-/*
- * Get state of the modem control input lines
- */
-static u_int atmel_get_mctrl(struct uart_port *port)
-{
-       unsigned int status, ret = 0;
-
-       status = UART_GET_CSR(port);
-
-       /*
-        * The control signals are active low.
-        */
-       if (!(status & ATMEL_US_DCD))
-               ret |= TIOCM_CD;
-       if (!(status & ATMEL_US_CTS))
-               ret |= TIOCM_CTS;
-       if (!(status & ATMEL_US_DSR))
-               ret |= TIOCM_DSR;
-       if (!(status & ATMEL_US_RI))
-               ret |= TIOCM_RI;
-
-       return ret;
-}
-
-/*
- * Stop transmitting.
- */
-static void atmel_stop_tx(struct uart_port *port)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       if (atmel_use_dma_tx(port)) {
-               /* disable PDC transmit */
-               UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
-       }
-       /* Disable interrupts */
-       UART_PUT_IDR(port, atmel_port->tx_done_mask);
-
-       if (atmel_port->rs485.flags & SER_RS485_ENABLED)
-               atmel_start_rx(port);
-}
-
-/*
- * Start transmitting.
- */
-static void atmel_start_tx(struct uart_port *port)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       if (atmel_use_dma_tx(port)) {
-               if (UART_GET_PTSR(port) & ATMEL_PDC_TXTEN)
-                       /* The transmitter is already running.  Yes, we
-                          really need this.*/
-                       return;
-
-               if (atmel_port->rs485.flags & SER_RS485_ENABLED)
-                       atmel_stop_rx(port);
-
-               /* re-enable PDC transmit */
-               UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
-       }
-       /* Enable interrupts */
-       UART_PUT_IER(port, atmel_port->tx_done_mask);
-}
-
-/*
- * start receiving - port is in process of being opened.
- */
-static void atmel_start_rx(struct uart_port *port)
-{
-       UART_PUT_CR(port, ATMEL_US_RSTSTA);  /* reset status and receiver */
-
-       if (atmel_use_dma_rx(port)) {
-               /* enable PDC controller */
-               UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
-                       port->read_status_mask);
-               UART_PUT_PTCR(port, ATMEL_PDC_RXTEN);
-       } else {
-               UART_PUT_IER(port, ATMEL_US_RXRDY);
-       }
-}
-
-/*
- * Stop receiving - port is in process of being closed.
- */
-static void atmel_stop_rx(struct uart_port *port)
-{
-       if (atmel_use_dma_rx(port)) {
-               /* disable PDC receive */
-               UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS);
-               UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
-                       port->read_status_mask);
-       } else {
-               UART_PUT_IDR(port, ATMEL_US_RXRDY);
-       }
-}
-
-/*
- * Enable modem status interrupts
- */
-static void atmel_enable_ms(struct uart_port *port)
-{
-       UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC
-                       | ATMEL_US_DCDIC | ATMEL_US_CTSIC);
-}
-
-/*
- * Control the transmission of a break signal
- */
-static void atmel_break_ctl(struct uart_port *port, int break_state)
-{
-       if (break_state != 0)
-               UART_PUT_CR(port, ATMEL_US_STTBRK);     /* start break */
-       else
-               UART_PUT_CR(port, ATMEL_US_STPBRK);     /* stop break */
-}
-
-/*
- * Stores the incoming character in the ring buffer
- */
-static void
-atmel_buffer_rx_char(struct uart_port *port, unsigned int status,
-                    unsigned int ch)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       struct circ_buf *ring = &atmel_port->rx_ring;
-       struct atmel_uart_char *c;
-
-       if (!CIRC_SPACE(ring->head, ring->tail, ATMEL_SERIAL_RINGSIZE))
-               /* Buffer overflow, ignore char */
-               return;
-
-       c = &((struct atmel_uart_char *)ring->buf)[ring->head];
-       c->status       = status;
-       c->ch           = ch;
-
-       /* Make sure the character is stored before we update head. */
-       smp_wmb();
-
-       ring->head = (ring->head + 1) & (ATMEL_SERIAL_RINGSIZE - 1);
-}
-
-/*
- * Deal with parity, framing and overrun errors.
- */
-static void atmel_pdc_rxerr(struct uart_port *port, unsigned int status)
-{
-       /* clear error */
-       UART_PUT_CR(port, ATMEL_US_RSTSTA);
-
-       if (status & ATMEL_US_RXBRK) {
-               /* ignore side-effect */
-               status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME);
-               port->icount.brk++;
-       }
-       if (status & ATMEL_US_PARE)
-               port->icount.parity++;
-       if (status & ATMEL_US_FRAME)
-               port->icount.frame++;
-       if (status & ATMEL_US_OVRE)
-               port->icount.overrun++;
-}
-
-/*
- * Characters received (called from interrupt handler)
- */
-static void atmel_rx_chars(struct uart_port *port)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       unsigned int status, ch;
-
-       status = UART_GET_CSR(port);
-       while (status & ATMEL_US_RXRDY) {
-               ch = UART_GET_CHAR(port);
-
-               /*
-                * note that the error handling code is
-                * out of the main execution path
-                */
-               if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME
-                                      | ATMEL_US_OVRE | ATMEL_US_RXBRK)
-                            || atmel_port->break_active)) {
-
-                       /* clear error */
-                       UART_PUT_CR(port, ATMEL_US_RSTSTA);
-
-                       if (status & ATMEL_US_RXBRK
-                           && !atmel_port->break_active) {
-                               atmel_port->break_active = 1;
-                               UART_PUT_IER(port, ATMEL_US_RXBRK);
-                       } else {
-                               /*
-                                * This is either the end-of-break
-                                * condition or we've received at
-                                * least one character without RXBRK
-                                * being set. In both cases, the next
-                                * RXBRK will indicate start-of-break.
-                                */
-                               UART_PUT_IDR(port, ATMEL_US_RXBRK);
-                               status &= ~ATMEL_US_RXBRK;
-                               atmel_port->break_active = 0;
-                       }
-               }
-
-               atmel_buffer_rx_char(port, status, ch);
-               status = UART_GET_CSR(port);
-       }
-
-       tasklet_schedule(&atmel_port->tasklet);
-}
-
-/*
- * Transmit characters (called from tasklet with TXRDY interrupt
- * disabled)
- */
-static void atmel_tx_chars(struct uart_port *port)
-{
-       struct circ_buf *xmit = &port->state->xmit;
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       if (port->x_char && UART_GET_CSR(port) & atmel_port->tx_done_mask) {
-               UART_PUT_CHAR(port, port->x_char);
-               port->icount.tx++;
-               port->x_char = 0;
-       }
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port))
-               return;
-
-       while (UART_GET_CSR(port) & atmel_port->tx_done_mask) {
-               UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (!uart_circ_empty(xmit))
-               /* Enable interrupts */
-               UART_PUT_IER(port, atmel_port->tx_done_mask);
-}
-
-/*
- * receive interrupt handler.
- */
-static void
-atmel_handle_receive(struct uart_port *port, unsigned int pending)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       if (atmel_use_dma_rx(port)) {
-               /*
-                * PDC receive. Just schedule the tasklet and let it
-                * figure out the details.
-                *
-                * TODO: We're not handling error flags correctly at
-                * the moment.
-                */
-               if (pending & (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)) {
-                       UART_PUT_IDR(port, (ATMEL_US_ENDRX
-                                               | ATMEL_US_TIMEOUT));
-                       tasklet_schedule(&atmel_port->tasklet);
-               }
-
-               if (pending & (ATMEL_US_RXBRK | ATMEL_US_OVRE |
-                               ATMEL_US_FRAME | ATMEL_US_PARE))
-                       atmel_pdc_rxerr(port, pending);
-       }
-
-       /* Interrupt receive */
-       if (pending & ATMEL_US_RXRDY)
-               atmel_rx_chars(port);
-       else if (pending & ATMEL_US_RXBRK) {
-               /*
-                * End of break detected. If it came along with a
-                * character, atmel_rx_chars will handle it.
-                */
-               UART_PUT_CR(port, ATMEL_US_RSTSTA);
-               UART_PUT_IDR(port, ATMEL_US_RXBRK);
-               atmel_port->break_active = 0;
-       }
-}
-
-/*
- * transmit interrupt handler. (Transmit is IRQF_NODELAY safe)
- */
-static void
-atmel_handle_transmit(struct uart_port *port, unsigned int pending)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       if (pending & atmel_port->tx_done_mask) {
-               /* Either PDC or interrupt transmission */
-               UART_PUT_IDR(port, atmel_port->tx_done_mask);
-               tasklet_schedule(&atmel_port->tasklet);
-       }
-}
-
-/*
- * status flags interrupt handler.
- */
-static void
-atmel_handle_status(struct uart_port *port, unsigned int pending,
-                   unsigned int status)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC
-                               | ATMEL_US_CTSIC)) {
-               atmel_port->irq_status = status;
-               tasklet_schedule(&atmel_port->tasklet);
-       }
-}
-
-/*
- * Interrupt handler
- */
-static irqreturn_t atmel_interrupt(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       unsigned int status, pending, pass_counter = 0;
-
-       do {
-               status = UART_GET_CSR(port);
-               pending = status & UART_GET_IMR(port);
-               if (!pending)
-                       break;
-
-               atmel_handle_receive(port, pending);
-               atmel_handle_status(port, pending, status);
-               atmel_handle_transmit(port, pending);
-       } while (pass_counter++ < ATMEL_ISR_PASS_LIMIT);
-
-       return pass_counter ? IRQ_HANDLED : IRQ_NONE;
-}
-
-/*
- * Called from tasklet with ENDTX and TXBUFE interrupts disabled.
- */
-static void atmel_tx_dma(struct uart_port *port)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       struct circ_buf *xmit = &port->state->xmit;
-       struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
-       int count;
-
-       /* nothing left to transmit? */
-       if (UART_GET_TCR(port))
-               return;
-
-       xmit->tail += pdc->ofs;
-       xmit->tail &= UART_XMIT_SIZE - 1;
-
-       port->icount.tx += pdc->ofs;
-       pdc->ofs = 0;
-
-       /* more to transmit - setup next transfer */
-
-       /* disable PDC transmit */
-       UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
-
-       if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) {
-               dma_sync_single_for_device(port->dev,
-                                          pdc->dma_addr,
-                                          pdc->dma_size,
-                                          DMA_TO_DEVICE);
-
-               count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
-               pdc->ofs = count;
-
-               UART_PUT_TPR(port, pdc->dma_addr + xmit->tail);
-               UART_PUT_TCR(port, count);
-               /* re-enable PDC transmit */
-               UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
-               /* Enable interrupts */
-               UART_PUT_IER(port, atmel_port->tx_done_mask);
-       } else {
-               if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
-                       /* DMA done, stop TX, start RX for RS485 */
-                       atmel_start_rx(port);
-               }
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-}
-
-static void atmel_rx_from_ring(struct uart_port *port)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       struct circ_buf *ring = &atmel_port->rx_ring;
-       unsigned int flg;
-       unsigned int status;
-
-       while (ring->head != ring->tail) {
-               struct atmel_uart_char c;
-
-               /* Make sure c is loaded after head. */
-               smp_rmb();
-
-               c = ((struct atmel_uart_char *)ring->buf)[ring->tail];
-
-               ring->tail = (ring->tail + 1) & (ATMEL_SERIAL_RINGSIZE - 1);
-
-               port->icount.rx++;
-               status = c.status;
-               flg = TTY_NORMAL;
-
-               /*
-                * note that the error handling code is
-                * out of the main execution path
-                */
-               if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME
-                                      | ATMEL_US_OVRE | ATMEL_US_RXBRK))) {
-                       if (status & ATMEL_US_RXBRK) {
-                               /* ignore side-effect */
-                               status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME);
-
-                               port->icount.brk++;
-                               if (uart_handle_break(port))
-                                       continue;
-                       }
-                       if (status & ATMEL_US_PARE)
-                               port->icount.parity++;
-                       if (status & ATMEL_US_FRAME)
-                               port->icount.frame++;
-                       if (status & ATMEL_US_OVRE)
-                               port->icount.overrun++;
-
-                       status &= port->read_status_mask;
-
-                       if (status & ATMEL_US_RXBRK)
-                               flg = TTY_BREAK;
-                       else if (status & ATMEL_US_PARE)
-                               flg = TTY_PARITY;
-                       else if (status & ATMEL_US_FRAME)
-                               flg = TTY_FRAME;
-               }
-
-
-               if (uart_handle_sysrq_char(port, c.ch))
-                       continue;
-
-               uart_insert_char(port, status, ATMEL_US_OVRE, c.ch, flg);
-       }
-
-       /*
-        * Drop the lock here since it might end up calling
-        * uart_start(), which takes the lock.
-        */
-       spin_unlock(&port->lock);
-       tty_flip_buffer_push(port->state->port.tty);
-       spin_lock(&port->lock);
-}
-
-static void atmel_rx_from_dma(struct uart_port *port)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       struct tty_struct *tty = port->state->port.tty;
-       struct atmel_dma_buffer *pdc;
-       int rx_idx = atmel_port->pdc_rx_idx;
-       unsigned int head;
-       unsigned int tail;
-       unsigned int count;
-
-       do {
-               /* Reset the UART timeout early so that we don't miss one */
-               UART_PUT_CR(port, ATMEL_US_STTTO);
-
-               pdc = &atmel_port->pdc_rx[rx_idx];
-               head = UART_GET_RPR(port) - pdc->dma_addr;
-               tail = pdc->ofs;
-
-               /* If the PDC has switched buffers, RPR won't contain
-                * any address within the current buffer. Since head
-                * is unsigned, we just need a one-way comparison to
-                * find out.
-                *
-                * In this case, we just need to consume the entire
-                * buffer and resubmit it for DMA. This will clear the
-                * ENDRX bit as well, so that we can safely re-enable
-                * all interrupts below.
-                */
-               head = min(head, pdc->dma_size);
-
-               if (likely(head != tail)) {
-                       dma_sync_single_for_cpu(port->dev, pdc->dma_addr,
-                                       pdc->dma_size, DMA_FROM_DEVICE);
-
-                       /*
-                        * head will only wrap around when we recycle
-                        * the DMA buffer, and when that happens, we
-                        * explicitly set tail to 0. So head will
-                        * always be greater than tail.
-                        */
-                       count = head - tail;
-
-                       tty_insert_flip_string(tty, pdc->buf + pdc->ofs, count);
-
-                       dma_sync_single_for_device(port->dev, pdc->dma_addr,
-                                       pdc->dma_size, DMA_FROM_DEVICE);
-
-                       port->icount.rx += count;
-                       pdc->ofs = head;
-               }
-
-               /*
-                * If the current buffer is full, we need to check if
-                * the next one contains any additional data.
-                */
-               if (head >= pdc->dma_size) {
-                       pdc->ofs = 0;
-                       UART_PUT_RNPR(port, pdc->dma_addr);
-                       UART_PUT_RNCR(port, pdc->dma_size);
-
-                       rx_idx = !rx_idx;
-                       atmel_port->pdc_rx_idx = rx_idx;
-               }
-       } while (head >= pdc->dma_size);
-
-       /*
-        * Drop the lock here since it might end up calling
-        * uart_start(), which takes the lock.
-        */
-       spin_unlock(&port->lock);
-       tty_flip_buffer_push(tty);
-       spin_lock(&port->lock);
-
-       UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
-}
-
-/*
- * tasklet handling tty stuff outside the interrupt handler.
- */
-static void atmel_tasklet_func(unsigned long data)
-{
-       struct uart_port *port = (struct uart_port *)data;
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       unsigned int status;
-       unsigned int status_change;
-
-       /* The interrupt handler does not take the lock */
-       spin_lock(&port->lock);
-
-       if (atmel_use_dma_tx(port))
-               atmel_tx_dma(port);
-       else
-               atmel_tx_chars(port);
-
-       status = atmel_port->irq_status;
-       status_change = status ^ atmel_port->irq_status_prev;
-
-       if (status_change & (ATMEL_US_RI | ATMEL_US_DSR
-                               | ATMEL_US_DCD | ATMEL_US_CTS)) {
-               /* TODO: All reads to CSR will clear these interrupts! */
-               if (status_change & ATMEL_US_RI)
-                       port->icount.rng++;
-               if (status_change & ATMEL_US_DSR)
-                       port->icount.dsr++;
-               if (status_change & ATMEL_US_DCD)
-                       uart_handle_dcd_change(port, !(status & ATMEL_US_DCD));
-               if (status_change & ATMEL_US_CTS)
-                       uart_handle_cts_change(port, !(status & ATMEL_US_CTS));
-
-               wake_up_interruptible(&port->state->port.delta_msr_wait);
-
-               atmel_port->irq_status_prev = status;
-       }
-
-       if (atmel_use_dma_rx(port))
-               atmel_rx_from_dma(port);
-       else
-               atmel_rx_from_ring(port);
-
-       spin_unlock(&port->lock);
-}
-
-/*
- * Perform initialization and enable port for reception
- */
-static int atmel_startup(struct uart_port *port)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       struct tty_struct *tty = port->state->port.tty;
-       int retval;
-
-       /*
-        * Ensure that no interrupts are enabled otherwise when
-        * request_irq() is called we could get stuck trying to
-        * handle an unexpected interrupt
-        */
-       UART_PUT_IDR(port, -1);
-
-       /*
-        * Allocate the IRQ
-        */
-       retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED,
-                       tty ? tty->name : "atmel_serial", port);
-       if (retval) {
-               printk("atmel_serial: atmel_startup - Can't get irq\n");
-               return retval;
-       }
-
-       /*
-        * Initialize DMA (if necessary)
-        */
-       if (atmel_use_dma_rx(port)) {
-               int i;
-
-               for (i = 0; i < 2; i++) {
-                       struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
-
-                       pdc->buf = kmalloc(PDC_BUFFER_SIZE, GFP_KERNEL);
-                       if (pdc->buf == NULL) {
-                               if (i != 0) {
-                                       dma_unmap_single(port->dev,
-                                               atmel_port->pdc_rx[0].dma_addr,
-                                               PDC_BUFFER_SIZE,
-                                               DMA_FROM_DEVICE);
-                                       kfree(atmel_port->pdc_rx[0].buf);
-                               }
-                               free_irq(port->irq, port);
-                               return -ENOMEM;
-                       }
-                       pdc->dma_addr = dma_map_single(port->dev,
-                                                      pdc->buf,
-                                                      PDC_BUFFER_SIZE,
-                                                      DMA_FROM_DEVICE);
-                       pdc->dma_size = PDC_BUFFER_SIZE;
-                       pdc->ofs = 0;
-               }
-
-               atmel_port->pdc_rx_idx = 0;
-
-               UART_PUT_RPR(port, atmel_port->pdc_rx[0].dma_addr);
-               UART_PUT_RCR(port, PDC_BUFFER_SIZE);
-
-               UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr);
-               UART_PUT_RNCR(port, PDC_BUFFER_SIZE);
-       }
-       if (atmel_use_dma_tx(port)) {
-               struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
-               struct circ_buf *xmit = &port->state->xmit;
-
-               pdc->buf = xmit->buf;
-               pdc->dma_addr = dma_map_single(port->dev,
-                                              pdc->buf,
-                                              UART_XMIT_SIZE,
-                                              DMA_TO_DEVICE);
-               pdc->dma_size = UART_XMIT_SIZE;
-               pdc->ofs = 0;
-       }
-
-       /*
-        * If there is a specific "open" function (to register
-        * control line interrupts)
-        */
-       if (atmel_open_hook) {
-               retval = atmel_open_hook(port);
-               if (retval) {
-                       free_irq(port->irq, port);
-                       return retval;
-               }
-       }
-
-       /* Save current CSR for comparison in atmel_tasklet_func() */
-       atmel_port->irq_status_prev = UART_GET_CSR(port);
-       atmel_port->irq_status = atmel_port->irq_status_prev;
-
-       /*
-        * Finally, enable the serial port
-        */
-       UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
-       /* enable xmit & rcvr */
-       UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
-
-       if (atmel_use_dma_rx(port)) {
-               /* set UART timeout */
-               UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
-               UART_PUT_CR(port, ATMEL_US_STTTO);
-
-               UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
-               /* enable PDC controller */
-               UART_PUT_PTCR(port, ATMEL_PDC_RXTEN);
-       } else {
-               /* enable receive only */
-               UART_PUT_IER(port, ATMEL_US_RXRDY);
-       }
-
-       return 0;
-}
-
-/*
- * Disable the port
- */
-static void atmel_shutdown(struct uart_port *port)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       /*
-        * Ensure everything is stopped.
-        */
-       atmel_stop_rx(port);
-       atmel_stop_tx(port);
-
-       /*
-        * Shut-down the DMA.
-        */
-       if (atmel_use_dma_rx(port)) {
-               int i;
-
-               for (i = 0; i < 2; i++) {
-                       struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
-
-                       dma_unmap_single(port->dev,
-                                        pdc->dma_addr,
-                                        pdc->dma_size,
-                                        DMA_FROM_DEVICE);
-                       kfree(pdc->buf);
-               }
-       }
-       if (atmel_use_dma_tx(port)) {
-               struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
-
-               dma_unmap_single(port->dev,
-                                pdc->dma_addr,
-                                pdc->dma_size,
-                                DMA_TO_DEVICE);
-       }
-
-       /*
-        * Disable all interrupts, port and break condition.
-        */
-       UART_PUT_CR(port, ATMEL_US_RSTSTA);
-       UART_PUT_IDR(port, -1);
-
-       /*
-        * Free the interrupt
-        */
-       free_irq(port->irq, port);
-
-       /*
-        * If there is a specific "close" function (to unregister
-        * control line interrupts)
-        */
-       if (atmel_close_hook)
-               atmel_close_hook(port);
-}
-
-/*
- * Flush any TX data submitted for DMA. Called when the TX circular
- * buffer is reset.
- */
-static void atmel_flush_buffer(struct uart_port *port)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       if (atmel_use_dma_tx(port)) {
-               UART_PUT_TCR(port, 0);
-               atmel_port->pdc_tx.ofs = 0;
-       }
-}
-
-/*
- * Power / Clock management.
- */
-static void atmel_serial_pm(struct uart_port *port, unsigned int state,
-                           unsigned int oldstate)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       switch (state) {
-       case 0:
-               /*
-                * Enable the peripheral clock for this serial port.
-                * This is called on uart_open() or a resume event.
-                */
-               clk_enable(atmel_port->clk);
-
-               /* re-enable interrupts if we disabled some on suspend */
-               UART_PUT_IER(port, atmel_port->backup_imr);
-               break;
-       case 3:
-               /* Back up the interrupt mask and disable all interrupts */
-               atmel_port->backup_imr = UART_GET_IMR(port);
-               UART_PUT_IDR(port, -1);
-
-               /*
-                * Disable the peripheral clock for this serial port.
-                * This is called on uart_close() or a suspend event.
-                */
-               clk_disable(atmel_port->clk);
-               break;
-       default:
-               printk(KERN_ERR "atmel_serial: unknown pm %d\n", state);
-       }
-}
-
-/*
- * Change the port parameters
- */
-static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
-                             struct ktermios *old)
-{
-       unsigned long flags;
-       unsigned int mode, imr, quot, baud;
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       /* Get current mode register */
-       mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL
-                                       | ATMEL_US_NBSTOP | ATMEL_US_PAR
-                                       | ATMEL_US_USMODE);
-
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
-       quot = uart_get_divisor(port, baud);
-
-       if (quot > 65535) {     /* BRGR is 16-bit, so switch to slower clock */
-               quot /= 8;
-               mode |= ATMEL_US_USCLKS_MCK_DIV8;
-       }
-
-       /* byte size */
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               mode |= ATMEL_US_CHRL_5;
-               break;
-       case CS6:
-               mode |= ATMEL_US_CHRL_6;
-               break;
-       case CS7:
-               mode |= ATMEL_US_CHRL_7;
-               break;
-       default:
-               mode |= ATMEL_US_CHRL_8;
-               break;
-       }
-
-       /* stop bits */
-       if (termios->c_cflag & CSTOPB)
-               mode |= ATMEL_US_NBSTOP_2;
-
-       /* parity */
-       if (termios->c_cflag & PARENB) {
-               /* Mark or Space parity */
-               if (termios->c_cflag & CMSPAR) {
-                       if (termios->c_cflag & PARODD)
-                               mode |= ATMEL_US_PAR_MARK;
-                       else
-                               mode |= ATMEL_US_PAR_SPACE;
-               } else if (termios->c_cflag & PARODD)
-                       mode |= ATMEL_US_PAR_ODD;
-               else
-                       mode |= ATMEL_US_PAR_EVEN;
-       } else
-               mode |= ATMEL_US_PAR_NONE;
-
-       /* hardware handshake (RTS/CTS) */
-       if (termios->c_cflag & CRTSCTS)
-               mode |= ATMEL_US_USMODE_HWHS;
-       else
-               mode |= ATMEL_US_USMODE_NORMAL;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       port->read_status_mask = ATMEL_US_OVRE;
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE);
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               port->read_status_mask |= ATMEL_US_RXBRK;
-
-       if (atmel_use_dma_rx(port))
-               /* need to enable error interrupts */
-               UART_PUT_IER(port, port->read_status_mask);
-
-       /*
-        * Characters to ignore
-        */
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE);
-       if (termios->c_iflag & IGNBRK) {
-               port->ignore_status_mask |= ATMEL_US_RXBRK;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       port->ignore_status_mask |= ATMEL_US_OVRE;
-       }
-       /* TODO: Ignore all characters if CREAD is set.*/
-
-       /* update the per-port timeout */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       /*
-        * save/disable interrupts. The tty layer will ensure that the
-        * transmitter is empty if requested by the caller, so there's
-        * no need to wait for it here.
-        */
-       imr = UART_GET_IMR(port);
-       UART_PUT_IDR(port, -1);
-
-       /* disable receiver and transmitter */
-       UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS);
-
-       /* Resetting serial mode to RS232 (0x0) */
-       mode &= ~ATMEL_US_USMODE;
-
-       if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
-               dev_dbg(port->dev, "Setting UART to RS485\n");
-               if (atmel_port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
-                       UART_PUT_TTGR(port,
-                                       atmel_port->rs485.delay_rts_after_send);
-               mode |= ATMEL_US_USMODE_RS485;
-       } else {
-               dev_dbg(port->dev, "Setting UART to RS232\n");
-       }
-
-       /* set the parity, stop bits and data size */
-       UART_PUT_MR(port, mode);
-
-       /* set the baud rate */
-       UART_PUT_BRGR(port, quot);
-       UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
-       UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
-
-       /* restore interrupts */
-       UART_PUT_IER(port, imr);
-
-       /* CTS flow-control and modem-status interrupts */
-       if (UART_ENABLE_MS(port, termios->c_cflag))
-               port->ops->enable_ms(port);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/*
- * Return string describing the specified port
- */
-static const char *atmel_type(struct uart_port *port)
-{
-       return (port->type == PORT_ATMEL) ? "ATMEL_SERIAL" : NULL;
-}
-
-/*
- * Release the memory region(s) being used by 'port'.
- */
-static void atmel_release_port(struct uart_port *port)
-{
-       struct platform_device *pdev = to_platform_device(port->dev);
-       int size = pdev->resource[0].end - pdev->resource[0].start + 1;
-
-       release_mem_region(port->mapbase, size);
-
-       if (port->flags & UPF_IOREMAP) {
-               iounmap(port->membase);
-               port->membase = NULL;
-       }
-}
-
-/*
- * Request the memory region(s) being used by 'port'.
- */
-static int atmel_request_port(struct uart_port *port)
-{
-       struct platform_device *pdev = to_platform_device(port->dev);
-       int size = pdev->resource[0].end - pdev->resource[0].start + 1;
-
-       if (!request_mem_region(port->mapbase, size, "atmel_serial"))
-               return -EBUSY;
-
-       if (port->flags & UPF_IOREMAP) {
-               port->membase = ioremap(port->mapbase, size);
-               if (port->membase == NULL) {
-                       release_mem_region(port->mapbase, size);
-                       return -ENOMEM;
-               }
-       }
-
-       return 0;
-}
-
-/*
- * Configure/autoconfigure the port.
- */
-static void atmel_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE) {
-               port->type = PORT_ATMEL;
-               atmel_request_port(port);
-       }
-}
-
-/*
- * Verify the new serial_struct (for TIOCSSERIAL).
- */
-static int atmel_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       int ret = 0;
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_ATMEL)
-               ret = -EINVAL;
-       if (port->irq != ser->irq)
-               ret = -EINVAL;
-       if (ser->io_type != SERIAL_IO_MEM)
-               ret = -EINVAL;
-       if (port->uartclk / 16 != ser->baud_base)
-               ret = -EINVAL;
-       if ((void *)port->mapbase != ser->iomem_base)
-               ret = -EINVAL;
-       if (port->iobase != ser->port)
-               ret = -EINVAL;
-       if (ser->hub6 != 0)
-               ret = -EINVAL;
-       return ret;
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-static int atmel_poll_get_char(struct uart_port *port)
-{
-       while (!(UART_GET_CSR(port) & ATMEL_US_RXRDY))
-               cpu_relax();
-
-       return UART_GET_CHAR(port);
-}
-
-static void atmel_poll_put_char(struct uart_port *port, unsigned char ch)
-{
-       while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY))
-               cpu_relax();
-
-       UART_PUT_CHAR(port, ch);
-}
-#endif
-
-static int
-atmel_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
-{
-       struct serial_rs485 rs485conf;
-
-       switch (cmd) {
-       case TIOCSRS485:
-               if (copy_from_user(&rs485conf, (struct serial_rs485 *) arg,
-                                       sizeof(rs485conf)))
-                       return -EFAULT;
-
-               atmel_config_rs485(port, &rs485conf);
-               break;
-
-       case TIOCGRS485:
-               if (copy_to_user((struct serial_rs485 *) arg,
-                                       &(to_atmel_uart_port(port)->rs485),
-                                       sizeof(rs485conf)))
-                       return -EFAULT;
-               break;
-
-       default:
-               return -ENOIOCTLCMD;
-       }
-       return 0;
-}
-
-
-
-static struct uart_ops atmel_pops = {
-       .tx_empty       = atmel_tx_empty,
-       .set_mctrl      = atmel_set_mctrl,
-       .get_mctrl      = atmel_get_mctrl,
-       .stop_tx        = atmel_stop_tx,
-       .start_tx       = atmel_start_tx,
-       .stop_rx        = atmel_stop_rx,
-       .enable_ms      = atmel_enable_ms,
-       .break_ctl      = atmel_break_ctl,
-       .startup        = atmel_startup,
-       .shutdown       = atmel_shutdown,
-       .flush_buffer   = atmel_flush_buffer,
-       .set_termios    = atmel_set_termios,
-       .type           = atmel_type,
-       .release_port   = atmel_release_port,
-       .request_port   = atmel_request_port,
-       .config_port    = atmel_config_port,
-       .verify_port    = atmel_verify_port,
-       .pm             = atmel_serial_pm,
-       .ioctl          = atmel_ioctl,
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_get_char  = atmel_poll_get_char,
-       .poll_put_char  = atmel_poll_put_char,
-#endif
-};
-
-/*
- * Configure the port from the platform device resource info.
- */
-static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
-                                     struct platform_device *pdev)
-{
-       struct uart_port *port = &atmel_port->uart;
-       struct atmel_uart_data *data = pdev->dev.platform_data;
-
-       port->iotype            = UPIO_MEM;
-       port->flags             = UPF_BOOT_AUTOCONF;
-       port->ops               = &atmel_pops;
-       port->fifosize          = 1;
-       port->line              = pdev->id;
-       port->dev               = &pdev->dev;
-       port->mapbase   = pdev->resource[0].start;
-       port->irq       = pdev->resource[1].start;
-
-       tasklet_init(&atmel_port->tasklet, atmel_tasklet_func,
-                       (unsigned long)port);
-
-       memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
-
-       if (data->regs)
-               /* Already mapped by setup code */
-               port->membase = data->regs;
-       else {
-               port->flags     |= UPF_IOREMAP;
-               port->membase   = NULL;
-       }
-
-       /* for console, the clock could already be configured */
-       if (!atmel_port->clk) {
-               atmel_port->clk = clk_get(&pdev->dev, "usart");
-               clk_enable(atmel_port->clk);
-               port->uartclk = clk_get_rate(atmel_port->clk);
-               clk_disable(atmel_port->clk);
-               /* only enable clock when USART is in use */
-       }
-
-       atmel_port->use_dma_rx = data->use_dma_rx;
-       atmel_port->use_dma_tx = data->use_dma_tx;
-       atmel_port->rs485       = data->rs485;
-       /* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
-       if (atmel_port->rs485.flags & SER_RS485_ENABLED)
-               atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
-       else if (atmel_use_dma_tx(port)) {
-               port->fifosize = PDC_BUFFER_SIZE;
-               atmel_port->tx_done_mask = ATMEL_US_ENDTX | ATMEL_US_TXBUFE;
-       } else {
-               atmel_port->tx_done_mask = ATMEL_US_TXRDY;
-       }
-}
-
-/*
- * Register board-specific modem-control line handlers.
- */
-void __init atmel_register_uart_fns(struct atmel_port_fns *fns)
-{
-       if (fns->enable_ms)
-               atmel_pops.enable_ms = fns->enable_ms;
-       if (fns->get_mctrl)
-               atmel_pops.get_mctrl = fns->get_mctrl;
-       if (fns->set_mctrl)
-               atmel_pops.set_mctrl = fns->set_mctrl;
-       atmel_open_hook         = fns->open;
-       atmel_close_hook        = fns->close;
-       atmel_pops.pm           = fns->pm;
-       atmel_pops.set_wake     = fns->set_wake;
-}
-
-#ifdef CONFIG_SERIAL_ATMEL_CONSOLE
-static void atmel_console_putchar(struct uart_port *port, int ch)
-{
-       while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY))
-               cpu_relax();
-       UART_PUT_CHAR(port, ch);
-}
-
-/*
- * Interrupts are disabled on entering
- */
-static void atmel_console_write(struct console *co, const char *s, u_int count)
-{
-       struct uart_port *port = &atmel_ports[co->index].uart;
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       unsigned int status, imr;
-       unsigned int pdc_tx;
-
-       /*
-        * First, save IMR and then disable interrupts
-        */
-       imr = UART_GET_IMR(port);
-       UART_PUT_IDR(port, ATMEL_US_RXRDY | atmel_port->tx_done_mask);
-
-       /* Store PDC transmit status and disable it */
-       pdc_tx = UART_GET_PTSR(port) & ATMEL_PDC_TXTEN;
-       UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
-
-       uart_console_write(port, s, count, atmel_console_putchar);
-
-       /*
-        * Finally, wait for transmitter to become empty
-        * and restore IMR
-        */
-       do {
-               status = UART_GET_CSR(port);
-       } while (!(status & ATMEL_US_TXRDY));
-
-       /* Restore PDC transmit status */
-       if (pdc_tx)
-               UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
-
-       /* set interrupts back the way they were */
-       UART_PUT_IER(port, imr);
-}
-
-/*
- * If the port was already initialised (eg, by a boot loader),
- * try to determine the current setup.
- */
-static void __init atmel_console_get_options(struct uart_port *port, int *baud,
-                                            int *parity, int *bits)
-{
-       unsigned int mr, quot;
-
-       /*
-        * If the baud rate generator isn't running, the port wasn't
-        * initialized by the boot loader.
-        */
-       quot = UART_GET_BRGR(port) & ATMEL_US_CD;
-       if (!quot)
-               return;
-
-       mr = UART_GET_MR(port) & ATMEL_US_CHRL;
-       if (mr == ATMEL_US_CHRL_8)
-               *bits = 8;
-       else
-               *bits = 7;
-
-       mr = UART_GET_MR(port) & ATMEL_US_PAR;
-       if (mr == ATMEL_US_PAR_EVEN)
-               *parity = 'e';
-       else if (mr == ATMEL_US_PAR_ODD)
-               *parity = 'o';
-
-       /*
-        * The serial core only rounds down when matching this to a
-        * supported baud rate. Make sure we don't end up slightly
-        * lower than one of those, as it would make us fall through
-        * to a much lower baud rate than we really want.
-        */
-       *baud = port->uartclk / (16 * (quot - 1));
-}
-
-static int __init atmel_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port = &atmel_ports[co->index].uart;
-       int baud = 115200;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       if (port->membase == NULL) {
-               /* Port not initialized yet - delay setup */
-               return -ENODEV;
-       }
-
-       clk_enable(atmel_ports[co->index].clk);
-
-       UART_PUT_IDR(port, -1);
-       UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
-       UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               atmel_console_get_options(port, &baud, &parity, &bits);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver atmel_uart;
-
-static struct console atmel_console = {
-       .name           = ATMEL_DEVICENAME,
-       .write          = atmel_console_write,
-       .device         = uart_console_device,
-       .setup          = atmel_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &atmel_uart,
-};
-
-#define ATMEL_CONSOLE_DEVICE   (&atmel_console)
-
-/*
- * Early console initialization (before VM subsystem initialized).
- */
-static int __init atmel_console_init(void)
-{
-       if (atmel_default_console_device) {
-               add_preferred_console(ATMEL_DEVICENAME,
-                                     atmel_default_console_device->id, NULL);
-               atmel_init_port(&atmel_ports[atmel_default_console_device->id],
-                               atmel_default_console_device);
-               register_console(&atmel_console);
-       }
-
-       return 0;
-}
-
-console_initcall(atmel_console_init);
-
-/*
- * Late console initialization.
- */
-static int __init atmel_late_console_init(void)
-{
-       if (atmel_default_console_device
-           && !(atmel_console.flags & CON_ENABLED))
-               register_console(&atmel_console);
-
-       return 0;
-}
-
-core_initcall(atmel_late_console_init);
-
-static inline bool atmel_is_console_port(struct uart_port *port)
-{
-       return port->cons && port->cons->index == port->line;
-}
-
-#else
-#define ATMEL_CONSOLE_DEVICE   NULL
-
-static inline bool atmel_is_console_port(struct uart_port *port)
-{
-       return false;
-}
-#endif
-
-static struct uart_driver atmel_uart = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "atmel_serial",
-       .dev_name       = ATMEL_DEVICENAME,
-       .major          = SERIAL_ATMEL_MAJOR,
-       .minor          = MINOR_START,
-       .nr             = ATMEL_MAX_UART,
-       .cons           = ATMEL_CONSOLE_DEVICE,
-};
-
-#ifdef CONFIG_PM
-static bool atmel_serial_clk_will_stop(void)
-{
-#ifdef CONFIG_ARCH_AT91
-       return at91_suspend_entering_slow_clock();
-#else
-       return false;
-#endif
-}
-
-static int atmel_serial_suspend(struct platform_device *pdev,
-                               pm_message_t state)
-{
-       struct uart_port *port = platform_get_drvdata(pdev);
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       if (atmel_is_console_port(port) && console_suspend_enabled) {
-               /* Drain the TX shifter */
-               while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY))
-                       cpu_relax();
-       }
-
-       /* we can not wake up if we're running on slow clock */
-       atmel_port->may_wakeup = device_may_wakeup(&pdev->dev);
-       if (atmel_serial_clk_will_stop())
-               device_set_wakeup_enable(&pdev->dev, 0);
-
-       uart_suspend_port(&atmel_uart, port);
-
-       return 0;
-}
-
-static int atmel_serial_resume(struct platform_device *pdev)
-{
-       struct uart_port *port = platform_get_drvdata(pdev);
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       uart_resume_port(&atmel_uart, port);
-       device_set_wakeup_enable(&pdev->dev, atmel_port->may_wakeup);
-
-       return 0;
-}
-#else
-#define atmel_serial_suspend NULL
-#define atmel_serial_resume NULL
-#endif
-
-static int __devinit atmel_serial_probe(struct platform_device *pdev)
-{
-       struct atmel_uart_port *port;
-       void *data;
-       int ret;
-
-       BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
-
-       port = &atmel_ports[pdev->id];
-       port->backup_imr = 0;
-
-       atmel_init_port(port, pdev);
-
-       if (!atmel_use_dma_rx(&port->uart)) {
-               ret = -ENOMEM;
-               data = kmalloc(sizeof(struct atmel_uart_char)
-                               * ATMEL_SERIAL_RINGSIZE, GFP_KERNEL);
-               if (!data)
-                       goto err_alloc_ring;
-               port->rx_ring.buf = data;
-       }
-
-       ret = uart_add_one_port(&atmel_uart, &port->uart);
-       if (ret)
-               goto err_add_port;
-
-#ifdef CONFIG_SERIAL_ATMEL_CONSOLE
-       if (atmel_is_console_port(&port->uart)
-                       && ATMEL_CONSOLE_DEVICE->flags & CON_ENABLED) {
-               /*
-                * The serial core enabled the clock for us, so undo
-                * the clk_enable() in atmel_console_setup()
-                */
-               clk_disable(port->clk);
-       }
-#endif
-
-       device_init_wakeup(&pdev->dev, 1);
-       platform_set_drvdata(pdev, port);
-
-       return 0;
-
-err_add_port:
-       kfree(port->rx_ring.buf);
-       port->rx_ring.buf = NULL;
-err_alloc_ring:
-       if (!atmel_is_console_port(&port->uart)) {
-               clk_put(port->clk);
-               port->clk = NULL;
-       }
-
-       return ret;
-}
-
-static int __devexit atmel_serial_remove(struct platform_device *pdev)
-{
-       struct uart_port *port = platform_get_drvdata(pdev);
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       int ret = 0;
-
-       device_init_wakeup(&pdev->dev, 0);
-       platform_set_drvdata(pdev, NULL);
-
-       ret = uart_remove_one_port(&atmel_uart, port);
-
-       tasklet_kill(&atmel_port->tasklet);
-       kfree(atmel_port->rx_ring.buf);
-
-       /* "port" is allocated statically, so we shouldn't free it */
-
-       clk_put(atmel_port->clk);
-
-       return ret;
-}
-
-static struct platform_driver atmel_serial_driver = {
-       .probe          = atmel_serial_probe,
-       .remove         = __devexit_p(atmel_serial_remove),
-       .suspend        = atmel_serial_suspend,
-       .resume         = atmel_serial_resume,
-       .driver         = {
-               .name   = "atmel_usart",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init atmel_serial_init(void)
-{
-       int ret;
-
-       ret = uart_register_driver(&atmel_uart);
-       if (ret)
-               return ret;
-
-       ret = platform_driver_register(&atmel_serial_driver);
-       if (ret)
-               uart_unregister_driver(&atmel_uart);
-
-       return ret;
-}
-
-static void __exit atmel_serial_exit(void)
-{
-       platform_driver_unregister(&atmel_serial_driver);
-       uart_unregister_driver(&atmel_uart);
-}
-
-module_init(atmel_serial_init);
-module_exit(atmel_serial_exit);
-
-MODULE_AUTHOR("Rick Bronson");
-MODULE_DESCRIPTION("Atmel AT91 / AT32 serial port driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:atmel_usart");
diff --git a/drivers/serial/bcm63xx_uart.c b/drivers/serial/bcm63xx_uart.c
deleted file mode 100644 (file)
index a1a0e55..0000000
+++ /dev/null
@@ -1,891 +0,0 @@
-/*
- * 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.
- *
- * Derived from many drivers using generic_serial interface.
- *
- * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
- *
- *  Serial driver for BCM63xx integrated UART.
- *
- * Hardware flow control was _not_ tested since I only have RX/TX on
- * my board.
- */
-
-#if defined(CONFIG_SERIAL_BCM63XX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/console.h>
-#include <linux/clk.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/sysrq.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-
-#include <bcm63xx_clk.h>
-#include <bcm63xx_irq.h>
-#include <bcm63xx_regs.h>
-#include <bcm63xx_io.h>
-
-#define BCM63XX_NR_UARTS       2
-
-static struct uart_port ports[BCM63XX_NR_UARTS];
-
-/*
- * rx interrupt mask / stat
- *
- * mask:
- *  - rx fifo full
- *  - rx fifo above threshold
- *  - rx fifo not empty for too long
- */
-#define UART_RX_INT_MASK       (UART_IR_MASK(UART_IR_RXOVER) |         \
-                               UART_IR_MASK(UART_IR_RXTHRESH) |        \
-                               UART_IR_MASK(UART_IR_RXTIMEOUT))
-
-#define UART_RX_INT_STAT       (UART_IR_STAT(UART_IR_RXOVER) |         \
-                               UART_IR_STAT(UART_IR_RXTHRESH) |        \
-                               UART_IR_STAT(UART_IR_RXTIMEOUT))
-
-/*
- * tx interrupt mask / stat
- *
- * mask:
- * - tx fifo empty
- * - tx fifo below threshold
- */
-#define UART_TX_INT_MASK       (UART_IR_MASK(UART_IR_TXEMPTY) |        \
-                               UART_IR_MASK(UART_IR_TXTRESH))
-
-#define UART_TX_INT_STAT       (UART_IR_STAT(UART_IR_TXEMPTY) |        \
-                               UART_IR_STAT(UART_IR_TXTRESH))
-
-/*
- * external input interrupt
- *
- * mask: any edge on CTS, DCD
- */
-#define UART_EXTINP_INT_MASK   (UART_EXTINP_IRMASK(UART_EXTINP_IR_CTS) | \
-                                UART_EXTINP_IRMASK(UART_EXTINP_IR_DCD))
-
-/*
- * handy uart register accessor
- */
-static inline unsigned int bcm_uart_readl(struct uart_port *port,
-                                        unsigned int offset)
-{
-       return bcm_readl(port->membase + offset);
-}
-
-static inline void bcm_uart_writel(struct uart_port *port,
-                                 unsigned int value, unsigned int offset)
-{
-       bcm_writel(value, port->membase + offset);
-}
-
-/*
- * serial core request to check if uart tx fifo is empty
- */
-static unsigned int bcm_uart_tx_empty(struct uart_port *port)
-{
-       unsigned int val;
-
-       val = bcm_uart_readl(port, UART_IR_REG);
-       return (val & UART_IR_STAT(UART_IR_TXEMPTY)) ? 1 : 0;
-}
-
-/*
- * serial core request to set RTS and DTR pin state and loopback mode
- */
-static void bcm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       unsigned int val;
-
-       val = bcm_uart_readl(port, UART_MCTL_REG);
-       val &= ~(UART_MCTL_DTR_MASK | UART_MCTL_RTS_MASK);
-       /* invert of written value is reflected on the pin */
-       if (!(mctrl & TIOCM_DTR))
-               val |= UART_MCTL_DTR_MASK;
-       if (!(mctrl & TIOCM_RTS))
-               val |= UART_MCTL_RTS_MASK;
-       bcm_uart_writel(port, val, UART_MCTL_REG);
-
-       val = bcm_uart_readl(port, UART_CTL_REG);
-       if (mctrl & TIOCM_LOOP)
-               val |= UART_CTL_LOOPBACK_MASK;
-       else
-               val &= ~UART_CTL_LOOPBACK_MASK;
-       bcm_uart_writel(port, val, UART_CTL_REG);
-}
-
-/*
- * serial core request to return RI, CTS, DCD and DSR pin state
- */
-static unsigned int bcm_uart_get_mctrl(struct uart_port *port)
-{
-       unsigned int val, mctrl;
-
-       mctrl = 0;
-       val = bcm_uart_readl(port, UART_EXTINP_REG);
-       if (val & UART_EXTINP_RI_MASK)
-               mctrl |= TIOCM_RI;
-       if (val & UART_EXTINP_CTS_MASK)
-               mctrl |= TIOCM_CTS;
-       if (val & UART_EXTINP_DCD_MASK)
-               mctrl |= TIOCM_CD;
-       if (val & UART_EXTINP_DSR_MASK)
-               mctrl |= TIOCM_DSR;
-       return mctrl;
-}
-
-/*
- * serial core request to disable tx ASAP (used for flow control)
- */
-static void bcm_uart_stop_tx(struct uart_port *port)
-{
-       unsigned int val;
-
-       val = bcm_uart_readl(port, UART_CTL_REG);
-       val &= ~(UART_CTL_TXEN_MASK);
-       bcm_uart_writel(port, val, UART_CTL_REG);
-
-       val = bcm_uart_readl(port, UART_IR_REG);
-       val &= ~UART_TX_INT_MASK;
-       bcm_uart_writel(port, val, UART_IR_REG);
-}
-
-/*
- * serial core request to (re)enable tx
- */
-static void bcm_uart_start_tx(struct uart_port *port)
-{
-       unsigned int val;
-
-       val = bcm_uart_readl(port, UART_IR_REG);
-       val |= UART_TX_INT_MASK;
-       bcm_uart_writel(port, val, UART_IR_REG);
-
-       val = bcm_uart_readl(port, UART_CTL_REG);
-       val |= UART_CTL_TXEN_MASK;
-       bcm_uart_writel(port, val, UART_CTL_REG);
-}
-
-/*
- * serial core request to stop rx, called before port shutdown
- */
-static void bcm_uart_stop_rx(struct uart_port *port)
-{
-       unsigned int val;
-
-       val = bcm_uart_readl(port, UART_IR_REG);
-       val &= ~UART_RX_INT_MASK;
-       bcm_uart_writel(port, val, UART_IR_REG);
-}
-
-/*
- * serial core request to enable modem status interrupt reporting
- */
-static void bcm_uart_enable_ms(struct uart_port *port)
-{
-       unsigned int val;
-
-       val = bcm_uart_readl(port, UART_IR_REG);
-       val |= UART_IR_MASK(UART_IR_EXTIP);
-       bcm_uart_writel(port, val, UART_IR_REG);
-}
-
-/*
- * serial core request to start/stop emitting break char
- */
-static void bcm_uart_break_ctl(struct uart_port *port, int ctl)
-{
-       unsigned long flags;
-       unsigned int val;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       val = bcm_uart_readl(port, UART_CTL_REG);
-       if (ctl)
-               val |= UART_CTL_XMITBRK_MASK;
-       else
-               val &= ~UART_CTL_XMITBRK_MASK;
-       bcm_uart_writel(port, val, UART_CTL_REG);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/*
- * return port type in string format
- */
-static const char *bcm_uart_type(struct uart_port *port)
-{
-       return (port->type == PORT_BCM63XX) ? "bcm63xx_uart" : NULL;
-}
-
-/*
- * read all chars in rx fifo and send them to core
- */
-static void bcm_uart_do_rx(struct uart_port *port)
-{
-       struct tty_struct *tty;
-       unsigned int max_count;
-
-       /* limit number of char read in interrupt, should not be
-        * higher than fifo size anyway since we're much faster than
-        * serial port */
-       max_count = 32;
-       tty = port->state->port.tty;
-       do {
-               unsigned int iestat, c, cstat;
-               char flag;
-
-               /* get overrun/fifo empty information from ier
-                * register */
-               iestat = bcm_uart_readl(port, UART_IR_REG);
-               if (!(iestat & UART_IR_STAT(UART_IR_RXNOTEMPTY)))
-                       break;
-
-               cstat = c = bcm_uart_readl(port, UART_FIFO_REG);
-               port->icount.rx++;
-               flag = TTY_NORMAL;
-               c &= 0xff;
-
-               if (unlikely((cstat & UART_FIFO_ANYERR_MASK))) {
-                       /* do stats first */
-                       if (cstat & UART_FIFO_BRKDET_MASK) {
-                               port->icount.brk++;
-                               if (uart_handle_break(port))
-                                       continue;
-                       }
-
-                       if (cstat & UART_FIFO_PARERR_MASK)
-                               port->icount.parity++;
-                       if (cstat & UART_FIFO_FRAMEERR_MASK)
-                               port->icount.frame++;
-
-                       /* update flag wrt read_status_mask */
-                       cstat &= port->read_status_mask;
-                       if (cstat & UART_FIFO_BRKDET_MASK)
-                               flag = TTY_BREAK;
-                       if (cstat & UART_FIFO_FRAMEERR_MASK)
-                               flag = TTY_FRAME;
-                       if (cstat & UART_FIFO_PARERR_MASK)
-                               flag = TTY_PARITY;
-               }
-
-               if (uart_handle_sysrq_char(port, c))
-                       continue;
-
-               if (unlikely(iestat & UART_IR_STAT(UART_IR_RXOVER))) {
-                       port->icount.overrun++;
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               }
-
-               if ((cstat & port->ignore_status_mask) == 0)
-                       tty_insert_flip_char(tty, c, flag);
-
-       } while (--max_count);
-
-       tty_flip_buffer_push(tty);
-}
-
-/*
- * fill tx fifo with chars to send, stop when fifo is about to be full
- * or when all chars have been sent.
- */
-static void bcm_uart_do_tx(struct uart_port *port)
-{
-       struct circ_buf *xmit;
-       unsigned int val, max_count;
-
-       if (port->x_char) {
-               bcm_uart_writel(port, port->x_char, UART_FIFO_REG);
-               port->icount.tx++;
-               port->x_char = 0;
-               return;
-       }
-
-       if (uart_tx_stopped(port)) {
-               bcm_uart_stop_tx(port);
-               return;
-       }
-
-       xmit = &port->state->xmit;
-       if (uart_circ_empty(xmit))
-               goto txq_empty;
-
-       val = bcm_uart_readl(port, UART_MCTL_REG);
-       val = (val & UART_MCTL_TXFIFOFILL_MASK) >> UART_MCTL_TXFIFOFILL_SHIFT;
-       max_count = port->fifosize - val;
-
-       while (max_count--) {
-               unsigned int c;
-
-               c = xmit->buf[xmit->tail];
-               bcm_uart_writel(port, c, UART_FIFO_REG);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (uart_circ_empty(xmit))
-               goto txq_empty;
-       return;
-
-txq_empty:
-       /* nothing to send, disable transmit interrupt */
-       val = bcm_uart_readl(port, UART_IR_REG);
-       val &= ~UART_TX_INT_MASK;
-       bcm_uart_writel(port, val, UART_IR_REG);
-       return;
-}
-
-/*
- * process uart interrupt
- */
-static irqreturn_t bcm_uart_interrupt(int irq, void *dev_id)
-{
-       struct uart_port *port;
-       unsigned int irqstat;
-
-       port = dev_id;
-       spin_lock(&port->lock);
-
-       irqstat = bcm_uart_readl(port, UART_IR_REG);
-       if (irqstat & UART_RX_INT_STAT)
-               bcm_uart_do_rx(port);
-
-       if (irqstat & UART_TX_INT_STAT)
-               bcm_uart_do_tx(port);
-
-       if (irqstat & UART_IR_MASK(UART_IR_EXTIP)) {
-               unsigned int estat;
-
-               estat = bcm_uart_readl(port, UART_EXTINP_REG);
-               if (estat & UART_EXTINP_IRSTAT(UART_EXTINP_IR_CTS))
-                       uart_handle_cts_change(port,
-                                              estat & UART_EXTINP_CTS_MASK);
-               if (estat & UART_EXTINP_IRSTAT(UART_EXTINP_IR_DCD))
-                       uart_handle_dcd_change(port,
-                                              estat & UART_EXTINP_DCD_MASK);
-       }
-
-       spin_unlock(&port->lock);
-       return IRQ_HANDLED;
-}
-
-/*
- * enable rx & tx operation on uart
- */
-static void bcm_uart_enable(struct uart_port *port)
-{
-       unsigned int val;
-
-       val = bcm_uart_readl(port, UART_CTL_REG);
-       val |= (UART_CTL_BRGEN_MASK | UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK);
-       bcm_uart_writel(port, val, UART_CTL_REG);
-}
-
-/*
- * disable rx & tx operation on uart
- */
-static void bcm_uart_disable(struct uart_port *port)
-{
-       unsigned int val;
-
-       val = bcm_uart_readl(port, UART_CTL_REG);
-       val &= ~(UART_CTL_BRGEN_MASK | UART_CTL_TXEN_MASK |
-                UART_CTL_RXEN_MASK);
-       bcm_uart_writel(port, val, UART_CTL_REG);
-}
-
-/*
- * clear all unread data in rx fifo and unsent data in tx fifo
- */
-static void bcm_uart_flush(struct uart_port *port)
-{
-       unsigned int val;
-
-       /* empty rx and tx fifo */
-       val = bcm_uart_readl(port, UART_CTL_REG);
-       val |= UART_CTL_RSTRXFIFO_MASK | UART_CTL_RSTTXFIFO_MASK;
-       bcm_uart_writel(port, val, UART_CTL_REG);
-
-       /* read any pending char to make sure all irq status are
-        * cleared */
-       (void)bcm_uart_readl(port, UART_FIFO_REG);
-}
-
-/*
- * serial core request to initialize uart and start rx operation
- */
-static int bcm_uart_startup(struct uart_port *port)
-{
-       unsigned int val;
-       int ret;
-
-       /* mask all irq and flush port */
-       bcm_uart_disable(port);
-       bcm_uart_writel(port, 0, UART_IR_REG);
-       bcm_uart_flush(port);
-
-       /* clear any pending external input interrupt */
-       (void)bcm_uart_readl(port, UART_EXTINP_REG);
-
-       /* set rx/tx fifo thresh to fifo half size */
-       val = bcm_uart_readl(port, UART_MCTL_REG);
-       val &= ~(UART_MCTL_RXFIFOTHRESH_MASK | UART_MCTL_TXFIFOTHRESH_MASK);
-       val |= (port->fifosize / 2) << UART_MCTL_RXFIFOTHRESH_SHIFT;
-       val |= (port->fifosize / 2) << UART_MCTL_TXFIFOTHRESH_SHIFT;
-       bcm_uart_writel(port, val, UART_MCTL_REG);
-
-       /* set rx fifo timeout to 1 char time */
-       val = bcm_uart_readl(port, UART_CTL_REG);
-       val &= ~UART_CTL_RXTMOUTCNT_MASK;
-       val |= 1 << UART_CTL_RXTMOUTCNT_SHIFT;
-       bcm_uart_writel(port, val, UART_CTL_REG);
-
-       /* report any edge on dcd and cts */
-       val = UART_EXTINP_INT_MASK;
-       val |= UART_EXTINP_DCD_NOSENSE_MASK;
-       val |= UART_EXTINP_CTS_NOSENSE_MASK;
-       bcm_uart_writel(port, val, UART_EXTINP_REG);
-
-       /* register irq and enable rx interrupts */
-       ret = request_irq(port->irq, bcm_uart_interrupt, 0,
-                         bcm_uart_type(port), port);
-       if (ret)
-               return ret;
-       bcm_uart_writel(port, UART_RX_INT_MASK, UART_IR_REG);
-       bcm_uart_enable(port);
-       return 0;
-}
-
-/*
- * serial core request to flush & disable uart
- */
-static void bcm_uart_shutdown(struct uart_port *port)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       bcm_uart_writel(port, 0, UART_IR_REG);
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       bcm_uart_disable(port);
-       bcm_uart_flush(port);
-       free_irq(port->irq, port);
-}
-
-/*
- * serial core request to change current uart setting
- */
-static void bcm_uart_set_termios(struct uart_port *port,
-                                struct ktermios *new,
-                                struct ktermios *old)
-{
-       unsigned int ctl, baud, quot, ier;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /* disable uart while changing speed */
-       bcm_uart_disable(port);
-       bcm_uart_flush(port);
-
-       /* update Control register */
-       ctl = bcm_uart_readl(port, UART_CTL_REG);
-       ctl &= ~UART_CTL_BITSPERSYM_MASK;
-
-       switch (new->c_cflag & CSIZE) {
-       case CS5:
-               ctl |= (0 << UART_CTL_BITSPERSYM_SHIFT);
-               break;
-       case CS6:
-               ctl |= (1 << UART_CTL_BITSPERSYM_SHIFT);
-               break;
-       case CS7:
-               ctl |= (2 << UART_CTL_BITSPERSYM_SHIFT);
-               break;
-       default:
-               ctl |= (3 << UART_CTL_BITSPERSYM_SHIFT);
-               break;
-       }
-
-       ctl &= ~UART_CTL_STOPBITS_MASK;
-       if (new->c_cflag & CSTOPB)
-               ctl |= UART_CTL_STOPBITS_2;
-       else
-               ctl |= UART_CTL_STOPBITS_1;
-
-       ctl &= ~(UART_CTL_RXPAREN_MASK | UART_CTL_TXPAREN_MASK);
-       if (new->c_cflag & PARENB)
-               ctl |= (UART_CTL_RXPAREN_MASK | UART_CTL_TXPAREN_MASK);
-       ctl &= ~(UART_CTL_RXPAREVEN_MASK | UART_CTL_TXPAREVEN_MASK);
-       if (new->c_cflag & PARODD)
-               ctl |= (UART_CTL_RXPAREVEN_MASK | UART_CTL_TXPAREVEN_MASK);
-       bcm_uart_writel(port, ctl, UART_CTL_REG);
-
-       /* update Baudword register */
-       baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
-       quot = uart_get_divisor(port, baud) - 1;
-       bcm_uart_writel(port, quot, UART_BAUD_REG);
-
-       /* update Interrupt register */
-       ier = bcm_uart_readl(port, UART_IR_REG);
-
-       ier &= ~UART_IR_MASK(UART_IR_EXTIP);
-       if (UART_ENABLE_MS(port, new->c_cflag))
-               ier |= UART_IR_MASK(UART_IR_EXTIP);
-
-       bcm_uart_writel(port, ier, UART_IR_REG);
-
-       /* update read/ignore mask */
-       port->read_status_mask = UART_FIFO_VALID_MASK;
-       if (new->c_iflag & INPCK) {
-               port->read_status_mask |= UART_FIFO_FRAMEERR_MASK;
-               port->read_status_mask |= UART_FIFO_PARERR_MASK;
-       }
-       if (new->c_iflag & (BRKINT))
-               port->read_status_mask |= UART_FIFO_BRKDET_MASK;
-
-       port->ignore_status_mask = 0;
-       if (new->c_iflag & IGNPAR)
-               port->ignore_status_mask |= UART_FIFO_PARERR_MASK;
-       if (new->c_iflag & IGNBRK)
-               port->ignore_status_mask |= UART_FIFO_BRKDET_MASK;
-       if (!(new->c_cflag & CREAD))
-               port->ignore_status_mask |= UART_FIFO_VALID_MASK;
-
-       uart_update_timeout(port, new->c_cflag, baud);
-       bcm_uart_enable(port);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/*
- * serial core request to claim uart iomem
- */
-static int bcm_uart_request_port(struct uart_port *port)
-{
-       unsigned int size;
-
-       size = RSET_UART_SIZE;
-       if (!request_mem_region(port->mapbase, size, "bcm63xx")) {
-               dev_err(port->dev, "Memory region busy\n");
-               return -EBUSY;
-       }
-
-       port->membase = ioremap(port->mapbase, size);
-       if (!port->membase) {
-               dev_err(port->dev, "Unable to map registers\n");
-               release_mem_region(port->mapbase, size);
-               return -EBUSY;
-       }
-       return 0;
-}
-
-/*
- * serial core request to release uart iomem
- */
-static void bcm_uart_release_port(struct uart_port *port)
-{
-       release_mem_region(port->mapbase, RSET_UART_SIZE);
-       iounmap(port->membase);
-}
-
-/*
- * serial core request to do any port required autoconfiguration
- */
-static void bcm_uart_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE) {
-               if (bcm_uart_request_port(port))
-                       return;
-               port->type = PORT_BCM63XX;
-       }
-}
-
-/*
- * serial core request to check that port information in serinfo are
- * suitable
- */
-static int bcm_uart_verify_port(struct uart_port *port,
-                               struct serial_struct *serinfo)
-{
-       if (port->type != PORT_BCM63XX)
-               return -EINVAL;
-       if (port->irq != serinfo->irq)
-               return -EINVAL;
-       if (port->iotype != serinfo->io_type)
-               return -EINVAL;
-       if (port->mapbase != (unsigned long)serinfo->iomem_base)
-               return -EINVAL;
-       return 0;
-}
-
-/* serial core callbacks */
-static struct uart_ops bcm_uart_ops = {
-       .tx_empty       = bcm_uart_tx_empty,
-       .get_mctrl      = bcm_uart_get_mctrl,
-       .set_mctrl      = bcm_uart_set_mctrl,
-       .start_tx       = bcm_uart_start_tx,
-       .stop_tx        = bcm_uart_stop_tx,
-       .stop_rx        = bcm_uart_stop_rx,
-       .enable_ms      = bcm_uart_enable_ms,
-       .break_ctl      = bcm_uart_break_ctl,
-       .startup        = bcm_uart_startup,
-       .shutdown       = bcm_uart_shutdown,
-       .set_termios    = bcm_uart_set_termios,
-       .type           = bcm_uart_type,
-       .release_port   = bcm_uart_release_port,
-       .request_port   = bcm_uart_request_port,
-       .config_port    = bcm_uart_config_port,
-       .verify_port    = bcm_uart_verify_port,
-};
-
-
-
-#ifdef CONFIG_SERIAL_BCM63XX_CONSOLE
-static inline void wait_for_xmitr(struct uart_port *port)
-{
-       unsigned int tmout;
-
-       /* Wait up to 10ms for the character(s) to be sent. */
-       tmout = 10000;
-       while (--tmout) {
-               unsigned int val;
-
-               val = bcm_uart_readl(port, UART_IR_REG);
-               if (val & UART_IR_STAT(UART_IR_TXEMPTY))
-                       break;
-               udelay(1);
-       }
-
-       /* Wait up to 1s for flow control if necessary */
-       if (port->flags & UPF_CONS_FLOW) {
-               tmout = 1000000;
-               while (--tmout) {
-                       unsigned int val;
-
-                       val = bcm_uart_readl(port, UART_EXTINP_REG);
-                       if (val & UART_EXTINP_CTS_MASK)
-                               break;
-                       udelay(1);
-               }
-       }
-}
-
-/*
- * output given char
- */
-static void bcm_console_putchar(struct uart_port *port, int ch)
-{
-       wait_for_xmitr(port);
-       bcm_uart_writel(port, ch, UART_FIFO_REG);
-}
-
-/*
- * console core request to output given string
- */
-static void bcm_console_write(struct console *co, const char *s,
-                             unsigned int count)
-{
-       struct uart_port *port;
-       unsigned long flags;
-       int locked;
-
-       port = &ports[co->index];
-
-       local_irq_save(flags);
-       if (port->sysrq) {
-               /* bcm_uart_interrupt() already took the lock */
-               locked = 0;
-       } else if (oops_in_progress) {
-               locked = spin_trylock(&port->lock);
-       } else {
-               spin_lock(&port->lock);
-               locked = 1;
-       }
-
-       /* call helper to deal with \r\n */
-       uart_console_write(port, s, count, bcm_console_putchar);
-
-       /* and wait for char to be transmitted */
-       wait_for_xmitr(port);
-
-       if (locked)
-               spin_unlock(&port->lock);
-       local_irq_restore(flags);
-}
-
-/*
- * console core request to setup given console, find matching uart
- * port and setup it.
- */
-static int bcm_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       if (co->index < 0 || co->index >= BCM63XX_NR_UARTS)
-               return -EINVAL;
-       port = &ports[co->index];
-       if (!port->membase)
-               return -ENODEV;
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver bcm_uart_driver;
-
-static struct console bcm63xx_console = {
-       .name           = "ttyS",
-       .write          = bcm_console_write,
-       .device         = uart_console_device,
-       .setup          = bcm_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &bcm_uart_driver,
-};
-
-static int __init bcm63xx_console_init(void)
-{
-       register_console(&bcm63xx_console);
-       return 0;
-}
-
-console_initcall(bcm63xx_console_init);
-
-#define BCM63XX_CONSOLE        (&bcm63xx_console)
-#else
-#define BCM63XX_CONSOLE        NULL
-#endif /* CONFIG_SERIAL_BCM63XX_CONSOLE */
-
-static struct uart_driver bcm_uart_driver = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "bcm63xx_uart",
-       .dev_name       = "ttyS",
-       .major          = TTY_MAJOR,
-       .minor          = 64,
-       .nr             = BCM63XX_NR_UARTS,
-       .cons           = BCM63XX_CONSOLE,
-};
-
-/*
- * platform driver probe/remove callback
- */
-static int __devinit bcm_uart_probe(struct platform_device *pdev)
-{
-       struct resource *res_mem, *res_irq;
-       struct uart_port *port;
-       struct clk *clk;
-       int ret;
-
-       if (pdev->id < 0 || pdev->id >= BCM63XX_NR_UARTS)
-               return -EINVAL;
-
-       if (ports[pdev->id].membase)
-               return -EBUSY;
-
-       res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res_mem)
-               return -ENODEV;
-
-       res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!res_irq)
-               return -ENODEV;
-
-       clk = clk_get(&pdev->dev, "periph");
-       if (IS_ERR(clk))
-               return -ENODEV;
-
-       port = &ports[pdev->id];
-       memset(port, 0, sizeof(*port));
-       port->iotype = UPIO_MEM;
-       port->mapbase = res_mem->start;
-       port->irq = res_irq->start;
-       port->ops = &bcm_uart_ops;
-       port->flags = UPF_BOOT_AUTOCONF;
-       port->dev = &pdev->dev;
-       port->fifosize = 16;
-       port->uartclk = clk_get_rate(clk) / 2;
-       port->line = pdev->id;
-       clk_put(clk);
-
-       ret = uart_add_one_port(&bcm_uart_driver, port);
-       if (ret) {
-               ports[pdev->id].membase = 0;
-               return ret;
-       }
-       platform_set_drvdata(pdev, port);
-       return 0;
-}
-
-static int __devexit bcm_uart_remove(struct platform_device *pdev)
-{
-       struct uart_port *port;
-
-       port = platform_get_drvdata(pdev);
-       uart_remove_one_port(&bcm_uart_driver, port);
-       platform_set_drvdata(pdev, NULL);
-       /* mark port as free */
-       ports[pdev->id].membase = 0;
-       return 0;
-}
-
-/*
- * platform driver stuff
- */
-static struct platform_driver bcm_uart_platform_driver = {
-       .probe  = bcm_uart_probe,
-       .remove = __devexit_p(bcm_uart_remove),
-       .driver = {
-               .owner = THIS_MODULE,
-               .name  = "bcm63xx_uart",
-       },
-};
-
-static int __init bcm_uart_init(void)
-{
-       int ret;
-
-       ret = uart_register_driver(&bcm_uart_driver);
-       if (ret)
-               return ret;
-
-       ret = platform_driver_register(&bcm_uart_platform_driver);
-       if (ret)
-               uart_unregister_driver(&bcm_uart_driver);
-
-       return ret;
-}
-
-static void __exit bcm_uart_exit(void)
-{
-       platform_driver_unregister(&bcm_uart_platform_driver);
-       uart_unregister_driver(&bcm_uart_driver);
-}
-
-module_init(bcm_uart_init);
-module_exit(bcm_uart_exit);
-
-MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>");
-MODULE_DESCRIPTION("Broadcom 63<xx integrated uart driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
deleted file mode 100644 (file)
index e381b89..0000000
+++ /dev/null
@@ -1,1600 +0,0 @@
-/*
- * Blackfin On-Chip Serial Driver
- *
- * Copyright 2006-2010 Analog Devices Inc.
- *
- * Enter bugs at http://blackfin.uclinux.org/
- *
- * Licensed under the GPL-2 or later.
- */
-
-#if defined(CONFIG_SERIAL_BFIN_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#define DRIVER_NAME "bfin-uart"
-#define pr_fmt(fmt) DRIVER_NAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/gfp.h>
-#include <linux/io.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/platform_device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/gpio.h>
-#include <linux/irq.h>
-#include <linux/kgdb.h>
-#include <linux/slab.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/portmux.h>
-#include <asm/cacheflush.h>
-#include <asm/dma.h>
-
-#define port_membase(uart)     (((struct bfin_serial_port *)(uart))->port.membase)
-#define get_lsr_cache(uart)    (((struct bfin_serial_port *)(uart))->lsr)
-#define put_lsr_cache(uart, v) (((struct bfin_serial_port *)(uart))->lsr = (v))
-#include <asm/bfin_serial.h>
-
-#ifdef CONFIG_SERIAL_BFIN_MODULE
-# undef CONFIG_EARLY_PRINTK
-#endif
-
-#ifdef CONFIG_SERIAL_BFIN_MODULE
-# undef CONFIG_EARLY_PRINTK
-#endif
-
-/* UART name and device definitions */
-#define BFIN_SERIAL_DEV_NAME   "ttyBF"
-#define BFIN_SERIAL_MAJOR      204
-#define BFIN_SERIAL_MINOR      64
-
-static struct bfin_serial_port *bfin_serial_ports[BFIN_UART_NR_PORTS];
-
-#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
-       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
-
-# ifndef CONFIG_SERIAL_BFIN_PIO
-#  error KGDB only support UART in PIO mode.
-# endif
-
-static int kgdboc_port_line;
-static int kgdboc_break_enabled;
-#endif
-/*
- * Setup for console. Argument comes from the menuconfig
- */
-#define DMA_RX_XCOUNT          512
-#define DMA_RX_YCOUNT          (PAGE_SIZE / DMA_RX_XCOUNT)
-
-#define DMA_RX_FLUSH_JIFFIES   (HZ / 50)
-
-#ifdef CONFIG_SERIAL_BFIN_DMA
-static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart);
-#else
-static void bfin_serial_tx_chars(struct bfin_serial_port *uart);
-#endif
-
-static void bfin_serial_reset_irda(struct uart_port *port);
-
-#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
-       defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
-static unsigned int bfin_serial_get_mctrl(struct uart_port *port)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-       if (uart->cts_pin < 0)
-               return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
-
-       /* CTS PIN is negative assertive. */
-       if (UART_GET_CTS(uart))
-               return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
-       else
-               return TIOCM_DSR | TIOCM_CAR;
-}
-
-static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-       if (uart->rts_pin < 0)
-               return;
-
-       /* RTS PIN is negative assertive. */
-       if (mctrl & TIOCM_RTS)
-               UART_ENABLE_RTS(uart);
-       else
-               UART_DISABLE_RTS(uart);
-}
-
-/*
- * Handle any change of modem status signal.
- */
-static irqreturn_t bfin_serial_mctrl_cts_int(int irq, void *dev_id)
-{
-       struct bfin_serial_port *uart = dev_id;
-       unsigned int status;
-
-       status = bfin_serial_get_mctrl(&uart->port);
-       uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
-       uart->scts = 1;
-       UART_CLEAR_SCTS(uart);
-       UART_CLEAR_IER(uart, EDSSI);
-#endif
-
-       return IRQ_HANDLED;
-}
-#else
-static unsigned int bfin_serial_get_mctrl(struct uart_port *port)
-{
-       return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
-}
-
-static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-}
-#endif
-
-/*
- * interrupts are disabled on entry
- */
-static void bfin_serial_stop_tx(struct uart_port *port)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       struct circ_buf *xmit = &uart->port.state->xmit;
-#endif
-
-       while (!(UART_GET_LSR(uart) & TEMT))
-               cpu_relax();
-
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       disable_dma(uart->tx_dma_channel);
-       xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
-       uart->port.icount.tx += uart->tx_count;
-       uart->tx_count = 0;
-       uart->tx_done = 1;
-#else
-#ifdef CONFIG_BF54x
-       /* Clear TFI bit */
-       UART_PUT_LSR(uart, TFI);
-#endif
-       UART_CLEAR_IER(uart, ETBEI);
-#endif
-}
-
-/*
- * port is locked and interrupts are disabled
- */
-static void bfin_serial_start_tx(struct uart_port *port)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-       struct tty_struct *tty = uart->port.state->port.tty;
-
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
-       if (uart->scts && !(bfin_serial_get_mctrl(&uart->port) & TIOCM_CTS)) {
-               uart->scts = 0;
-               uart_handle_cts_change(&uart->port, uart->scts);
-       }
-#endif
-
-       /*
-        * To avoid losting RX interrupt, we reset IR function
-        * before sending data.
-        */
-       if (tty->termios->c_line == N_IRDA)
-               bfin_serial_reset_irda(port);
-
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       if (uart->tx_done)
-               bfin_serial_dma_tx_chars(uart);
-#else
-       UART_SET_IER(uart, ETBEI);
-       bfin_serial_tx_chars(uart);
-#endif
-}
-
-/*
- * Interrupts are enabled
- */
-static void bfin_serial_stop_rx(struct uart_port *port)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-
-       UART_CLEAR_IER(uart, ERBFI);
-}
-
-/*
- * Set the modem control timer to fire immediately.
- */
-static void bfin_serial_enable_ms(struct uart_port *port)
-{
-}
-
-
-#if ANOMALY_05000363 && defined(CONFIG_SERIAL_BFIN_PIO)
-# define UART_GET_ANOMALY_THRESHOLD(uart)    ((uart)->anomaly_threshold)
-# define UART_SET_ANOMALY_THRESHOLD(uart, v) ((uart)->anomaly_threshold = (v))
-#else
-# define UART_GET_ANOMALY_THRESHOLD(uart)    0
-# define UART_SET_ANOMALY_THRESHOLD(uart, v)
-#endif
-
-#ifdef CONFIG_SERIAL_BFIN_PIO
-static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
-{
-       struct tty_struct *tty = NULL;
-       unsigned int status, ch, flg;
-       static struct timeval anomaly_start = { .tv_sec = 0 };
-
-       status = UART_GET_LSR(uart);
-       UART_CLEAR_LSR(uart);
-
-       ch = UART_GET_CHAR(uart);
-       uart->port.icount.rx++;
-
-#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
-       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
-       if (kgdb_connected && kgdboc_port_line == uart->port.line
-               && kgdboc_break_enabled)
-               if (ch == 0x3) {/* Ctrl + C */
-                       kgdb_breakpoint();
-                       return;
-               }
-
-       if (!uart->port.state || !uart->port.state->port.tty)
-               return;
-#endif
-       tty = uart->port.state->port.tty;
-
-       if (ANOMALY_05000363) {
-               /* The BF533 (and BF561) family of processors have a nice anomaly
-                * where they continuously generate characters for a "single" break.
-                * We have to basically ignore this flood until the "next" valid
-                * character comes across.  Due to the nature of the flood, it is
-                * not possible to reliably catch bytes that are sent too quickly
-                * after this break.  So application code talking to the Blackfin
-                * which sends a break signal must allow at least 1.5 character
-                * times after the end of the break for things to stabilize.  This
-                * timeout was picked as it must absolutely be larger than 1
-                * character time +/- some percent.  So 1.5 sounds good.  All other
-                * Blackfin families operate properly.  Woo.
-                */
-               if (anomaly_start.tv_sec) {
-                       struct timeval curr;
-                       suseconds_t usecs;
-
-                       if ((~ch & (~ch + 1)) & 0xff)
-                               goto known_good_char;
-
-                       do_gettimeofday(&curr);
-                       if (curr.tv_sec - anomaly_start.tv_sec > 1)
-                               goto known_good_char;
-
-                       usecs = 0;
-                       if (curr.tv_sec != anomaly_start.tv_sec)
-                               usecs += USEC_PER_SEC;
-                       usecs += curr.tv_usec - anomaly_start.tv_usec;
-
-                       if (usecs > UART_GET_ANOMALY_THRESHOLD(uart))
-                               goto known_good_char;
-
-                       if (ch)
-                               anomaly_start.tv_sec = 0;
-                       else
-                               anomaly_start = curr;
-
-                       return;
-
- known_good_char:
-                       status &= ~BI;
-                       anomaly_start.tv_sec = 0;
-               }
-       }
-
-       if (status & BI) {
-               if (ANOMALY_05000363)
-                       if (bfin_revid() < 5)
-                               do_gettimeofday(&anomaly_start);
-               uart->port.icount.brk++;
-               if (uart_handle_break(&uart->port))
-                       goto ignore_char;
-               status &= ~(PE | FE);
-       }
-       if (status & PE)
-               uart->port.icount.parity++;
-       if (status & OE)
-               uart->port.icount.overrun++;
-       if (status & FE)
-               uart->port.icount.frame++;
-
-       status &= uart->port.read_status_mask;
-
-       if (status & BI)
-               flg = TTY_BREAK;
-       else if (status & PE)
-               flg = TTY_PARITY;
-       else if (status & FE)
-               flg = TTY_FRAME;
-       else
-               flg = TTY_NORMAL;
-
-       if (uart_handle_sysrq_char(&uart->port, ch))
-               goto ignore_char;
-
-       uart_insert_char(&uart->port, status, OE, ch, flg);
-
- ignore_char:
-       tty_flip_buffer_push(tty);
-}
-
-static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
-{
-       struct circ_buf *xmit = &uart->port.state->xmit;
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
-#ifdef CONFIG_BF54x
-               /* Clear TFI bit */
-               UART_PUT_LSR(uart, TFI);
-#endif
-               /* Anomaly notes:
-                *  05000215 -  we always clear ETBEI within last UART TX
-                *              interrupt to end a string. It is always set
-                *              when start a new tx.
-                */
-               UART_CLEAR_IER(uart, ETBEI);
-               return;
-       }
-
-       if (uart->port.x_char) {
-               UART_PUT_CHAR(uart, uart->port.x_char);
-               uart->port.icount.tx++;
-               uart->port.x_char = 0;
-       }
-
-       while ((UART_GET_LSR(uart) & THRE) && xmit->tail != xmit->head) {
-               UART_PUT_CHAR(uart, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               uart->port.icount.tx++;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&uart->port);
-}
-
-static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id)
-{
-       struct bfin_serial_port *uart = dev_id;
-
-       spin_lock(&uart->port.lock);
-       while (UART_GET_LSR(uart) & DR)
-               bfin_serial_rx_chars(uart);
-       spin_unlock(&uart->port.lock);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id)
-{
-       struct bfin_serial_port *uart = dev_id;
-
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
-       if (uart->scts && !(bfin_serial_get_mctrl(&uart->port) & TIOCM_CTS)) {
-               uart->scts = 0;
-               uart_handle_cts_change(&uart->port, uart->scts);
-       }
-#endif
-       spin_lock(&uart->port.lock);
-       if (UART_GET_LSR(uart) & THRE)
-               bfin_serial_tx_chars(uart);
-       spin_unlock(&uart->port.lock);
-
-       return IRQ_HANDLED;
-}
-#endif
-
-#ifdef CONFIG_SERIAL_BFIN_DMA
-static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
-{
-       struct circ_buf *xmit = &uart->port.state->xmit;
-
-       uart->tx_done = 0;
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
-               uart->tx_count = 0;
-               uart->tx_done = 1;
-               return;
-       }
-
-       if (uart->port.x_char) {
-               UART_PUT_CHAR(uart, uart->port.x_char);
-               uart->port.icount.tx++;
-               uart->port.x_char = 0;
-       }
-
-       uart->tx_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);
-       if (uart->tx_count > (UART_XMIT_SIZE - xmit->tail))
-               uart->tx_count = UART_XMIT_SIZE - xmit->tail;
-       blackfin_dcache_flush_range((unsigned long)(xmit->buf+xmit->tail),
-                                       (unsigned long)(xmit->buf+xmit->tail+uart->tx_count));
-       set_dma_config(uart->tx_dma_channel,
-               set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP,
-                       INTR_ON_BUF,
-                       DIMENSION_LINEAR,
-                       DATA_SIZE_8,
-                       DMA_SYNC_RESTART));
-       set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail));
-       set_dma_x_count(uart->tx_dma_channel, uart->tx_count);
-       set_dma_x_modify(uart->tx_dma_channel, 1);
-       SSYNC();
-       enable_dma(uart->tx_dma_channel);
-
-       UART_SET_IER(uart, ETBEI);
-}
-
-static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
-{
-       struct tty_struct *tty = uart->port.state->port.tty;
-       int i, flg, status;
-
-       status = UART_GET_LSR(uart);
-       UART_CLEAR_LSR(uart);
-
-       uart->port.icount.rx +=
-               CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail,
-               UART_XMIT_SIZE);
-
-       if (status & BI) {
-               uart->port.icount.brk++;
-               if (uart_handle_break(&uart->port))
-                       goto dma_ignore_char;
-               status &= ~(PE | FE);
-       }
-       if (status & PE)
-               uart->port.icount.parity++;
-       if (status & OE)
-               uart->port.icount.overrun++;
-       if (status & FE)
-               uart->port.icount.frame++;
-
-       status &= uart->port.read_status_mask;
-
-       if (status & BI)
-               flg = TTY_BREAK;
-       else if (status & PE)
-               flg = TTY_PARITY;
-       else if (status & FE)
-               flg = TTY_FRAME;
-       else
-               flg = TTY_NORMAL;
-
-       for (i = uart->rx_dma_buf.tail; ; i++) {
-               if (i >= UART_XMIT_SIZE)
-                       i = 0;
-               if (i == uart->rx_dma_buf.head)
-                       break;
-               if (!uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i]))
-                       uart_insert_char(&uart->port, status, OE,
-                               uart->rx_dma_buf.buf[i], flg);
-       }
-
- dma_ignore_char:
-       tty_flip_buffer_push(tty);
-}
-
-void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
-{
-       int x_pos, pos;
-
-       dma_disable_irq(uart->tx_dma_channel);
-       dma_disable_irq(uart->rx_dma_channel);
-       spin_lock_bh(&uart->port.lock);
-
-       /* 2D DMA RX buffer ring is used. Because curr_y_count and
-        * curr_x_count can't be read as an atomic operation,
-        * curr_y_count should be read before curr_x_count. When
-        * curr_x_count is read, curr_y_count may already indicate
-        * next buffer line. But, the position calculated here is
-        * still indicate the old line. The wrong position data may
-        * be smaller than current buffer tail, which cause garbages
-        * are received if it is not prohibit.
-        */
-       uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel);
-       x_pos = get_dma_curr_xcount(uart->rx_dma_channel);
-       uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows;
-       if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0)
-               uart->rx_dma_nrows = 0;
-       x_pos = DMA_RX_XCOUNT - x_pos;
-       if (x_pos == DMA_RX_XCOUNT)
-               x_pos = 0;
-
-       pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos;
-       /* Ignore receiving data if new position is in the same line of
-        * current buffer tail and small.
-        */
-       if (pos > uart->rx_dma_buf.tail ||
-               uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) {
-               uart->rx_dma_buf.head = pos;
-               bfin_serial_dma_rx_chars(uart);
-               uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
-       }
-
-       spin_unlock_bh(&uart->port.lock);
-       dma_enable_irq(uart->tx_dma_channel);
-       dma_enable_irq(uart->rx_dma_channel);
-
-       mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES);
-}
-
-static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
-{
-       struct bfin_serial_port *uart = dev_id;
-       struct circ_buf *xmit = &uart->port.state->xmit;
-
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
-       if (uart->scts && !(bfin_serial_get_mctrl(&uart->port)&TIOCM_CTS)) {
-               uart->scts = 0;
-               uart_handle_cts_change(&uart->port, uart->scts);
-       }
-#endif
-
-       spin_lock(&uart->port.lock);
-       if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) {
-               disable_dma(uart->tx_dma_channel);
-               clear_dma_irqstat(uart->tx_dma_channel);
-               /* Anomaly notes:
-                *  05000215 -  we always clear ETBEI within last UART TX
-                *              interrupt to end a string. It is always set
-                *              when start a new tx.
-                */
-               UART_CLEAR_IER(uart, ETBEI);
-               xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
-               uart->port.icount.tx += uart->tx_count;
-
-               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-                       uart_write_wakeup(&uart->port);
-
-               bfin_serial_dma_tx_chars(uart);
-       }
-
-       spin_unlock(&uart->port.lock);
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
-{
-       struct bfin_serial_port *uart = dev_id;
-       unsigned short irqstat;
-       int x_pos, pos;
-
-       spin_lock(&uart->port.lock);
-       irqstat = get_dma_curr_irqstat(uart->rx_dma_channel);
-       clear_dma_irqstat(uart->rx_dma_channel);
-
-       uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel);
-       x_pos = get_dma_curr_xcount(uart->rx_dma_channel);
-       uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows;
-       if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0)
-               uart->rx_dma_nrows = 0;
-
-       pos = uart->rx_dma_nrows * DMA_RX_XCOUNT;
-       if (pos > uart->rx_dma_buf.tail ||
-               uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) {
-               uart->rx_dma_buf.head = pos;
-               bfin_serial_dma_rx_chars(uart);
-               uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
-       }
-
-       spin_unlock(&uart->port.lock);
-
-       return IRQ_HANDLED;
-}
-#endif
-
-/*
- * Return TIOCSER_TEMT when transmitter is not busy.
- */
-static unsigned int bfin_serial_tx_empty(struct uart_port *port)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-       unsigned short lsr;
-
-       lsr = UART_GET_LSR(uart);
-       if (lsr & TEMT)
-               return TIOCSER_TEMT;
-       else
-               return 0;
-}
-
-static void bfin_serial_break_ctl(struct uart_port *port, int break_state)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-       u16 lcr = UART_GET_LCR(uart);
-       if (break_state)
-               lcr |= SB;
-       else
-               lcr &= ~SB;
-       UART_PUT_LCR(uart, lcr);
-       SSYNC();
-}
-
-static int bfin_serial_startup(struct uart_port *port)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       dma_addr_t dma_handle;
-
-       if (request_dma(uart->rx_dma_channel, "BFIN_UART_RX") < 0) {
-               printk(KERN_NOTICE "Unable to attach Blackfin UART RX DMA channel\n");
-               return -EBUSY;
-       }
-
-       if (request_dma(uart->tx_dma_channel, "BFIN_UART_TX") < 0) {
-               printk(KERN_NOTICE "Unable to attach Blackfin UART TX DMA channel\n");
-               free_dma(uart->rx_dma_channel);
-               return -EBUSY;
-       }
-
-       set_dma_callback(uart->rx_dma_channel, bfin_serial_dma_rx_int, uart);
-       set_dma_callback(uart->tx_dma_channel, bfin_serial_dma_tx_int, uart);
-
-       uart->rx_dma_buf.buf = (unsigned char *)dma_alloc_coherent(NULL, PAGE_SIZE, &dma_handle, GFP_DMA);
-       uart->rx_dma_buf.head = 0;
-       uart->rx_dma_buf.tail = 0;
-       uart->rx_dma_nrows = 0;
-
-       set_dma_config(uart->rx_dma_channel,
-               set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO,
-                               INTR_ON_ROW, DIMENSION_2D,
-                               DATA_SIZE_8,
-                               DMA_SYNC_RESTART));
-       set_dma_x_count(uart->rx_dma_channel, DMA_RX_XCOUNT);
-       set_dma_x_modify(uart->rx_dma_channel, 1);
-       set_dma_y_count(uart->rx_dma_channel, DMA_RX_YCOUNT);
-       set_dma_y_modify(uart->rx_dma_channel, 1);
-       set_dma_start_addr(uart->rx_dma_channel, (unsigned long)uart->rx_dma_buf.buf);
-       enable_dma(uart->rx_dma_channel);
-
-       uart->rx_dma_timer.data = (unsigned long)(uart);
-       uart->rx_dma_timer.function = (void *)bfin_serial_rx_dma_timeout;
-       uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES;
-       add_timer(&(uart->rx_dma_timer));
-#else
-# if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
-       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
-       if (kgdboc_port_line == uart->port.line && kgdboc_break_enabled)
-               kgdboc_break_enabled = 0;
-       else {
-# endif
-       if (request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED,
-            "BFIN_UART_RX", uart)) {
-               printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n");
-               return -EBUSY;
-       }
-
-       if (request_irq
-           (uart->port.irq+1, bfin_serial_tx_int, IRQF_DISABLED,
-            "BFIN_UART_TX", uart)) {
-               printk(KERN_NOTICE "Unable to attach BlackFin UART TX interrupt\n");
-               free_irq(uart->port.irq, uart);
-               return -EBUSY;
-       }
-
-# ifdef CONFIG_BF54x
-       {
-               /*
-                * UART2 and UART3 on BF548 share interrupt PINs and DMA
-                * controllers with SPORT2 and SPORT3. UART rx and tx
-                * interrupts are generated in PIO mode only when configure
-                * their peripheral mapping registers properly, which means
-                * request corresponding DMA channels in PIO mode as well.
-                */
-               unsigned uart_dma_ch_rx, uart_dma_ch_tx;
-
-               switch (uart->port.irq) {
-               case IRQ_UART3_RX:
-                       uart_dma_ch_rx = CH_UART3_RX;
-                       uart_dma_ch_tx = CH_UART3_TX;
-                       break;
-               case IRQ_UART2_RX:
-                       uart_dma_ch_rx = CH_UART2_RX;
-                       uart_dma_ch_tx = CH_UART2_TX;
-                       break;
-               default:
-                       uart_dma_ch_rx = uart_dma_ch_tx = 0;
-                       break;
-               };
-
-               if (uart_dma_ch_rx &&
-                       request_dma(uart_dma_ch_rx, "BFIN_UART_RX") < 0) {
-                       printk(KERN_NOTICE"Fail to attach UART interrupt\n");
-                       free_irq(uart->port.irq, uart);
-                       free_irq(uart->port.irq + 1, uart);
-                       return -EBUSY;
-               }
-               if (uart_dma_ch_tx &&
-                       request_dma(uart_dma_ch_tx, "BFIN_UART_TX") < 0) {
-                       printk(KERN_NOTICE "Fail to attach UART interrupt\n");
-                       free_dma(uart_dma_ch_rx);
-                       free_irq(uart->port.irq, uart);
-                       free_irq(uart->port.irq + 1, uart);
-                       return -EBUSY;
-               }
-       }
-# endif
-# if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
-       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
-       }
-# endif
-#endif
-
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-       if (uart->cts_pin >= 0) {
-               if (request_irq(gpio_to_irq(uart->cts_pin),
-                       bfin_serial_mctrl_cts_int,
-                       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
-                       IRQF_DISABLED, "BFIN_UART_CTS", uart)) {
-                       uart->cts_pin = -1;
-                       pr_info("Unable to attach BlackFin UART CTS interrupt. So, disable it.\n");
-               }
-       }
-       if (uart->rts_pin >= 0) {
-               gpio_direction_output(uart->rts_pin, 0);
-       }
-#endif
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
-       if (uart->cts_pin >= 0 && request_irq(uart->status_irq,
-               bfin_serial_mctrl_cts_int,
-               IRQF_DISABLED, "BFIN_UART_MODEM_STATUS", uart)) {
-               uart->cts_pin = -1;
-               pr_info("Unable to attach BlackFin UART Modem Status interrupt.\n");
-       }
-
-       /* CTS RTS PINs are negative assertive. */
-       UART_PUT_MCR(uart, ACTS);
-       UART_SET_IER(uart, EDSSI);
-#endif
-
-       UART_SET_IER(uart, ERBFI);
-       return 0;
-}
-
-static void bfin_serial_shutdown(struct uart_port *port)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       disable_dma(uart->tx_dma_channel);
-       free_dma(uart->tx_dma_channel);
-       disable_dma(uart->rx_dma_channel);
-       free_dma(uart->rx_dma_channel);
-       del_timer(&(uart->rx_dma_timer));
-       dma_free_coherent(NULL, PAGE_SIZE, uart->rx_dma_buf.buf, 0);
-#else
-#ifdef CONFIG_BF54x
-       switch (uart->port.irq) {
-       case IRQ_UART3_RX:
-               free_dma(CH_UART3_RX);
-               free_dma(CH_UART3_TX);
-               break;
-       case IRQ_UART2_RX:
-               free_dma(CH_UART2_RX);
-               free_dma(CH_UART2_TX);
-               break;
-       default:
-               break;
-       };
-#endif
-       free_irq(uart->port.irq, uart);
-       free_irq(uart->port.irq+1, uart);
-#endif
-
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-       if (uart->cts_pin >= 0)
-               free_irq(gpio_to_irq(uart->cts_pin), uart);
-#endif
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
-       if (uart->cts_pin >= 0)
-               free_irq(uart->status_irq, uart);
-#endif
-}
-
-static void
-bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
-                  struct ktermios *old)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-       unsigned long flags;
-       unsigned int baud, quot;
-       unsigned short val, ier, lcr = 0;
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS8:
-               lcr = WLS(8);
-               break;
-       case CS7:
-               lcr = WLS(7);
-               break;
-       case CS6:
-               lcr = WLS(6);
-               break;
-       case CS5:
-               lcr = WLS(5);
-               break;
-       default:
-               printk(KERN_ERR "%s: word lengh not supported\n",
-                       __func__);
-       }
-
-       /* Anomaly notes:
-        *  05000231 -  STOP bit is always set to 1 whatever the user is set.
-        */
-       if (termios->c_cflag & CSTOPB) {
-               if (ANOMALY_05000231)
-                       printk(KERN_WARNING "STOP bits other than 1 is not "
-                               "supported in case of anomaly 05000231.\n");
-               else
-                       lcr |= STB;
-       }
-       if (termios->c_cflag & PARENB)
-               lcr |= PEN;
-       if (!(termios->c_cflag & PARODD))
-               lcr |= EPS;
-       if (termios->c_cflag & CMSPAR)
-               lcr |= STP;
-
-       spin_lock_irqsave(&uart->port.lock, flags);
-
-       port->read_status_mask = OE;
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= (FE | PE);
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               port->read_status_mask |= BI;
-
-       /*
-        * Characters to ignore
-        */
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= FE | PE;
-       if (termios->c_iflag & IGNBRK) {
-               port->ignore_status_mask |= BI;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       port->ignore_status_mask |= OE;
-       }
-
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
-       quot = uart_get_divisor(port, baud);
-
-       /* If discipline is not IRDA, apply ANOMALY_05000230 */
-       if (termios->c_line != N_IRDA)
-               quot -= ANOMALY_05000230;
-
-       UART_SET_ANOMALY_THRESHOLD(uart, USEC_PER_SEC / baud * 15);
-
-       /* Disable UART */
-       ier = UART_GET_IER(uart);
-       UART_DISABLE_INTS(uart);
-
-       /* Set DLAB in LCR to Access DLL and DLH */
-       UART_SET_DLAB(uart);
-
-       UART_PUT_DLL(uart, quot & 0xFF);
-       UART_PUT_DLH(uart, (quot >> 8) & 0xFF);
-       SSYNC();
-
-       /* Clear DLAB in LCR to Access THR RBR IER */
-       UART_CLEAR_DLAB(uart);
-
-       UART_PUT_LCR(uart, lcr);
-
-       /* Enable UART */
-       UART_ENABLE_INTS(uart, ier);
-
-       val = UART_GET_GCTL(uart);
-       val |= UCEN;
-       UART_PUT_GCTL(uart, val);
-
-       /* Port speed changed, update the per-port timeout. */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       spin_unlock_irqrestore(&uart->port.lock, flags);
-}
-
-static const char *bfin_serial_type(struct uart_port *port)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-
-       return uart->port.type == PORT_BFIN ? "BFIN-UART" : NULL;
-}
-
-/*
- * Release the memory region(s) being used by 'port'.
- */
-static void bfin_serial_release_port(struct uart_port *port)
-{
-}
-
-/*
- * Request the memory region(s) being used by 'port'.
- */
-static int bfin_serial_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-/*
- * Configure/autoconfigure the port.
- */
-static void bfin_serial_config_port(struct uart_port *port, int flags)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-
-       if (flags & UART_CONFIG_TYPE &&
-           bfin_serial_request_port(&uart->port) == 0)
-               uart->port.type = PORT_BFIN;
-}
-
-/*
- * Verify the new serial_struct (for TIOCSSERIAL).
- * The only change we allow are to the flags and type, and
- * even then only between PORT_BFIN and PORT_UNKNOWN
- */
-static int
-bfin_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       return 0;
-}
-
-/*
- * Enable the IrDA function if tty->ldisc.num is N_IRDA.
- * In other cases, disable IrDA function.
- */
-static void bfin_serial_set_ldisc(struct uart_port *port, int ld)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-       unsigned short val;
-
-       switch (ld) {
-       case N_IRDA:
-               val = UART_GET_GCTL(uart);
-               val |= (IREN | RPOLC);
-               UART_PUT_GCTL(uart, val);
-               break;
-       default:
-               val = UART_GET_GCTL(uart);
-               val &= ~(IREN | RPOLC);
-               UART_PUT_GCTL(uart, val);
-       }
-}
-
-static void bfin_serial_reset_irda(struct uart_port *port)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-       unsigned short val;
-
-       val = UART_GET_GCTL(uart);
-       val &= ~(IREN | RPOLC);
-       UART_PUT_GCTL(uart, val);
-       SSYNC();
-       val |= (IREN | RPOLC);
-       UART_PUT_GCTL(uart, val);
-       SSYNC();
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-/* Anomaly notes:
- *  05000099 -  Because we only use THRE in poll_put and DR in poll_get,
- *             losing other bits of UART_LSR is not a problem here.
- */
-static void bfin_serial_poll_put_char(struct uart_port *port, unsigned char chr)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-
-       while (!(UART_GET_LSR(uart) & THRE))
-               cpu_relax();
-
-       UART_CLEAR_DLAB(uart);
-       UART_PUT_CHAR(uart, (unsigned char)chr);
-}
-
-static int bfin_serial_poll_get_char(struct uart_port *port)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-       unsigned char chr;
-
-       while (!(UART_GET_LSR(uart) & DR))
-               cpu_relax();
-
-       UART_CLEAR_DLAB(uart);
-       chr = UART_GET_CHAR(uart);
-
-       return chr;
-}
-#endif
-
-#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
-       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
-static void bfin_kgdboc_port_shutdown(struct uart_port *port)
-{
-       if (kgdboc_break_enabled) {
-               kgdboc_break_enabled = 0;
-               bfin_serial_shutdown(port);
-       }
-}
-
-static int bfin_kgdboc_port_startup(struct uart_port *port)
-{
-       kgdboc_port_line = port->line;
-       kgdboc_break_enabled = !bfin_serial_startup(port);
-       return 0;
-}
-#endif
-
-static struct uart_ops bfin_serial_pops = {
-       .tx_empty       = bfin_serial_tx_empty,
-       .set_mctrl      = bfin_serial_set_mctrl,
-       .get_mctrl      = bfin_serial_get_mctrl,
-       .stop_tx        = bfin_serial_stop_tx,
-       .start_tx       = bfin_serial_start_tx,
-       .stop_rx        = bfin_serial_stop_rx,
-       .enable_ms      = bfin_serial_enable_ms,
-       .break_ctl      = bfin_serial_break_ctl,
-       .startup        = bfin_serial_startup,
-       .shutdown       = bfin_serial_shutdown,
-       .set_termios    = bfin_serial_set_termios,
-       .set_ldisc      = bfin_serial_set_ldisc,
-       .type           = bfin_serial_type,
-       .release_port   = bfin_serial_release_port,
-       .request_port   = bfin_serial_request_port,
-       .config_port    = bfin_serial_config_port,
-       .verify_port    = bfin_serial_verify_port,
-#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
-       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
-       .kgdboc_port_startup    = bfin_kgdboc_port_startup,
-       .kgdboc_port_shutdown   = bfin_kgdboc_port_shutdown,
-#endif
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_put_char  = bfin_serial_poll_put_char,
-       .poll_get_char  = bfin_serial_poll_get_char,
-#endif
-};
-
-#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
-/*
- * If the port was already initialised (eg, by a boot loader),
- * try to determine the current setup.
- */
-static void __init
-bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
-                          int *parity, int *bits)
-{
-       unsigned short status;
-
-       status = UART_GET_IER(uart) & (ERBFI | ETBEI);
-       if (status == (ERBFI | ETBEI)) {
-               /* ok, the port was enabled */
-               u16 lcr, dlh, dll;
-
-               lcr = UART_GET_LCR(uart);
-
-               *parity = 'n';
-               if (lcr & PEN) {
-                       if (lcr & EPS)
-                               *parity = 'e';
-                       else
-                               *parity = 'o';
-               }
-               switch (lcr & 0x03) {
-                       case 0: *bits = 5; break;
-                       case 1: *bits = 6; break;
-                       case 2: *bits = 7; break;
-                       case 3: *bits = 8; break;
-               }
-               /* Set DLAB in LCR to Access DLL and DLH */
-               UART_SET_DLAB(uart);
-
-               dll = UART_GET_DLL(uart);
-               dlh = UART_GET_DLH(uart);
-
-               /* Clear DLAB in LCR to Access THR RBR IER */
-               UART_CLEAR_DLAB(uart);
-
-               *baud = get_sclk() / (16*(dll | dlh << 8));
-       }
-       pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __func__, *baud, *parity, *bits);
-}
-
-static struct uart_driver bfin_serial_reg;
-
-static void bfin_serial_console_putchar(struct uart_port *port, int ch)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-       while (!(UART_GET_LSR(uart) & THRE))
-               barrier();
-       UART_PUT_CHAR(uart, ch);
-}
-
-#endif /* defined (CONFIG_SERIAL_BFIN_CONSOLE) ||
-                defined (CONFIG_EARLY_PRINTK) */
-
-#ifdef CONFIG_SERIAL_BFIN_CONSOLE
-#define CLASS_BFIN_CONSOLE     "bfin-console"
-/*
- * Interrupts are disabled on entering
- */
-static void
-bfin_serial_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct bfin_serial_port *uart = bfin_serial_ports[co->index];
-       unsigned long flags;
-
-       spin_lock_irqsave(&uart->port.lock, flags);
-       uart_console_write(&uart->port, s, count, bfin_serial_console_putchar);
-       spin_unlock_irqrestore(&uart->port.lock, flags);
-
-}
-
-static int __init
-bfin_serial_console_setup(struct console *co, char *options)
-{
-       struct bfin_serial_port *uart;
-       int baud = 57600;
-       int bits = 8;
-       int parity = 'n';
-# if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
-       defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
-       int flow = 'r';
-# else
-       int flow = 'n';
-# endif
-
-       /*
-        * Check whether an invalid uart number has been specified, and
-        * if so, search for the first available port that does have
-        * console support.
-        */
-       if (co->index < 0 || co->index >= BFIN_UART_NR_PORTS)
-               return -ENODEV;
-
-       uart = bfin_serial_ports[co->index];
-       if (!uart)
-               return -ENODEV;
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               bfin_serial_console_get_options(uart, &baud, &parity, &bits);
-
-       return uart_set_options(&uart->port, co, baud, parity, bits, flow);
-}
-
-static struct console bfin_serial_console = {
-       .name           = BFIN_SERIAL_DEV_NAME,
-       .write          = bfin_serial_console_write,
-       .device         = uart_console_device,
-       .setup          = bfin_serial_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &bfin_serial_reg,
-};
-#define BFIN_SERIAL_CONSOLE    &bfin_serial_console
-#else
-#define BFIN_SERIAL_CONSOLE    NULL
-#endif /* CONFIG_SERIAL_BFIN_CONSOLE */
-
-#ifdef CONFIG_EARLY_PRINTK
-static struct bfin_serial_port bfin_earlyprintk_port;
-#define CLASS_BFIN_EARLYPRINTK "bfin-earlyprintk"
-
-/*
- * Interrupts are disabled on entering
- */
-static void
-bfin_earlyprintk_console_write(struct console *co, const char *s, unsigned int count)
-{
-       unsigned long flags;
-
-       if (bfin_earlyprintk_port.port.line != co->index)
-               return;
-
-       spin_lock_irqsave(&bfin_earlyprintk_port.port.lock, flags);
-       uart_console_write(&bfin_earlyprintk_port.port, s, count,
-               bfin_serial_console_putchar);
-       spin_unlock_irqrestore(&bfin_earlyprintk_port.port.lock, flags);
-}
-
-/*
- * This should have a .setup or .early_setup in it, but then things get called
- * without the command line options, and the baud rate gets messed up - so
- * don't let the common infrastructure play with things. (see calls to setup
- * & earlysetup in ./kernel/printk.c:register_console()
- */
-static struct __initdata console bfin_early_serial_console = {
-       .name = "early_BFuart",
-       .write = bfin_earlyprintk_console_write,
-       .device = uart_console_device,
-       .flags = CON_PRINTBUFFER,
-       .index = -1,
-       .data  = &bfin_serial_reg,
-};
-#endif
-
-static struct uart_driver bfin_serial_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = DRIVER_NAME,
-       .dev_name               = BFIN_SERIAL_DEV_NAME,
-       .major                  = BFIN_SERIAL_MAJOR,
-       .minor                  = BFIN_SERIAL_MINOR,
-       .nr                     = BFIN_UART_NR_PORTS,
-       .cons                   = BFIN_SERIAL_CONSOLE,
-};
-
-static int bfin_serial_suspend(struct platform_device *pdev, pm_message_t state)
-{
-       struct bfin_serial_port *uart = platform_get_drvdata(pdev);
-
-       return uart_suspend_port(&bfin_serial_reg, &uart->port);
-}
-
-static int bfin_serial_resume(struct platform_device *pdev)
-{
-       struct bfin_serial_port *uart = platform_get_drvdata(pdev);
-
-       return uart_resume_port(&bfin_serial_reg, &uart->port);
-}
-
-static int bfin_serial_probe(struct platform_device *pdev)
-{
-       struct resource *res;
-       struct bfin_serial_port *uart = NULL;
-       int ret = 0;
-
-       if (pdev->id < 0 || pdev->id >= BFIN_UART_NR_PORTS) {
-               dev_err(&pdev->dev, "Wrong bfin uart platform device id.\n");
-               return -ENOENT;
-       }
-
-       if (bfin_serial_ports[pdev->id] == NULL) {
-
-               uart = kzalloc(sizeof(*uart), GFP_KERNEL);
-               if (!uart) {
-                       dev_err(&pdev->dev,
-                               "fail to malloc bfin_serial_port\n");
-                       return -ENOMEM;
-               }
-               bfin_serial_ports[pdev->id] = uart;
-
-#ifdef CONFIG_EARLY_PRINTK
-               if (!(bfin_earlyprintk_port.port.membase
-                       && bfin_earlyprintk_port.port.line == pdev->id)) {
-                       /*
-                        * If the peripheral PINs of current port is allocated
-                        * in earlyprintk probe stage, don't do it again.
-                        */
-#endif
-               ret = peripheral_request_list(
-                       (unsigned short *)pdev->dev.platform_data, DRIVER_NAME);
-               if (ret) {
-                       dev_err(&pdev->dev,
-                               "fail to request bfin serial peripherals\n");
-                       goto out_error_free_mem;
-               }
-#ifdef CONFIG_EARLY_PRINTK
-               }
-#endif
-
-               spin_lock_init(&uart->port.lock);
-               uart->port.uartclk   = get_sclk();
-               uart->port.fifosize  = BFIN_UART_TX_FIFO_SIZE;
-               uart->port.ops       = &bfin_serial_pops;
-               uart->port.line      = pdev->id;
-               uart->port.iotype    = UPIO_MEM;
-               uart->port.flags     = UPF_BOOT_AUTOCONF;
-
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-               if (res == NULL) {
-                       dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
-                       ret = -ENOENT;
-                       goto out_error_free_peripherals;
-               }
-
-               uart->port.membase = ioremap(res->start,
-                       res->end - res->start);
-               if (!uart->port.membase) {
-                       dev_err(&pdev->dev, "Cannot map uart IO\n");
-                       ret = -ENXIO;
-                       goto out_error_free_peripherals;
-               }
-               uart->port.mapbase = res->start;
-
-               uart->port.irq = platform_get_irq(pdev, 0);
-               if (uart->port.irq < 0) {
-                       dev_err(&pdev->dev, "No uart RX/TX IRQ specified\n");
-                       ret = -ENOENT;
-                       goto out_error_unmap;
-               }
-
-               uart->status_irq = platform_get_irq(pdev, 1);
-               if (uart->status_irq < 0) {
-                       dev_err(&pdev->dev, "No uart status IRQ specified\n");
-                       ret = -ENOENT;
-                       goto out_error_unmap;
-               }
-
-#ifdef CONFIG_SERIAL_BFIN_DMA
-               uart->tx_done       = 1;
-               uart->tx_count      = 0;
-
-               res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-               if (res == NULL) {
-                       dev_err(&pdev->dev, "No uart TX DMA channel specified\n");
-                       ret = -ENOENT;
-                       goto out_error_unmap;
-               }
-               uart->tx_dma_channel = res->start;
-
-               res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-               if (res == NULL) {
-                       dev_err(&pdev->dev, "No uart RX DMA channel specified\n");
-                       ret = -ENOENT;
-                       goto out_error_unmap;
-               }
-               uart->rx_dma_channel = res->start;
-
-               init_timer(&(uart->rx_dma_timer));
-#endif
-
-#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
-       defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
-               res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-               if (res == NULL)
-                       uart->cts_pin = -1;
-               else
-                       uart->cts_pin = res->start;
-
-               res = platform_get_resource(pdev, IORESOURCE_IO, 1);
-               if (res == NULL)
-                       uart->rts_pin = -1;
-               else
-                       uart->rts_pin = res->start;
-# if defined(CONFIG_SERIAL_BFIN_CTSRTS)
-               if (uart->rts_pin >= 0)
-                       gpio_request(uart->rts_pin, DRIVER_NAME);
-# endif
-#endif
-       }
-
-#ifdef CONFIG_SERIAL_BFIN_CONSOLE
-       if (!is_early_platform_device(pdev)) {
-#endif
-               uart = bfin_serial_ports[pdev->id];
-               uart->port.dev = &pdev->dev;
-               dev_set_drvdata(&pdev->dev, uart);
-               ret = uart_add_one_port(&bfin_serial_reg, &uart->port);
-#ifdef CONFIG_SERIAL_BFIN_CONSOLE
-       }
-#endif
-
-       if (!ret)
-               return 0;
-
-       if (uart) {
-out_error_unmap:
-               iounmap(uart->port.membase);
-out_error_free_peripherals:
-               peripheral_free_list(
-                       (unsigned short *)pdev->dev.platform_data);
-out_error_free_mem:
-               kfree(uart);
-               bfin_serial_ports[pdev->id] = NULL;
-       }
-
-       return ret;
-}
-
-static int __devexit bfin_serial_remove(struct platform_device *pdev)
-{
-       struct bfin_serial_port *uart = platform_get_drvdata(pdev);
-
-       dev_set_drvdata(&pdev->dev, NULL);
-
-       if (uart) {
-               uart_remove_one_port(&bfin_serial_reg, &uart->port);
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-               if (uart->rts_pin >= 0)
-                       gpio_free(uart->rts_pin);
-#endif
-               iounmap(uart->port.membase);
-               peripheral_free_list(
-                       (unsigned short *)pdev->dev.platform_data);
-               kfree(uart);
-               bfin_serial_ports[pdev->id] = NULL;
-       }
-
-       return 0;
-}
-
-static struct platform_driver bfin_serial_driver = {
-       .probe          = bfin_serial_probe,
-       .remove         = __devexit_p(bfin_serial_remove),
-       .suspend        = bfin_serial_suspend,
-       .resume         = bfin_serial_resume,
-       .driver         = {
-               .name   = DRIVER_NAME,
-               .owner  = THIS_MODULE,
-       },
-};
-
-#if defined(CONFIG_SERIAL_BFIN_CONSOLE)
-static __initdata struct early_platform_driver early_bfin_serial_driver = {
-       .class_str = CLASS_BFIN_CONSOLE,
-       .pdrv = &bfin_serial_driver,
-       .requested_id = EARLY_PLATFORM_ID_UNSET,
-};
-
-static int __init bfin_serial_rs_console_init(void)
-{
-       early_platform_driver_register(&early_bfin_serial_driver, DRIVER_NAME);
-
-       early_platform_driver_probe(CLASS_BFIN_CONSOLE, BFIN_UART_NR_PORTS, 0);
-
-       register_console(&bfin_serial_console);
-
-       return 0;
-}
-console_initcall(bfin_serial_rs_console_init);
-#endif
-
-#ifdef CONFIG_EARLY_PRINTK
-/*
- * Memory can't be allocated dynamically during earlyprink init stage.
- * So, do individual probe for earlyprink with a static uart port variable.
- */
-static int bfin_earlyprintk_probe(struct platform_device *pdev)
-{
-       struct resource *res;
-       int ret;
-
-       if (pdev->id < 0 || pdev->id >= BFIN_UART_NR_PORTS) {
-               dev_err(&pdev->dev, "Wrong earlyprintk platform device id.\n");
-               return -ENOENT;
-       }
-
-       ret = peripheral_request_list(
-               (unsigned short *)pdev->dev.platform_data, DRIVER_NAME);
-       if (ret) {
-               dev_err(&pdev->dev,
-                               "fail to request bfin serial peripherals\n");
-                       return ret;
-       }
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (res == NULL) {
-               dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
-               ret = -ENOENT;
-               goto out_error_free_peripherals;
-       }
-
-       bfin_earlyprintk_port.port.membase = ioremap(res->start,
-                       res->end - res->start);
-       if (!bfin_earlyprintk_port.port.membase) {
-               dev_err(&pdev->dev, "Cannot map uart IO\n");
-               ret = -ENXIO;
-               goto out_error_free_peripherals;
-       }
-       bfin_earlyprintk_port.port.mapbase = res->start;
-       bfin_earlyprintk_port.port.line = pdev->id;
-       bfin_earlyprintk_port.port.uartclk = get_sclk();
-       bfin_earlyprintk_port.port.fifosize  = BFIN_UART_TX_FIFO_SIZE;
-       spin_lock_init(&bfin_earlyprintk_port.port.lock);
-
-       return 0;
-
-out_error_free_peripherals:
-       peripheral_free_list(
-               (unsigned short *)pdev->dev.platform_data);
-
-       return ret;
-}
-
-static struct platform_driver bfin_earlyprintk_driver = {
-       .probe          = bfin_earlyprintk_probe,
-       .driver         = {
-               .name   = DRIVER_NAME,
-               .owner  = THIS_MODULE,
-       },
-};
-
-static __initdata struct early_platform_driver early_bfin_earlyprintk_driver = {
-       .class_str = CLASS_BFIN_EARLYPRINTK,
-       .pdrv = &bfin_earlyprintk_driver,
-       .requested_id = EARLY_PLATFORM_ID_UNSET,
-};
-
-struct console __init *bfin_earlyserial_init(unsigned int port,
-                                               unsigned int cflag)
-{
-       struct ktermios t;
-       char port_name[20];
-
-       if (port < 0 || port >= BFIN_UART_NR_PORTS)
-               return NULL;
-
-       /*
-        * Only probe resource of the given port in earlyprintk boot arg.
-        * The expected port id should be indicated in port name string.
-        */
-       snprintf(port_name, 20, DRIVER_NAME ".%d", port);
-       early_platform_driver_register(&early_bfin_earlyprintk_driver,
-               port_name);
-       early_platform_driver_probe(CLASS_BFIN_EARLYPRINTK, 1, 0);
-
-       if (!bfin_earlyprintk_port.port.membase)
-               return NULL;
-
-#ifdef CONFIG_SERIAL_BFIN_CONSOLE
-       /*
-        * If we are using early serial, don't let the normal console rewind
-        * log buffer, since that causes things to be printed multiple times
-        */
-       bfin_serial_console.flags &= ~CON_PRINTBUFFER;
-#endif
-
-       bfin_early_serial_console.index = port;
-       t.c_cflag = cflag;
-       t.c_iflag = 0;
-       t.c_oflag = 0;
-       t.c_lflag = ICANON;
-       t.c_line = port;
-       bfin_serial_set_termios(&bfin_earlyprintk_port.port, &t, &t);
-
-       return &bfin_early_serial_console;
-}
-#endif /* CONFIG_EARLY_PRINTK */
-
-static int __init bfin_serial_init(void)
-{
-       int ret;
-
-       pr_info("Blackfin serial driver\n");
-
-       ret = uart_register_driver(&bfin_serial_reg);
-       if (ret) {
-               pr_err("failed to register %s:%d\n",
-                       bfin_serial_reg.driver_name, ret);
-       }
-
-       ret = platform_driver_register(&bfin_serial_driver);
-       if (ret) {
-               pr_err("fail to register bfin uart\n");
-               uart_unregister_driver(&bfin_serial_reg);
-       }
-
-       return ret;
-}
-
-static void __exit bfin_serial_exit(void)
-{
-       platform_driver_unregister(&bfin_serial_driver);
-       uart_unregister_driver(&bfin_serial_reg);
-}
-
-
-module_init(bfin_serial_init);
-module_exit(bfin_serial_exit);
-
-MODULE_AUTHOR("Sonic Zhang, Aubrey Li");
-MODULE_DESCRIPTION("Blackfin generic serial port driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV_MAJOR(BFIN_SERIAL_MAJOR);
-MODULE_ALIAS("platform:bfin-uart");
diff --git a/drivers/serial/bfin_sport_uart.c b/drivers/serial/bfin_sport_uart.c
deleted file mode 100644 (file)
index e95c524..0000000
+++ /dev/null
@@ -1,935 +0,0 @@
-/*
- * Blackfin On-Chip Sport Emulated UART Driver
- *
- * Copyright 2006-2009 Analog Devices Inc.
- *
- * Enter bugs at http://blackfin.uclinux.org/
- *
- * Licensed under the GPL-2 or later.
- */
-
-/*
- * This driver and the hardware supported are in term of EE-191 of ADI.
- * http://www.analog.com/static/imported-files/application_notes/EE191.pdf 
- * This application note describe how to implement a UART on a Sharc DSP,
- * but this driver is implemented on Blackfin Processor.
- * Transmit Frame Sync is not used by this driver to transfer data out.
- */
-
-/* #define DEBUG */
-
-#define DRV_NAME "bfin-sport-uart"
-#define DEVICE_NAME    "ttySS"
-#define pr_fmt(fmt) DRV_NAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/io.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-
-#include <asm/bfin_sport.h>
-#include <asm/delay.h>
-#include <asm/portmux.h>
-
-#include "bfin_sport_uart.h"
-
-struct sport_uart_port {
-       struct uart_port        port;
-       int                     err_irq;
-       unsigned short          csize;
-       unsigned short          rxmask;
-       unsigned short          txmask1;
-       unsigned short          txmask2;
-       unsigned char           stopb;
-/*     unsigned char           parib; */
-#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
-       int cts_pin;
-       int rts_pin;
-#endif
-};
-
-static int sport_uart_tx_chars(struct sport_uart_port *up);
-static void sport_stop_tx(struct uart_port *port);
-
-static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value)
-{
-       pr_debug("%s value:%x, mask1=0x%x, mask2=0x%x\n", __func__, value,
-               up->txmask1, up->txmask2);
-
-       /* Place Start and Stop bits */
-       __asm__ __volatile__ (
-               "%[val] <<= 1;"
-               "%[val] = %[val] & %[mask1];"
-               "%[val] = %[val] | %[mask2];"
-               : [val]"+d"(value)
-               : [mask1]"d"(up->txmask1), [mask2]"d"(up->txmask2)
-               : "ASTAT"
-       );
-       pr_debug("%s value:%x\n", __func__, value);
-
-       SPORT_PUT_TX(up, value);
-}
-
-static inline unsigned char rx_one_byte(struct sport_uart_port *up)
-{
-       unsigned int value;
-       unsigned char extract;
-       u32 tmp_mask1, tmp_mask2, tmp_shift, tmp;
-
-       if ((up->csize + up->stopb) > 7)
-               value = SPORT_GET_RX32(up);
-       else
-               value = SPORT_GET_RX(up);
-
-       pr_debug("%s value:%x, cs=%d, mask=0x%x\n", __func__, value,
-               up->csize, up->rxmask);
-
-       /* Extract data */
-       __asm__ __volatile__ (
-               "%[extr] = 0;"
-               "%[mask1] = %[rxmask];"
-               "%[mask2] = 0x0200(Z);"
-               "%[shift] = 0;"
-               "LSETUP(.Lloop_s, .Lloop_e) LC0 = %[lc];"
-               ".Lloop_s:"
-               "%[tmp] = extract(%[val], %[mask1].L)(Z);"
-               "%[tmp] <<= %[shift];"
-               "%[extr] = %[extr] | %[tmp];"
-               "%[mask1] = %[mask1] - %[mask2];"
-               ".Lloop_e:"
-               "%[shift] += 1;"
-               : [extr]"=&d"(extract), [shift]"=&d"(tmp_shift), [tmp]"=&d"(tmp),
-                 [mask1]"=&d"(tmp_mask1), [mask2]"=&d"(tmp_mask2)
-               : [val]"d"(value), [rxmask]"d"(up->rxmask), [lc]"a"(up->csize)
-               : "ASTAT", "LB0", "LC0", "LT0"
-       );
-
-       pr_debug("      extract:%x\n", extract);
-       return extract;
-}
-
-static int sport_uart_setup(struct sport_uart_port *up, int size, int baud_rate)
-{
-       int tclkdiv, rclkdiv;
-       unsigned int sclk = get_sclk();
-
-       /* Set TCR1 and TCR2, TFSR is not enabled for uart */
-       SPORT_PUT_TCR1(up, (LATFS | ITFS | TFSR | TLSBIT | ITCLK));
-       SPORT_PUT_TCR2(up, size + 1);
-       pr_debug("%s TCR1:%x, TCR2:%x\n", __func__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up));
-
-       /* Set RCR1 and RCR2 */
-       SPORT_PUT_RCR1(up, (RCKFE | LARFS | LRFS | RFSR | IRCLK));
-       SPORT_PUT_RCR2(up, (size + 1) * 2 - 1);
-       pr_debug("%s RCR1:%x, RCR2:%x\n", __func__, SPORT_GET_RCR1(up), SPORT_GET_RCR2(up));
-
-       tclkdiv = sclk / (2 * baud_rate) - 1;
-       /* The actual uart baud rate of devices vary between +/-2%. The sport
-        * RX sample rate should be faster than the double of the worst case,
-        * otherwise, wrong data are received. So, set sport RX clock to be
-        * 3% faster.
-        */
-       rclkdiv = sclk / (2 * baud_rate * 2 * 97 / 100) - 1;
-       SPORT_PUT_TCLKDIV(up, tclkdiv);
-       SPORT_PUT_RCLKDIV(up, rclkdiv);
-       SSYNC();
-       pr_debug("%s sclk:%d, baud_rate:%d, tclkdiv:%d, rclkdiv:%d\n",
-                       __func__, sclk, baud_rate, tclkdiv, rclkdiv);
-
-       return 0;
-}
-
-static irqreturn_t sport_uart_rx_irq(int irq, void *dev_id)
-{
-       struct sport_uart_port *up = dev_id;
-       struct tty_struct *tty = up->port.state->port.tty;
-       unsigned int ch;
-
-       spin_lock(&up->port.lock);
-
-       while (SPORT_GET_STAT(up) & RXNE) {
-               ch = rx_one_byte(up);
-               up->port.icount.rx++;
-
-               if (!uart_handle_sysrq_char(&up->port, ch))
-                       tty_insert_flip_char(tty, ch, TTY_NORMAL);
-       }
-       tty_flip_buffer_push(tty);
-
-       spin_unlock(&up->port.lock);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t sport_uart_tx_irq(int irq, void *dev_id)
-{
-       struct sport_uart_port *up = dev_id;
-
-       spin_lock(&up->port.lock);
-       sport_uart_tx_chars(up);
-       spin_unlock(&up->port.lock);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t sport_uart_err_irq(int irq, void *dev_id)
-{
-       struct sport_uart_port *up = dev_id;
-       struct tty_struct *tty = up->port.state->port.tty;
-       unsigned int stat = SPORT_GET_STAT(up);
-
-       spin_lock(&up->port.lock);
-
-       /* Overflow in RX FIFO */
-       if (stat & ROVF) {
-               up->port.icount.overrun++;
-               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               SPORT_PUT_STAT(up, ROVF); /* Clear ROVF bit */
-       }
-       /* These should not happen */
-       if (stat & (TOVF | TUVF | RUVF)) {
-               pr_err("SPORT Error:%s %s %s\n",
-                      (stat & TOVF) ? "TX overflow" : "",
-                      (stat & TUVF) ? "TX underflow" : "",
-                      (stat & RUVF) ? "RX underflow" : "");
-               SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN);
-               SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) & ~RSPEN);
-       }
-       SSYNC();
-
-       spin_unlock(&up->port.lock);
-       return IRQ_HANDLED;
-}
-
-#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
-static unsigned int sport_get_mctrl(struct uart_port *port)
-{
-       struct sport_uart_port *up = (struct sport_uart_port *)port;
-       if (up->cts_pin < 0)
-               return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
-
-       /* CTS PIN is negative assertive. */
-       if (SPORT_UART_GET_CTS(up))
-               return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
-       else
-               return TIOCM_DSR | TIOCM_CAR;
-}
-
-static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct sport_uart_port *up = (struct sport_uart_port *)port;
-       if (up->rts_pin < 0)
-               return;
-
-       /* RTS PIN is negative assertive. */
-       if (mctrl & TIOCM_RTS)
-               SPORT_UART_ENABLE_RTS(up);
-       else
-               SPORT_UART_DISABLE_RTS(up);
-}
-
-/*
- * Handle any change of modem status signal.
- */
-static irqreturn_t sport_mctrl_cts_int(int irq, void *dev_id)
-{
-       struct sport_uart_port *up = (struct sport_uart_port *)dev_id;
-       unsigned int status;
-
-       status = sport_get_mctrl(&up->port);
-       uart_handle_cts_change(&up->port, status & TIOCM_CTS);
-
-       return IRQ_HANDLED;
-}
-#else
-static unsigned int sport_get_mctrl(struct uart_port *port)
-{
-       pr_debug("%s enter\n", __func__);
-       return TIOCM_CTS | TIOCM_CD | TIOCM_DSR;
-}
-
-static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       pr_debug("%s enter\n", __func__);
-}
-#endif
-
-/* Reqeust IRQ, Setup clock */
-static int sport_startup(struct uart_port *port)
-{
-       struct sport_uart_port *up = (struct sport_uart_port *)port;
-       int ret;
-
-       pr_debug("%s enter\n", __func__);
-       ret = request_irq(up->port.irq, sport_uart_rx_irq, 0,
-               "SPORT_UART_RX", up);
-       if (ret) {
-               dev_err(port->dev, "unable to request SPORT RX interrupt\n");
-               return ret;
-       }
-
-       ret = request_irq(up->port.irq+1, sport_uart_tx_irq, 0,
-               "SPORT_UART_TX", up);
-       if (ret) {
-               dev_err(port->dev, "unable to request SPORT TX interrupt\n");
-               goto fail1;
-       }
-
-       ret = request_irq(up->err_irq, sport_uart_err_irq, 0,
-               "SPORT_UART_STATUS", up);
-       if (ret) {
-               dev_err(port->dev, "unable to request SPORT status interrupt\n");
-               goto fail2;
-       }
-
-#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
-       if (up->cts_pin >= 0) {
-               if (request_irq(gpio_to_irq(up->cts_pin),
-                       sport_mctrl_cts_int,
-                       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
-                       IRQF_DISABLED, "BFIN_SPORT_UART_CTS", up)) {
-                       up->cts_pin = -1;
-                       dev_info(port->dev, "Unable to attach BlackFin UART \
-                               over SPORT CTS interrupt. So, disable it.\n");
-               }
-       }
-       if (up->rts_pin >= 0)
-               gpio_direction_output(up->rts_pin, 0);
-#endif
-
-       return 0;
- fail2:
-       free_irq(up->port.irq+1, up);
- fail1:
-       free_irq(up->port.irq, up);
-
-       return ret;
-}
-
-/*
- * sport_uart_tx_chars
- *
- * ret 1 means need to enable sport.
- * ret 0 means do nothing.
- */
-static int sport_uart_tx_chars(struct sport_uart_port *up)
-{
-       struct circ_buf *xmit = &up->port.state->xmit;
-
-       if (SPORT_GET_STAT(up) & TXF)
-               return 0;
-
-       if (up->port.x_char) {
-               tx_one_byte(up, up->port.x_char);
-               up->port.icount.tx++;
-               up->port.x_char = 0;
-               return 1;
-       }
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
-               /* The waiting loop to stop SPORT TX from TX interrupt is
-                * too long. This may block SPORT RX interrupts and cause
-                * RX FIFO overflow. So, do stop sport TX only after the last
-                * char in TX FIFO is moved into the shift register.
-                */
-               if (SPORT_GET_STAT(up) & TXHRE)
-                       sport_stop_tx(&up->port);
-               return 0;
-       }
-
-       while(!(SPORT_GET_STAT(up) & TXF) && !uart_circ_empty(xmit)) {
-               tx_one_byte(up, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1);
-               up->port.icount.tx++;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&up->port);
-
-       return 1;
-}
-
-static unsigned int sport_tx_empty(struct uart_port *port)
-{
-       struct sport_uart_port *up = (struct sport_uart_port *)port;
-       unsigned int stat;
-
-       stat = SPORT_GET_STAT(up);
-       pr_debug("%s stat:%04x\n", __func__, stat);
-       if (stat & TXHRE) {
-               return TIOCSER_TEMT;
-       } else
-               return 0;
-}
-
-static void sport_stop_tx(struct uart_port *port)
-{
-       struct sport_uart_port *up = (struct sport_uart_port *)port;
-
-       pr_debug("%s enter\n", __func__);
-
-       if (!(SPORT_GET_TCR1(up) & TSPEN))
-               return;
-
-       /* Although the hold register is empty, last byte is still in shift
-        * register and not sent out yet. So, put a dummy data into TX FIFO.
-        * Then, sport tx stops when last byte is shift out and the dummy
-        * data is moved into the shift register.
-        */
-       SPORT_PUT_TX(up, 0xffff);
-       while (!(SPORT_GET_STAT(up) & TXHRE))
-               cpu_relax();
-
-       SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN));
-       SSYNC();
-
-       return;
-}
-
-static void sport_start_tx(struct uart_port *port)
-{
-       struct sport_uart_port *up = (struct sport_uart_port *)port;
-
-       pr_debug("%s enter\n", __func__);
-
-       /* Write data into SPORT FIFO before enable SPROT to transmit */
-       if (sport_uart_tx_chars(up)) {
-               /* Enable transmit, then an interrupt will generated */
-               SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN));
-               SSYNC();
-       }
-
-       pr_debug("%s exit\n", __func__);
-}
-
-static void sport_stop_rx(struct uart_port *port)
-{
-       struct sport_uart_port *up = (struct sport_uart_port *)port;
-
-       pr_debug("%s enter\n", __func__);
-       /* Disable sport to stop rx */
-       SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) & ~RSPEN));
-       SSYNC();
-}
-
-static void sport_enable_ms(struct uart_port *port)
-{
-       pr_debug("%s enter\n", __func__);
-}
-
-static void sport_break_ctl(struct uart_port *port, int break_state)
-{
-       pr_debug("%s enter\n", __func__);
-}
-
-static void sport_shutdown(struct uart_port *port)
-{
-       struct sport_uart_port *up = (struct sport_uart_port *)port;
-
-       dev_dbg(port->dev, "%s enter\n", __func__);
-
-       /* Disable sport */
-       SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN));
-       SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) & ~RSPEN));
-       SSYNC();
-
-       free_irq(up->port.irq, up);
-       free_irq(up->port.irq+1, up);
-       free_irq(up->err_irq, up);
-#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
-       if (up->cts_pin >= 0)
-               free_irq(gpio_to_irq(up->cts_pin), up);
-#endif
-}
-
-static const char *sport_type(struct uart_port *port)
-{
-       struct sport_uart_port *up = (struct sport_uart_port *)port;
-
-       pr_debug("%s enter\n", __func__);
-       return up->port.type == PORT_BFIN_SPORT ? "BFIN-SPORT-UART" : NULL;
-}
-
-static void sport_release_port(struct uart_port *port)
-{
-       pr_debug("%s enter\n", __func__);
-}
-
-static int sport_request_port(struct uart_port *port)
-{
-       pr_debug("%s enter\n", __func__);
-       return 0;
-}
-
-static void sport_config_port(struct uart_port *port, int flags)
-{
-       struct sport_uart_port *up = (struct sport_uart_port *)port;
-
-       pr_debug("%s enter\n", __func__);
-       up->port.type = PORT_BFIN_SPORT;
-}
-
-static int sport_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       pr_debug("%s enter\n", __func__);
-       return 0;
-}
-
-static void sport_set_termios(struct uart_port *port,
-               struct ktermios *termios, struct ktermios *old)
-{
-       struct sport_uart_port *up = (struct sport_uart_port *)port;
-       unsigned long flags;
-       int i;
-
-       pr_debug("%s enter, c_cflag:%08x\n", __func__, termios->c_cflag);
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS8:
-               up->csize = 8;
-               break;
-       case CS7:
-               up->csize = 7;
-               break;
-       case CS6:
-               up->csize = 6;
-               break;
-       case CS5:
-               up->csize = 5;
-               break;
-       default:
-               pr_warning("requested word length not supported\n");
-       }
-
-       if (termios->c_cflag & CSTOPB) {
-               up->stopb = 1;
-       }
-       if (termios->c_cflag & PARENB) {
-               pr_warning("PAREN bits is not supported yet\n");
-               /* up->parib = 1; */
-       }
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       port->read_status_mask = 0;
-
-       /*
-        * Characters to ignore
-        */
-       port->ignore_status_mask = 0;
-
-       /* RX extract mask */
-       up->rxmask = 0x01 | (((up->csize + up->stopb) * 2 - 1) << 0x8);
-       /* TX masks, 8 bit data and 1 bit stop for example:
-        * mask1 = b#0111111110
-        * mask2 = b#1000000000
-        */
-       for (i = 0, up->txmask1 = 0; i < up->csize; i++)
-               up->txmask1 |= (1<<i);
-       up->txmask2 = (1<<i);
-       if (up->stopb) {
-               ++i;
-               up->txmask2 |= (1<<i);
-       }
-       up->txmask1 <<= 1;
-       up->txmask2 <<= 1;
-       /* uart baud rate */
-       port->uartclk = uart_get_baud_rate(port, termios, old, 0, get_sclk()/16);
-
-       /* Disable UART */
-       SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN);
-       SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) & ~RSPEN);
-
-       sport_uart_setup(up, up->csize + up->stopb, port->uartclk);
-
-       /* driver TX line high after config, one dummy data is
-        * necessary to stop sport after shift one byte
-        */
-       SPORT_PUT_TX(up, 0xffff);
-       SPORT_PUT_TX(up, 0xffff);
-       SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN));
-       SSYNC();
-       while (!(SPORT_GET_STAT(up) & TXHRE))
-               cpu_relax();
-       SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN);
-       SSYNC();
-
-       /* Port speed changed, update the per-port timeout. */
-       uart_update_timeout(port, termios->c_cflag, port->uartclk);
-
-       /* Enable sport rx */
-       SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) | RSPEN);
-       SSYNC();
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-struct uart_ops sport_uart_ops = {
-       .tx_empty       = sport_tx_empty,
-       .set_mctrl      = sport_set_mctrl,
-       .get_mctrl      = sport_get_mctrl,
-       .stop_tx        = sport_stop_tx,
-       .start_tx       = sport_start_tx,
-       .stop_rx        = sport_stop_rx,
-       .enable_ms      = sport_enable_ms,
-       .break_ctl      = sport_break_ctl,
-       .startup        = sport_startup,
-       .shutdown       = sport_shutdown,
-       .set_termios    = sport_set_termios,
-       .type           = sport_type,
-       .release_port   = sport_release_port,
-       .request_port   = sport_request_port,
-       .config_port    = sport_config_port,
-       .verify_port    = sport_verify_port,
-};
-
-#define BFIN_SPORT_UART_MAX_PORTS 4
-
-static struct sport_uart_port *bfin_sport_uart_ports[BFIN_SPORT_UART_MAX_PORTS];
-
-#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
-#define CLASS_BFIN_SPORT_CONSOLE       "bfin-sport-console"
-
-static int __init
-sport_uart_console_setup(struct console *co, char *options)
-{
-       struct sport_uart_port *up;
-       int baud = 57600;
-       int bits = 8;
-       int parity = 'n';
-# ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
-       int flow = 'r';
-# else
-       int flow = 'n';
-# endif
-
-       /* Check whether an invalid uart number has been specified */
-       if (co->index < 0 || co->index >= BFIN_SPORT_UART_MAX_PORTS)
-               return -ENODEV;
-
-       up = bfin_sport_uart_ports[co->index];
-       if (!up)
-               return -ENODEV;
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(&up->port, co, baud, parity, bits, flow);
-}
-
-static void sport_uart_console_putchar(struct uart_port *port, int ch)
-{
-       struct sport_uart_port *up = (struct sport_uart_port *)port;
-
-       while (SPORT_GET_STAT(up) & TXF)
-               barrier();
-
-       tx_one_byte(up, ch);
-}
-
-/*
- * Interrupts are disabled on entering
- */
-static void
-sport_uart_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct sport_uart_port *up = bfin_sport_uart_ports[co->index];
-       unsigned long flags;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       if (SPORT_GET_TCR1(up) & TSPEN)
-               uart_console_write(&up->port, s, count, sport_uart_console_putchar);
-       else {
-               /* dummy data to start sport */
-               while (SPORT_GET_STAT(up) & TXF)
-                       barrier();
-               SPORT_PUT_TX(up, 0xffff);
-               /* Enable transmit, then an interrupt will generated */
-               SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN));
-               SSYNC();
-
-               uart_console_write(&up->port, s, count, sport_uart_console_putchar);
-
-               /* Although the hold register is empty, last byte is still in shift
-                * register and not sent out yet. So, put a dummy data into TX FIFO.
-                * Then, sport tx stops when last byte is shift out and the dummy
-                * data is moved into the shift register.
-                */
-               while (SPORT_GET_STAT(up) & TXF)
-                       barrier();
-               SPORT_PUT_TX(up, 0xffff);
-               while (!(SPORT_GET_STAT(up) & TXHRE))
-                       barrier();
-
-               /* Stop sport tx transfer */
-               SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN));
-               SSYNC();
-       }
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static struct uart_driver sport_uart_reg;
-
-static struct console sport_uart_console = {
-       .name           = DEVICE_NAME,
-       .write          = sport_uart_console_write,
-       .device         = uart_console_device,
-       .setup          = sport_uart_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &sport_uart_reg,
-};
-
-#define SPORT_UART_CONSOLE     (&sport_uart_console)
-#else
-#define SPORT_UART_CONSOLE     NULL
-#endif /* CONFIG_SERIAL_BFIN_SPORT_CONSOLE */
-
-
-static struct uart_driver sport_uart_reg = {
-       .owner          = THIS_MODULE,
-       .driver_name    = DRV_NAME,
-       .dev_name       = DEVICE_NAME,
-       .major          = 204,
-       .minor          = 84,
-       .nr             = BFIN_SPORT_UART_MAX_PORTS,
-       .cons           = SPORT_UART_CONSOLE,
-};
-
-#ifdef CONFIG_PM
-static int sport_uart_suspend(struct device *dev)
-{
-       struct sport_uart_port *sport = dev_get_drvdata(dev);
-
-       dev_dbg(dev, "%s enter\n", __func__);
-       if (sport)
-               uart_suspend_port(&sport_uart_reg, &sport->port);
-
-       return 0;
-}
-
-static int sport_uart_resume(struct device *dev)
-{
-       struct sport_uart_port *sport = dev_get_drvdata(dev);
-
-       dev_dbg(dev, "%s enter\n", __func__);
-       if (sport)
-               uart_resume_port(&sport_uart_reg, &sport->port);
-
-       return 0;
-}
-
-static struct dev_pm_ops bfin_sport_uart_dev_pm_ops = {
-       .suspend        = sport_uart_suspend,
-       .resume         = sport_uart_resume,
-};
-#endif
-
-static int __devinit sport_uart_probe(struct platform_device *pdev)
-{
-       struct resource *res;
-       struct sport_uart_port *sport;
-       int ret = 0;
-
-       dev_dbg(&pdev->dev, "%s enter\n", __func__);
-
-       if (pdev->id < 0 || pdev->id >= BFIN_SPORT_UART_MAX_PORTS) {
-               dev_err(&pdev->dev, "Wrong sport uart platform device id.\n");
-               return -ENOENT;
-       }
-
-       if (bfin_sport_uart_ports[pdev->id] == NULL) {
-               bfin_sport_uart_ports[pdev->id] =
-                       kzalloc(sizeof(struct sport_uart_port), GFP_KERNEL);
-               sport = bfin_sport_uart_ports[pdev->id];
-               if (!sport) {
-                       dev_err(&pdev->dev,
-                               "Fail to malloc sport_uart_port\n");
-                       return -ENOMEM;
-               }
-
-               ret = peripheral_request_list(
-                       (unsigned short *)pdev->dev.platform_data, DRV_NAME);
-               if (ret) {
-                       dev_err(&pdev->dev,
-                               "Fail to request SPORT peripherals\n");
-                       goto out_error_free_mem;
-               }
-
-               spin_lock_init(&sport->port.lock);
-               sport->port.fifosize  = SPORT_TX_FIFO_SIZE,
-               sport->port.ops       = &sport_uart_ops;
-               sport->port.line      = pdev->id;
-               sport->port.iotype    = UPIO_MEM;
-               sport->port.flags     = UPF_BOOT_AUTOCONF;
-
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-               if (res == NULL) {
-                       dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
-                       ret = -ENOENT;
-                       goto out_error_free_peripherals;
-               }
-
-               sport->port.membase = ioremap(res->start, resource_size(res));
-               if (!sport->port.membase) {
-                       dev_err(&pdev->dev, "Cannot map sport IO\n");
-                       ret = -ENXIO;
-                       goto out_error_free_peripherals;
-               }
-               sport->port.mapbase = res->start;
-
-               sport->port.irq = platform_get_irq(pdev, 0);
-               if (sport->port.irq < 0) {
-                       dev_err(&pdev->dev, "No sport RX/TX IRQ specified\n");
-                       ret = -ENOENT;
-                       goto out_error_unmap;
-               }
-
-               sport->err_irq = platform_get_irq(pdev, 1);
-               if (sport->err_irq < 0) {
-                       dev_err(&pdev->dev, "No sport status IRQ specified\n");
-                       ret = -ENOENT;
-                       goto out_error_unmap;
-               }
-#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
-               res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-               if (res == NULL)
-                       sport->cts_pin = -1;
-               else
-                       sport->cts_pin = res->start;
-
-               res = platform_get_resource(pdev, IORESOURCE_IO, 1);
-               if (res == NULL)
-                       sport->rts_pin = -1;
-               else
-                       sport->rts_pin = res->start;
-
-               if (sport->rts_pin >= 0)
-                       gpio_request(sport->rts_pin, DRV_NAME);
-#endif
-       }
-
-#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
-       if (!is_early_platform_device(pdev)) {
-#endif
-               sport = bfin_sport_uart_ports[pdev->id];
-               sport->port.dev = &pdev->dev;
-               dev_set_drvdata(&pdev->dev, sport);
-               ret = uart_add_one_port(&sport_uart_reg, &sport->port);
-#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
-       }
-#endif
-       if (!ret)
-               return 0;
-
-       if (sport) {
-out_error_unmap:
-               iounmap(sport->port.membase);
-out_error_free_peripherals:
-               peripheral_free_list(
-                       (unsigned short *)pdev->dev.platform_data);
-out_error_free_mem:
-               kfree(sport);
-               bfin_sport_uart_ports[pdev->id] = NULL;
-       }
-
-       return ret;
-}
-
-static int __devexit sport_uart_remove(struct platform_device *pdev)
-{
-       struct sport_uart_port *sport = platform_get_drvdata(pdev);
-
-       dev_dbg(&pdev->dev, "%s enter\n", __func__);
-       dev_set_drvdata(&pdev->dev, NULL);
-
-       if (sport) {
-               uart_remove_one_port(&sport_uart_reg, &sport->port);
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-               if (sport->rts_pin >= 0)
-                       gpio_free(sport->rts_pin);
-#endif
-               iounmap(sport->port.membase);
-               peripheral_free_list(
-                       (unsigned short *)pdev->dev.platform_data);
-               kfree(sport);
-               bfin_sport_uart_ports[pdev->id] = NULL;
-       }
-
-       return 0;
-}
-
-static struct platform_driver sport_uart_driver = {
-       .probe          = sport_uart_probe,
-       .remove         = __devexit_p(sport_uart_remove),
-       .driver         = {
-               .name   = DRV_NAME,
-#ifdef CONFIG_PM
-               .pm     = &bfin_sport_uart_dev_pm_ops,
-#endif
-       },
-};
-
-#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
-static __initdata struct early_platform_driver early_sport_uart_driver = {
-       .class_str = CLASS_BFIN_SPORT_CONSOLE,
-       .pdrv = &sport_uart_driver,
-       .requested_id = EARLY_PLATFORM_ID_UNSET,
-};
-
-static int __init sport_uart_rs_console_init(void)
-{
-       early_platform_driver_register(&early_sport_uart_driver, DRV_NAME);
-
-       early_platform_driver_probe(CLASS_BFIN_SPORT_CONSOLE,
-               BFIN_SPORT_UART_MAX_PORTS, 0);
-
-       register_console(&sport_uart_console);
-
-       return 0;
-}
-console_initcall(sport_uart_rs_console_init);
-#endif
-
-static int __init sport_uart_init(void)
-{
-       int ret;
-
-       pr_info("Blackfin uart over sport driver\n");
-
-       ret = uart_register_driver(&sport_uart_reg);
-       if (ret) {
-               pr_err("failed to register %s:%d\n",
-                               sport_uart_reg.driver_name, ret);
-               return ret;
-       }
-
-       ret = platform_driver_register(&sport_uart_driver);
-       if (ret) {
-               pr_err("failed to register sport uart driver:%d\n", ret);
-               uart_unregister_driver(&sport_uart_reg);
-       }
-
-       return ret;
-}
-module_init(sport_uart_init);
-
-static void __exit sport_uart_exit(void)
-{
-       platform_driver_unregister(&sport_uart_driver);
-       uart_unregister_driver(&sport_uart_reg);
-}
-module_exit(sport_uart_exit);
-
-MODULE_AUTHOR("Sonic Zhang, Roy Huang");
-MODULE_DESCRIPTION("Blackfin serial over SPORT driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/bfin_sport_uart.h b/drivers/serial/bfin_sport_uart.h
deleted file mode 100644 (file)
index 6d06ce1..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Blackfin On-Chip Sport Emulated UART Driver
- *
- * Copyright 2006-2008 Analog Devices Inc.
- *
- * Enter bugs at http://blackfin.uclinux.org/
- *
- * Licensed under the GPL-2 or later.
- */
-
-/*
- * This driver and the hardware supported are in term of EE-191 of ADI.
- * http://www.analog.com/static/imported-files/application_notes/EE191.pdf 
- * This application note describe how to implement a UART on a Sharc DSP,
- * but this driver is implemented on Blackfin Processor.
- * Transmit Frame Sync is not used by this driver to transfer data out.
- */
-
-#ifndef _BFIN_SPORT_UART_H
-#define _BFIN_SPORT_UART_H
-
-#define OFFSET_TCR1            0x00    /* Transmit Configuration 1 Register */
-#define OFFSET_TCR2            0x04    /* Transmit Configuration 2 Register */
-#define OFFSET_TCLKDIV         0x08    /* Transmit Serial Clock Divider Register */
-#define OFFSET_TFSDIV          0x0C    /* Transmit Frame Sync Divider Register */
-#define OFFSET_TX              0x10    /* Transmit Data Register               */
-#define OFFSET_RX              0x18    /* Receive Data Register                */
-#define OFFSET_RCR1            0x20    /* Receive Configuration 1 Register     */
-#define OFFSET_RCR2            0x24    /* Receive Configuration 2 Register     */
-#define OFFSET_RCLKDIV         0x28    /* Receive Serial Clock Divider Register */
-#define OFFSET_RFSDIV          0x2c    /* Receive Frame Sync Divider Register */
-#define OFFSET_STAT            0x30    /* Status Register                      */
-
-#define SPORT_GET_TCR1(sport)          bfin_read16(((sport)->port.membase + OFFSET_TCR1))
-#define SPORT_GET_TCR2(sport)          bfin_read16(((sport)->port.membase + OFFSET_TCR2))
-#define SPORT_GET_TCLKDIV(sport)       bfin_read16(((sport)->port.membase + OFFSET_TCLKDIV))
-#define SPORT_GET_TFSDIV(sport)                bfin_read16(((sport)->port.membase + OFFSET_TFSDIV))
-#define SPORT_GET_TX(sport)            bfin_read16(((sport)->port.membase + OFFSET_TX))
-#define SPORT_GET_RX(sport)            bfin_read16(((sport)->port.membase + OFFSET_RX))
-/*
- * If another interrupt fires while doing a 32-bit read from RX FIFO,
- * a fake RX underflow error will be generated.  So disable interrupts
- * to prevent interruption while reading the FIFO.
- */
-#define SPORT_GET_RX32(sport) \
-({ \
-       unsigned int __ret; \
-       if (ANOMALY_05000473) \
-               local_irq_disable(); \
-       __ret = bfin_read32((sport)->port.membase + OFFSET_RX); \
-       if (ANOMALY_05000473) \
-               local_irq_enable(); \
-       __ret; \
-})
-#define SPORT_GET_RCR1(sport)          bfin_read16(((sport)->port.membase + OFFSET_RCR1))
-#define SPORT_GET_RCR2(sport)          bfin_read16(((sport)->port.membase + OFFSET_RCR2))
-#define SPORT_GET_RCLKDIV(sport)       bfin_read16(((sport)->port.membase + OFFSET_RCLKDIV))
-#define SPORT_GET_RFSDIV(sport)                bfin_read16(((sport)->port.membase + OFFSET_RFSDIV))
-#define SPORT_GET_STAT(sport)          bfin_read16(((sport)->port.membase + OFFSET_STAT))
-
-#define SPORT_PUT_TCR1(sport, v)       bfin_write16(((sport)->port.membase + OFFSET_TCR1), v)
-#define SPORT_PUT_TCR2(sport, v)       bfin_write16(((sport)->port.membase + OFFSET_TCR2), v)
-#define SPORT_PUT_TCLKDIV(sport, v)    bfin_write16(((sport)->port.membase + OFFSET_TCLKDIV), v)
-#define SPORT_PUT_TFSDIV(sport, v)     bfin_write16(((sport)->port.membase + OFFSET_TFSDIV), v)
-#define SPORT_PUT_TX(sport, v)         bfin_write16(((sport)->port.membase + OFFSET_TX), v)
-#define SPORT_PUT_RX(sport, v)         bfin_write16(((sport)->port.membase + OFFSET_RX), v)
-#define SPORT_PUT_RCR1(sport, v)       bfin_write16(((sport)->port.membase + OFFSET_RCR1), v)
-#define SPORT_PUT_RCR2(sport, v)       bfin_write16(((sport)->port.membase + OFFSET_RCR2), v)
-#define SPORT_PUT_RCLKDIV(sport, v)    bfin_write16(((sport)->port.membase + OFFSET_RCLKDIV), v)
-#define SPORT_PUT_RFSDIV(sport, v)     bfin_write16(((sport)->port.membase + OFFSET_RFSDIV), v)
-#define SPORT_PUT_STAT(sport, v)       bfin_write16(((sport)->port.membase + OFFSET_STAT), v)
-
-#define SPORT_TX_FIFO_SIZE     8
-
-#define SPORT_UART_GET_CTS(x)          gpio_get_value(x->cts_pin)
-#define SPORT_UART_DISABLE_RTS(x)      gpio_set_value(x->rts_pin, 1)
-#define SPORT_UART_ENABLE_RTS(x)       gpio_set_value(x->rts_pin, 0)
-
-#if defined(CONFIG_SERIAL_BFIN_SPORT0_UART_CTSRTS) \
-       || defined(CONFIG_SERIAL_BFIN_SPORT1_UART_CTSRTS) \
-       || defined(CONFIG_SERIAL_BFIN_SPORT2_UART_CTSRTS) \
-       || defined(CONFIG_SERIAL_BFIN_SPORT3_UART_CTSRTS)
-# define CONFIG_SERIAL_BFIN_SPORT_CTSRTS
-#endif
-
-#endif /* _BFIN_SPORT_UART_H */
diff --git a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c
deleted file mode 100644 (file)
index b6acd19..0000000
+++ /dev/null
@@ -1,579 +0,0 @@
-/*
- *  linux/drivers/char/clps711x.c
- *
- *  Driver for CLPS711x serial ports
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *
- *  Copyright 1999 ARM Limited
- *  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
- */
-
-#if defined(CONFIG_SERIAL_CLPS711X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/spinlock.h>
-#include <linux/device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/hardware/clps7111.h>
-
-#define UART_NR                2
-
-#define SERIAL_CLPS711X_MAJOR  204
-#define SERIAL_CLPS711X_MINOR  40
-#define SERIAL_CLPS711X_NR     UART_NR
-
-/*
- * We use the relevant SYSCON register as a base address for these ports.
- */
-#define UBRLCR(port)           ((port)->iobase + UBRLCR1 - SYSCON1)
-#define UARTDR(port)           ((port)->iobase + UARTDR1 - SYSCON1)
-#define SYSFLG(port)           ((port)->iobase + SYSFLG1 - SYSCON1)
-#define SYSCON(port)           ((port)->iobase + SYSCON1 - SYSCON1)
-
-#define TX_IRQ(port)           ((port)->irq)
-#define RX_IRQ(port)           ((port)->irq + 1)
-
-#define UART_ANY_ERR           (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR)
-
-#define tx_enabled(port)       ((port)->unused[0])
-
-static void clps711xuart_stop_tx(struct uart_port *port)
-{
-       if (tx_enabled(port)) {
-               disable_irq(TX_IRQ(port));
-               tx_enabled(port) = 0;
-       }
-}
-
-static void clps711xuart_start_tx(struct uart_port *port)
-{
-       if (!tx_enabled(port)) {
-               enable_irq(TX_IRQ(port));
-               tx_enabled(port) = 1;
-       }
-}
-
-static void clps711xuart_stop_rx(struct uart_port *port)
-{
-       disable_irq(RX_IRQ(port));
-}
-
-static void clps711xuart_enable_ms(struct uart_port *port)
-{
-}
-
-static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       struct tty_struct *tty = port->state->port.tty;
-       unsigned int status, ch, flg;
-
-       status = clps_readl(SYSFLG(port));
-       while (!(status & SYSFLG_URXFE)) {
-               ch = clps_readl(UARTDR(port));
-
-               port->icount.rx++;
-
-               flg = TTY_NORMAL;
-
-               /*
-                * Note that the error handling code is
-                * out of the main execution path
-                */
-               if (unlikely(ch & UART_ANY_ERR)) {
-                       if (ch & UARTDR_PARERR)
-                               port->icount.parity++;
-                       else if (ch & UARTDR_FRMERR)
-                               port->icount.frame++;
-                       if (ch & UARTDR_OVERR)
-                               port->icount.overrun++;
-
-                       ch &= port->read_status_mask;
-
-                       if (ch & UARTDR_PARERR)
-                               flg = TTY_PARITY;
-                       else if (ch & UARTDR_FRMERR)
-                               flg = TTY_FRAME;
-
-#ifdef SUPPORT_SYSRQ
-                       port->sysrq = 0;
-#endif
-               }
-
-               if (uart_handle_sysrq_char(port, ch))
-                       goto ignore_char;
-
-               /*
-                * CHECK: does overrun affect the current character?
-                * ASSUMPTION: it does not.
-                */
-               uart_insert_char(port, ch, UARTDR_OVERR, ch, flg);
-
-       ignore_char:
-               status = clps_readl(SYSFLG(port));
-       }
-       tty_flip_buffer_push(tty);
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       struct circ_buf *xmit = &port->state->xmit;
-       int count;
-
-       if (port->x_char) {
-               clps_writel(port->x_char, UARTDR(port));
-               port->icount.tx++;
-               port->x_char = 0;
-               return IRQ_HANDLED;
-       }
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               clps711xuart_stop_tx(port);
-               return IRQ_HANDLED;
-       }
-
-       count = port->fifosize >> 1;
-       do {
-               clps_writel(xmit->buf[xmit->tail], UARTDR(port));
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (--count > 0);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (uart_circ_empty(xmit))
-               clps711xuart_stop_tx(port);
-
-       return IRQ_HANDLED;
-}
-
-static unsigned int clps711xuart_tx_empty(struct uart_port *port)
-{
-       unsigned int status = clps_readl(SYSFLG(port));
-       return status & SYSFLG_UBUSY ? 0 : TIOCSER_TEMT;
-}
-
-static unsigned int clps711xuart_get_mctrl(struct uart_port *port)
-{
-       unsigned int port_addr;
-       unsigned int result = 0;
-       unsigned int status;
-
-       port_addr = SYSFLG(port);
-       if (port_addr == SYSFLG1) {
-               status = clps_readl(SYSFLG1);
-               if (status & SYSFLG1_DCD)
-                       result |= TIOCM_CAR;
-               if (status & SYSFLG1_DSR)
-                       result |= TIOCM_DSR;
-               if (status & SYSFLG1_CTS)
-                       result |= TIOCM_CTS;
-       }
-
-       return result;
-}
-
-static void
-clps711xuart_set_mctrl_null(struct uart_port *port, unsigned int mctrl)
-{
-}
-
-static void clps711xuart_break_ctl(struct uart_port *port, int break_state)
-{
-       unsigned long flags;
-       unsigned int ubrlcr;
-
-       spin_lock_irqsave(&port->lock, flags);
-       ubrlcr = clps_readl(UBRLCR(port));
-       if (break_state == -1)
-               ubrlcr |= UBRLCR_BREAK;
-       else
-               ubrlcr &= ~UBRLCR_BREAK;
-       clps_writel(ubrlcr, UBRLCR(port));
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static int clps711xuart_startup(struct uart_port *port)
-{
-       unsigned int syscon;
-       int retval;
-
-       tx_enabled(port) = 1;
-
-       /*
-        * Allocate the IRQs
-        */
-       retval = request_irq(TX_IRQ(port), clps711xuart_int_tx, 0,
-                            "clps711xuart_tx", port);
-       if (retval)
-               return retval;
-
-       retval = request_irq(RX_IRQ(port), clps711xuart_int_rx, 0,
-                            "clps711xuart_rx", port);
-       if (retval) {
-               free_irq(TX_IRQ(port), port);
-               return retval;
-       }
-
-       /*
-        * enable the port
-        */
-       syscon = clps_readl(SYSCON(port));
-       syscon |= SYSCON_UARTEN;
-       clps_writel(syscon, SYSCON(port));
-
-       return 0;
-}
-
-static void clps711xuart_shutdown(struct uart_port *port)
-{
-       unsigned int ubrlcr, syscon;
-
-       /*
-        * Free the interrupt
-        */
-       free_irq(TX_IRQ(port), port);   /* TX interrupt */
-       free_irq(RX_IRQ(port), port);   /* RX interrupt */
-
-       /*
-        * disable the port
-        */
-       syscon = clps_readl(SYSCON(port));
-       syscon &= ~SYSCON_UARTEN;
-       clps_writel(syscon, SYSCON(port));
-
-       /*
-        * disable break condition and fifos
-        */
-       ubrlcr = clps_readl(UBRLCR(port));
-       ubrlcr &= ~(UBRLCR_FIFOEN | UBRLCR_BREAK);
-       clps_writel(ubrlcr, UBRLCR(port));
-}
-
-static void
-clps711xuart_set_termios(struct uart_port *port, struct ktermios *termios,
-                        struct ktermios *old)
-{
-       unsigned int ubrlcr, baud, quot;
-       unsigned long flags;
-
-       /*
-        * We don't implement CREAD.
-        */
-       termios->c_cflag |= CREAD;
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
-       quot = uart_get_divisor(port, baud);
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               ubrlcr = UBRLCR_WRDLEN5;
-               break;
-       case CS6:
-               ubrlcr = UBRLCR_WRDLEN6;
-               break;
-       case CS7:
-               ubrlcr = UBRLCR_WRDLEN7;
-               break;
-       default: // CS8
-               ubrlcr = UBRLCR_WRDLEN8;
-               break;
-       }
-       if (termios->c_cflag & CSTOPB)
-               ubrlcr |= UBRLCR_XSTOP;
-       if (termios->c_cflag & PARENB) {
-               ubrlcr |= UBRLCR_PRTEN;
-               if (!(termios->c_cflag & PARODD))
-                       ubrlcr |= UBRLCR_EVENPRT;
-       }
-       if (port->fifosize > 1)
-               ubrlcr |= UBRLCR_FIFOEN;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       port->read_status_mask = UARTDR_OVERR;
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= UARTDR_PARERR | UARTDR_FRMERR;
-
-       /*
-        * Characters to ignore
-        */
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= UARTDR_FRMERR | UARTDR_PARERR;
-       if (termios->c_iflag & IGNBRK) {
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns to (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       port->ignore_status_mask |= UARTDR_OVERR;
-       }
-
-       quot -= 1;
-
-       clps_writel(ubrlcr | quot, UBRLCR(port));
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *clps711xuart_type(struct uart_port *port)
-{
-       return port->type == PORT_CLPS711X ? "CLPS711x" : NULL;
-}
-
-/*
- * Configure/autoconfigure the port.
- */
-static void clps711xuart_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE)
-               port->type = PORT_CLPS711X;
-}
-
-static void clps711xuart_release_port(struct uart_port *port)
-{
-}
-
-static int clps711xuart_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-static struct uart_ops clps711x_pops = {
-       .tx_empty       = clps711xuart_tx_empty,
-       .set_mctrl      = clps711xuart_set_mctrl_null,
-       .get_mctrl      = clps711xuart_get_mctrl,
-       .stop_tx        = clps711xuart_stop_tx,
-       .start_tx       = clps711xuart_start_tx,
-       .stop_rx        = clps711xuart_stop_rx,
-       .enable_ms      = clps711xuart_enable_ms,
-       .break_ctl      = clps711xuart_break_ctl,
-       .startup        = clps711xuart_startup,
-       .shutdown       = clps711xuart_shutdown,
-       .set_termios    = clps711xuart_set_termios,
-       .type           = clps711xuart_type,
-       .config_port    = clps711xuart_config_port,
-       .release_port   = clps711xuart_release_port,
-       .request_port   = clps711xuart_request_port,
-};
-
-static struct uart_port clps711x_ports[UART_NR] = {
-       {
-               .iobase         = SYSCON1,
-               .irq            = IRQ_UTXINT1, /* IRQ_URXINT1, IRQ_UMSINT */
-               .uartclk        = 3686400,
-               .fifosize       = 16,
-               .ops            = &clps711x_pops,
-               .line           = 0,
-               .flags          = UPF_BOOT_AUTOCONF,
-       },
-       {
-               .iobase         = SYSCON2,
-               .irq            = IRQ_UTXINT2, /* IRQ_URXINT2 */
-               .uartclk        = 3686400,
-               .fifosize       = 16,
-               .ops            = &clps711x_pops,
-               .line           = 1,
-               .flags          = UPF_BOOT_AUTOCONF,
-       }
-};
-
-#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
-static void clps711xuart_console_putchar(struct uart_port *port, int ch)
-{
-       while (clps_readl(SYSFLG(port)) & SYSFLG_UTXFF)
-               barrier();
-       clps_writel(ch, UARTDR(port));
-}
-
-/*
- *     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
-clps711xuart_console_write(struct console *co, const char *s,
-                          unsigned int count)
-{
-       struct uart_port *port = clps711x_ports + co->index;
-       unsigned int status, syscon;
-
-       /*
-        *      Ensure that the port is enabled.
-        */
-       syscon = clps_readl(SYSCON(port));
-       clps_writel(syscon | SYSCON_UARTEN, SYSCON(port));
-
-       uart_console_write(port, s, count, clps711xuart_console_putchar);
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore the uart state.
-        */
-       do {
-               status = clps_readl(SYSFLG(port));
-       } while (status & SYSFLG_UBUSY);
-
-       clps_writel(syscon, SYSCON(port));
-}
-
-static void __init
-clps711xuart_console_get_options(struct uart_port *port, int *baud,
-                                int *parity, int *bits)
-{
-       if (clps_readl(SYSCON(port)) & SYSCON_UARTEN) {
-               unsigned int ubrlcr, quot;
-
-               ubrlcr = clps_readl(UBRLCR(port));
-
-               *parity = 'n';
-               if (ubrlcr & UBRLCR_PRTEN) {
-                       if (ubrlcr & UBRLCR_EVENPRT)
-                               *parity = 'e';
-                       else
-                               *parity = 'o';
-               }
-
-               if ((ubrlcr & UBRLCR_WRDLEN_MASK) == UBRLCR_WRDLEN7)
-                       *bits = 7;
-               else
-                       *bits = 8;
-
-               quot = ubrlcr & UBRLCR_BAUD_MASK;
-               *baud = port->uartclk / (16 * (quot + 1));
-       }
-}
-
-static int __init clps711xuart_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(clps711x_ports, UART_NR, co);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               clps711xuart_console_get_options(port, &baud, &parity, &bits);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver clps711x_reg;
-static struct console clps711x_console = {
-       .name           = "ttyCL",
-       .write          = clps711xuart_console_write,
-       .device         = uart_console_device,
-       .setup          = clps711xuart_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &clps711x_reg,
-};
-
-static int __init clps711xuart_console_init(void)
-{
-       register_console(&clps711x_console);
-       return 0;
-}
-console_initcall(clps711xuart_console_init);
-
-#define CLPS711X_CONSOLE       &clps711x_console
-#else
-#define CLPS711X_CONSOLE       NULL
-#endif
-
-static struct uart_driver clps711x_reg = {
-       .driver_name            = "ttyCL",
-       .dev_name               = "ttyCL",
-       .major                  = SERIAL_CLPS711X_MAJOR,
-       .minor                  = SERIAL_CLPS711X_MINOR,
-       .nr                     = UART_NR,
-
-       .cons                   = CLPS711X_CONSOLE,
-};
-
-static int __init clps711xuart_init(void)
-{
-       int ret, i;
-
-       printk(KERN_INFO "Serial: CLPS711x driver\n");
-
-       ret = uart_register_driver(&clps711x_reg);
-       if (ret)
-               return ret;
-
-       for (i = 0; i < UART_NR; i++)
-               uart_add_one_port(&clps711x_reg, &clps711x_ports[i]);
-
-       return 0;
-}
-
-static void __exit clps711xuart_exit(void)
-{
-       int i;
-
-       for (i = 0; i < UART_NR; i++)
-               uart_remove_one_port(&clps711x_reg, &clps711x_ports[i]);
-
-       uart_unregister_driver(&clps711x_reg);
-}
-
-module_init(clps711xuart_init);
-module_exit(clps711xuart_exit);
-
-MODULE_AUTHOR("Deep Blue Solutions Ltd");
-MODULE_DESCRIPTION("CLPS-711x generic serial driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV(SERIAL_CLPS711X_MAJOR, SERIAL_CLPS711X_MINOR);
diff --git a/drivers/serial/cpm_uart/Makefile b/drivers/serial/cpm_uart/Makefile
deleted file mode 100644 (file)
index e072724..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# Makefile for the Motorola 8xx FEC ethernet controller
-#
-
-obj-$(CONFIG_SERIAL_CPM) += cpm_uart.o
-
-# Select the correct platform objects.
-cpm_uart-objs-$(CONFIG_CPM2)   += cpm_uart_cpm2.o
-cpm_uart-objs-$(CONFIG_8xx)    += cpm_uart_cpm1.o
-
-cpm_uart-objs  := cpm_uart_core.o $(cpm_uart-objs-y)
diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h
deleted file mode 100644 (file)
index b754dcf..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- *  linux/drivers/serial/cpm_uart.h
- *
- *  Driver for CPM (SCC/SMC) serial ports
- *
- *  Copyright (C) 2004 Freescale Semiconductor, Inc.
- *
- *  2006 (c) MontaVista Software, Inc.
- *     Vitaly Bordug <vbordug@ru.mvista.com>
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- *
- */
-#ifndef CPM_UART_H
-#define CPM_UART_H
-
-#include <linux/platform_device.h>
-#include <linux/fs_uart_pd.h>
-
-#if defined(CONFIG_CPM2)
-#include "cpm_uart_cpm2.h"
-#elif defined(CONFIG_8xx)
-#include "cpm_uart_cpm1.h"
-#endif
-
-#define SERIAL_CPM_MAJOR       204
-#define SERIAL_CPM_MINOR       46
-
-#define IS_SMC(pinfo)          (pinfo->flags & FLAG_SMC)
-#define IS_DISCARDING(pinfo)   (pinfo->flags & FLAG_DISCARDING)
-#define FLAG_DISCARDING        0x00000004      /* when set, don't discard */
-#define FLAG_SMC       0x00000002
-#define FLAG_CONSOLE   0x00000001
-
-#define UART_SMC1      fsid_smc1_uart
-#define UART_SMC2      fsid_smc2_uart
-#define UART_SCC1      fsid_scc1_uart
-#define UART_SCC2      fsid_scc2_uart
-#define UART_SCC3      fsid_scc3_uart
-#define UART_SCC4      fsid_scc4_uart
-
-#define UART_NR                fs_uart_nr
-
-#define RX_NUM_FIFO    4
-#define RX_BUF_SIZE    32
-#define TX_NUM_FIFO    4
-#define TX_BUF_SIZE    32
-
-#define SCC_WAIT_CLOSING 100
-
-#define GPIO_CTS       0
-#define GPIO_RTS       1
-#define GPIO_DCD       2
-#define GPIO_DSR       3
-#define GPIO_DTR       4
-#define GPIO_RI                5
-
-#define NUM_GPIOS      (GPIO_RI+1)
-
-struct uart_cpm_port {
-       struct uart_port        port;
-       u16                     rx_nrfifos;
-       u16                     rx_fifosize;
-       u16                     tx_nrfifos;
-       u16                     tx_fifosize;
-       smc_t __iomem           *smcp;
-       smc_uart_t __iomem      *smcup;
-       scc_t __iomem           *sccp;
-       scc_uart_t __iomem      *sccup;
-       cbd_t __iomem           *rx_bd_base;
-       cbd_t __iomem           *rx_cur;
-       cbd_t __iomem           *tx_bd_base;
-       cbd_t __iomem           *tx_cur;
-       unsigned char           *tx_buf;
-       unsigned char           *rx_buf;
-       u32                     flags;
-       struct clk              *clk;
-       u8                      brg;
-       uint                     dp_addr;
-       void                    *mem_addr;
-       dma_addr_t               dma_addr;
-       u32                     mem_size;
-       /* wait on close if needed */
-       int                     wait_closing;
-       /* value to combine with opcode to form cpm command */
-       u32                     command;
-       int                     gpios[NUM_GPIOS];
-};
-
-extern int cpm_uart_nr;
-extern struct uart_cpm_port cpm_uart_ports[UART_NR];
-
-/* these are located in their respective files */
-void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd);
-void __iomem *cpm_uart_map_pram(struct uart_cpm_port *port,
-                               struct device_node *np);
-void cpm_uart_unmap_pram(struct uart_cpm_port *port, void __iomem *pram);
-int cpm_uart_init_portdesc(void);
-int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con);
-void cpm_uart_freebuf(struct uart_cpm_port *pinfo);
-
-void smc1_lineif(struct uart_cpm_port *pinfo);
-void smc2_lineif(struct uart_cpm_port *pinfo);
-void scc1_lineif(struct uart_cpm_port *pinfo);
-void scc2_lineif(struct uart_cpm_port *pinfo);
-void scc3_lineif(struct uart_cpm_port *pinfo);
-void scc4_lineif(struct uart_cpm_port *pinfo);
-
-/*
-   virtual to phys transtalion
-*/
-static inline unsigned long cpu2cpm_addr(void *addr,
-                                         struct uart_cpm_port *pinfo)
-{
-       int offset;
-       u32 val = (u32)addr;
-       u32 mem = (u32)pinfo->mem_addr;
-       /* sane check */
-       if (likely(val >= mem && val < mem + pinfo->mem_size)) {
-               offset = val - mem;
-               return pinfo->dma_addr + offset;
-       }
-       /* something nasty happened */
-       BUG();
-       return 0;
-}
-
-static inline void *cpm2cpu_addr(unsigned long addr,
-                                 struct uart_cpm_port *pinfo)
-{
-       int offset;
-       u32 val = addr;
-       u32 dma = (u32)pinfo->dma_addr;
-       /* sane check */
-       if (likely(val >= dma && val < dma + pinfo->mem_size)) {
-               offset = val - dma;
-               return pinfo->mem_addr + offset;
-       }
-       /* something nasty happened */
-       BUG();
-       return NULL;
-}
-
-
-#endif /* CPM_UART_H */
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
deleted file mode 100644 (file)
index 8692ff9..0000000
+++ /dev/null
@@ -1,1443 +0,0 @@
-/*
- *  linux/drivers/serial/cpm_uart.c
- *
- *  Driver for CPM (SCC/SMC) serial ports; core driver
- *
- *  Based on arch/ppc/cpm2_io/uart.c by Dan Malek
- *  Based on ppc8xx.c by Thomas Gleixner
- *  Based on drivers/serial/amba.c by Russell King
- *
- *  Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2)
- *              Pantelis Antoniou (panto@intracom.gr) (CPM1)
- *
- *  Copyright (C) 2004, 2007 Freescale Semiconductor, Inc.
- *            (C) 2004 Intracom, S.A.
- *            (C) 2005-2006 MontaVista Software, Inc.
- *             Vitaly Bordug <vbordug@ru.mvista.com>
- *
- * 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/module.h>
-#include <linux/tty.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/serial.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/device.h>
-#include <linux/bootmem.h>
-#include <linux/dma-mapping.h>
-#include <linux/fs_uart_pd.h>
-#include <linux/of_platform.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
-#include <linux/clk.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/delay.h>
-#include <asm/fs_pd.h>
-#include <asm/udbg.h>
-
-#if defined(CONFIG_SERIAL_CPM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-#include <linux/kernel.h>
-
-#include "cpm_uart.h"
-
-
-/**************************************************************/
-
-static int  cpm_uart_tx_pump(struct uart_port *port);
-static void cpm_uart_init_smc(struct uart_cpm_port *pinfo);
-static void cpm_uart_init_scc(struct uart_cpm_port *pinfo);
-static void cpm_uart_initbd(struct uart_cpm_port *pinfo);
-
-/**************************************************************/
-
-#define HW_BUF_SPD_THRESHOLD    9600
-
-/*
- * Check, if transmit buffers are processed
-*/
-static unsigned int cpm_uart_tx_empty(struct uart_port *port)
-{
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-       cbd_t __iomem *bdp = pinfo->tx_bd_base;
-       int ret = 0;
-
-       while (1) {
-               if (in_be16(&bdp->cbd_sc) & BD_SC_READY)
-                       break;
-
-               if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) {
-                       ret = TIOCSER_TEMT;
-                       break;
-               }
-               bdp++;
-       }
-
-       pr_debug("CPM uart[%d]:tx_empty: %d\n", port->line, ret);
-
-       return ret;
-}
-
-static void cpm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-
-       if (pinfo->gpios[GPIO_RTS] >= 0)
-               gpio_set_value(pinfo->gpios[GPIO_RTS], !(mctrl & TIOCM_RTS));
-
-       if (pinfo->gpios[GPIO_DTR] >= 0)
-               gpio_set_value(pinfo->gpios[GPIO_DTR], !(mctrl & TIOCM_DTR));
-}
-
-static unsigned int cpm_uart_get_mctrl(struct uart_port *port)
-{
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-       unsigned int mctrl = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
-
-       if (pinfo->gpios[GPIO_CTS] >= 0) {
-               if (gpio_get_value(pinfo->gpios[GPIO_CTS]))
-                       mctrl &= ~TIOCM_CTS;
-       }
-
-       if (pinfo->gpios[GPIO_DSR] >= 0) {
-               if (gpio_get_value(pinfo->gpios[GPIO_DSR]))
-                       mctrl &= ~TIOCM_DSR;
-       }
-
-       if (pinfo->gpios[GPIO_DCD] >= 0) {
-               if (gpio_get_value(pinfo->gpios[GPIO_DCD]))
-                       mctrl &= ~TIOCM_CAR;
-       }
-
-       if (pinfo->gpios[GPIO_RI] >= 0) {
-               if (!gpio_get_value(pinfo->gpios[GPIO_RI]))
-                       mctrl |= TIOCM_RNG;
-       }
-
-       return mctrl;
-}
-
-/*
- * Stop transmitter
- */
-static void cpm_uart_stop_tx(struct uart_port *port)
-{
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-       smc_t __iomem *smcp = pinfo->smcp;
-       scc_t __iomem *sccp = pinfo->sccp;
-
-       pr_debug("CPM uart[%d]:stop tx\n", port->line);
-
-       if (IS_SMC(pinfo))
-               clrbits8(&smcp->smc_smcm, SMCM_TX);
-       else
-               clrbits16(&sccp->scc_sccm, UART_SCCM_TX);
-}
-
-/*
- * Start transmitter
- */
-static void cpm_uart_start_tx(struct uart_port *port)
-{
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-       smc_t __iomem *smcp = pinfo->smcp;
-       scc_t __iomem *sccp = pinfo->sccp;
-
-       pr_debug("CPM uart[%d]:start tx\n", port->line);
-
-       if (IS_SMC(pinfo)) {
-               if (in_8(&smcp->smc_smcm) & SMCM_TX)
-                       return;
-       } else {
-               if (in_be16(&sccp->scc_sccm) & UART_SCCM_TX)
-                       return;
-       }
-
-       if (cpm_uart_tx_pump(port) != 0) {
-               if (IS_SMC(pinfo)) {
-                       setbits8(&smcp->smc_smcm, SMCM_TX);
-               } else {
-                       setbits16(&sccp->scc_sccm, UART_SCCM_TX);
-               }
-       }
-}
-
-/*
- * Stop receiver
- */
-static void cpm_uart_stop_rx(struct uart_port *port)
-{
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-       smc_t __iomem *smcp = pinfo->smcp;
-       scc_t __iomem *sccp = pinfo->sccp;
-
-       pr_debug("CPM uart[%d]:stop rx\n", port->line);
-
-       if (IS_SMC(pinfo))
-               clrbits8(&smcp->smc_smcm, SMCM_RX);
-       else
-               clrbits16(&sccp->scc_sccm, UART_SCCM_RX);
-}
-
-/*
- * Enable Modem status interrupts
- */
-static void cpm_uart_enable_ms(struct uart_port *port)
-{
-       pr_debug("CPM uart[%d]:enable ms\n", port->line);
-}
-
-/*
- * Generate a break.
- */
-static void cpm_uart_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-
-       pr_debug("CPM uart[%d]:break ctrl, break_state: %d\n", port->line,
-               break_state);
-
-       if (break_state)
-               cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX);
-       else
-               cpm_line_cr_cmd(pinfo, CPM_CR_RESTART_TX);
-}
-
-/*
- * Transmit characters, refill buffer descriptor, if possible
- */
-static void cpm_uart_int_tx(struct uart_port *port)
-{
-       pr_debug("CPM uart[%d]:TX INT\n", port->line);
-
-       cpm_uart_tx_pump(port);
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-static int serial_polled;
-#endif
-
-/*
- * Receive characters
- */
-static void cpm_uart_int_rx(struct uart_port *port)
-{
-       int i;
-       unsigned char ch;
-       u8 *cp;
-       struct tty_struct *tty = port->state->port.tty;
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-       cbd_t __iomem *bdp;
-       u16 status;
-       unsigned int flg;
-
-       pr_debug("CPM uart[%d]:RX INT\n", port->line);
-
-       /* Just loop through the closed BDs and copy the characters into
-        * the buffer.
-        */
-       bdp = pinfo->rx_cur;
-       for (;;) {
-#ifdef CONFIG_CONSOLE_POLL
-               if (unlikely(serial_polled)) {
-                       serial_polled = 0;
-                       return;
-               }
-#endif
-               /* get status */
-               status = in_be16(&bdp->cbd_sc);
-               /* If this one is empty, return happy */
-               if (status & BD_SC_EMPTY)
-                       break;
-
-               /* get number of characters, and check spce in flip-buffer */
-               i = in_be16(&bdp->cbd_datlen);
-
-               /* If we have not enough room in tty flip buffer, then we try
-                * later, which will be the next rx-interrupt or a timeout
-                */
-               if(tty_buffer_request_room(tty, i) < i) {
-                       printk(KERN_WARNING "No room in flip buffer\n");
-                       return;
-               }
-
-               /* get pointer */
-               cp = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
-
-               /* loop through the buffer */
-               while (i-- > 0) {
-                       ch = *cp++;
-                       port->icount.rx++;
-                       flg = TTY_NORMAL;
-
-                       if (status &
-                           (BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV))
-                               goto handle_error;
-                       if (uart_handle_sysrq_char(port, ch))
-                               continue;
-#ifdef CONFIG_CONSOLE_POLL
-                       if (unlikely(serial_polled)) {
-                               serial_polled = 0;
-                               return;
-                       }
-#endif
-                     error_return:
-                       tty_insert_flip_char(tty, ch, flg);
-
-               }               /* End while (i--) */
-
-               /* This BD is ready to be used again. Clear status. get next */
-               clrbits16(&bdp->cbd_sc, BD_SC_BR | BD_SC_FR | BD_SC_PR |
-                                       BD_SC_OV | BD_SC_ID);
-               setbits16(&bdp->cbd_sc, BD_SC_EMPTY);
-
-               if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
-                       bdp = pinfo->rx_bd_base;
-               else
-                       bdp++;
-
-       } /* End for (;;) */
-
-       /* Write back buffer pointer */
-       pinfo->rx_cur = bdp;
-
-       /* activate BH processing */
-       tty_flip_buffer_push(tty);
-
-       return;
-
-       /* Error processing */
-
-      handle_error:
-       /* Statistics */
-       if (status & BD_SC_BR)
-               port->icount.brk++;
-       if (status & BD_SC_PR)
-               port->icount.parity++;
-       if (status & BD_SC_FR)
-               port->icount.frame++;
-       if (status & BD_SC_OV)
-               port->icount.overrun++;
-
-       /* Mask out ignored conditions */
-       status &= port->read_status_mask;
-
-       /* Handle the remaining ones */
-       if (status & BD_SC_BR)
-               flg = TTY_BREAK;
-       else if (status & BD_SC_PR)
-               flg = TTY_PARITY;
-       else if (status & BD_SC_FR)
-               flg = TTY_FRAME;
-
-       /* overrun does not affect the current character ! */
-       if (status & BD_SC_OV) {
-               ch = 0;
-               flg = TTY_OVERRUN;
-               /* We skip this buffer */
-               /* CHECK: Is really nothing senseful there */
-               /* ASSUMPTION: it contains nothing valid */
-               i = 0;
-       }
-#ifdef SUPPORT_SYSRQ
-       port->sysrq = 0;
-#endif
-       goto error_return;
-}
-
-/*
- * Asynchron mode interrupt handler
- */
-static irqreturn_t cpm_uart_int(int irq, void *data)
-{
-       u8 events;
-       struct uart_port *port = data;
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-       smc_t __iomem *smcp = pinfo->smcp;
-       scc_t __iomem *sccp = pinfo->sccp;
-
-       pr_debug("CPM uart[%d]:IRQ\n", port->line);
-
-       if (IS_SMC(pinfo)) {
-               events = in_8(&smcp->smc_smce);
-               out_8(&smcp->smc_smce, events);
-               if (events & SMCM_BRKE)
-                       uart_handle_break(port);
-               if (events & SMCM_RX)
-                       cpm_uart_int_rx(port);
-               if (events & SMCM_TX)
-                       cpm_uart_int_tx(port);
-       } else {
-               events = in_be16(&sccp->scc_scce);
-               out_be16(&sccp->scc_scce, events);
-               if (events & UART_SCCM_BRKE)
-                       uart_handle_break(port);
-               if (events & UART_SCCM_RX)
-                       cpm_uart_int_rx(port);
-               if (events & UART_SCCM_TX)
-                       cpm_uart_int_tx(port);
-       }
-       return (events) ? IRQ_HANDLED : IRQ_NONE;
-}
-
-static int cpm_uart_startup(struct uart_port *port)
-{
-       int retval;
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-
-       pr_debug("CPM uart[%d]:startup\n", port->line);
-
-       /* If the port is not the console, make sure rx is disabled. */
-       if (!(pinfo->flags & FLAG_CONSOLE)) {
-               /* Disable UART rx */
-               if (IS_SMC(pinfo)) {
-                       clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN);
-                       clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX);
-               } else {
-                       clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR);
-                       clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_RX);
-               }
-               cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
-       }
-       /* Install interrupt handler. */
-       retval = request_irq(port->irq, cpm_uart_int, 0, "cpm_uart", port);
-       if (retval)
-               return retval;
-
-       /* Startup rx-int */
-       if (IS_SMC(pinfo)) {
-               setbits8(&pinfo->smcp->smc_smcm, SMCM_RX);
-               setbits16(&pinfo->smcp->smc_smcmr, (SMCMR_REN | SMCMR_TEN));
-       } else {
-               setbits16(&pinfo->sccp->scc_sccm, UART_SCCM_RX);
-               setbits32(&pinfo->sccp->scc_gsmrl, (SCC_GSMRL_ENR | SCC_GSMRL_ENT));
-       }
-
-       return 0;
-}
-
-inline void cpm_uart_wait_until_send(struct uart_cpm_port *pinfo)
-{
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       schedule_timeout(pinfo->wait_closing);
-}
-
-/*
- * Shutdown the uart
- */
-static void cpm_uart_shutdown(struct uart_port *port)
-{
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-
-       pr_debug("CPM uart[%d]:shutdown\n", port->line);
-
-       /* free interrupt handler */
-       free_irq(port->irq, port);
-
-       /* If the port is not the console, disable Rx and Tx. */
-       if (!(pinfo->flags & FLAG_CONSOLE)) {
-               /* Wait for all the BDs marked sent */
-               while(!cpm_uart_tx_empty(port)) {
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       schedule_timeout(2);
-               }
-
-               if (pinfo->wait_closing)
-                       cpm_uart_wait_until_send(pinfo);
-
-               /* Stop uarts */
-               if (IS_SMC(pinfo)) {
-                       smc_t __iomem *smcp = pinfo->smcp;
-                       clrbits16(&smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
-                       clrbits8(&smcp->smc_smcm, SMCM_RX | SMCM_TX);
-               } else {
-                       scc_t __iomem *sccp = pinfo->sccp;
-                       clrbits32(&sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-                       clrbits16(&sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX);
-               }
-
-               /* Shut them really down and reinit buffer descriptors */
-               if (IS_SMC(pinfo)) {
-                       out_be16(&pinfo->smcup->smc_brkcr, 0);
-                       cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX);
-               } else {
-                       out_be16(&pinfo->sccup->scc_brkcr, 0);
-                       cpm_line_cr_cmd(pinfo, CPM_CR_GRA_STOP_TX);
-               }
-
-               cpm_uart_initbd(pinfo);
-       }
-}
-
-static void cpm_uart_set_termios(struct uart_port *port,
-                                 struct ktermios *termios,
-                                 struct ktermios *old)
-{
-       int baud;
-       unsigned long flags;
-       u16 cval, scval, prev_mode;
-       int bits, sbits;
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-       smc_t __iomem *smcp = pinfo->smcp;
-       scc_t __iomem *sccp = pinfo->sccp;
-
-       pr_debug("CPM uart[%d]:set_termios\n", port->line);
-
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
-       if (baud <= HW_BUF_SPD_THRESHOLD ||
-           (pinfo->port.state && pinfo->port.state->port.tty->low_latency))
-               pinfo->rx_fifosize = 1;
-       else
-               pinfo->rx_fifosize = RX_BUF_SIZE;
-
-       /* Character length programmed into the mode register is the
-        * sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
-        * 1 or 2 stop bits, minus 1.
-        * The value 'bits' counts this for us.
-        */
-       cval = 0;
-       scval = 0;
-
-       /* byte size */
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               bits = 5;
-               break;
-       case CS6:
-               bits = 6;
-               break;
-       case CS7:
-               bits = 7;
-               break;
-       case CS8:
-               bits = 8;
-               break;
-               /* Never happens, but GCC is too dumb to figure it out */
-       default:
-               bits = 8;
-               break;
-       }
-       sbits = bits - 5;
-
-       if (termios->c_cflag & CSTOPB) {
-               cval |= SMCMR_SL;       /* Two stops */
-               scval |= SCU_PSMR_SL;
-               bits++;
-       }
-
-       if (termios->c_cflag & PARENB) {
-               cval |= SMCMR_PEN;
-               scval |= SCU_PSMR_PEN;
-               bits++;
-               if (!(termios->c_cflag & PARODD)) {
-                       cval |= SMCMR_PM_EVEN;
-                       scval |= (SCU_PSMR_REVP | SCU_PSMR_TEVP);
-               }
-       }
-
-       /*
-        * Update the timeout
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       /*
-        * Set up parity check flag
-        */
-#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
-       port->read_status_mask = (BD_SC_EMPTY | BD_SC_OV);
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= BD_SC_FR | BD_SC_PR;
-       if ((termios->c_iflag & BRKINT) || (termios->c_iflag & PARMRK))
-               port->read_status_mask |= BD_SC_BR;
-
-       /*
-        * Characters to ignore
-        */
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= BD_SC_PR | BD_SC_FR;
-       if (termios->c_iflag & IGNBRK) {
-               port->ignore_status_mask |= BD_SC_BR;
-               /*
-                * If we're ignore parity and break indicators, ignore
-                * overruns too.  (For real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       port->ignore_status_mask |= BD_SC_OV;
-       }
-       /*
-        * !!! ignore all characters if CREAD is not set
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               port->read_status_mask &= ~BD_SC_EMPTY;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /* Start bit has not been added (so don't, because we would just
-        * subtract it later), and we need to add one for the number of
-        * stops bits (there is always at least one).
-        */
-       bits++;
-       if (IS_SMC(pinfo)) {
-               /*
-                * MRBLR can be changed while an SMC/SCC is operating only
-                * if it is done in a single bus cycle with one 16-bit move
-                * (not two 8-bit bus cycles back-to-back). This occurs when
-                * the cp shifts control to the next RxBD, so the change does
-                * not take effect immediately. To guarantee the exact RxBD
-                * on which the change occurs, change MRBLR only while the
-                * SMC/SCC receiver is disabled.
-                */
-               out_be16(&pinfo->smcup->smc_mrblr, pinfo->rx_fifosize);
-
-               /* Set the mode register.  We want to keep a copy of the
-                * enables, because we want to put them back if they were
-                * present.
-                */
-               prev_mode = in_be16(&smcp->smc_smcmr) & (SMCMR_REN | SMCMR_TEN);
-               /* Output in *one* operation, so we don't interrupt RX/TX if they
-                * were already enabled. */
-               out_be16(&smcp->smc_smcmr, smcr_mk_clen(bits) | cval |
-                   SMCMR_SM_UART | prev_mode);
-       } else {
-               out_be16(&pinfo->sccup->scc_genscc.scc_mrblr, pinfo->rx_fifosize);
-               out_be16(&sccp->scc_psmr, (sbits << 12) | scval);
-       }
-
-       if (pinfo->clk)
-               clk_set_rate(pinfo->clk, baud);
-       else
-               cpm_set_brg(pinfo->brg - 1, baud);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *cpm_uart_type(struct uart_port *port)
-{
-       pr_debug("CPM uart[%d]:uart_type\n", port->line);
-
-       return port->type == PORT_CPM ? "CPM UART" : NULL;
-}
-
-/*
- * verify the new serial_struct (for TIOCSSERIAL).
- */
-static int cpm_uart_verify_port(struct uart_port *port,
-                               struct serial_struct *ser)
-{
-       int ret = 0;
-
-       pr_debug("CPM uart[%d]:verify_port\n", port->line);
-
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_CPM)
-               ret = -EINVAL;
-       if (ser->irq < 0 || ser->irq >= nr_irqs)
-               ret = -EINVAL;
-       if (ser->baud_base < 9600)
-               ret = -EINVAL;
-       return ret;
-}
-
-/*
- * Transmit characters, refill buffer descriptor, if possible
- */
-static int cpm_uart_tx_pump(struct uart_port *port)
-{
-       cbd_t __iomem *bdp;
-       u8 *p;
-       int count;
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-       struct circ_buf *xmit = &port->state->xmit;
-
-       /* Handle xon/xoff */
-       if (port->x_char) {
-               /* Pick next descriptor and fill from buffer */
-               bdp = pinfo->tx_cur;
-
-               p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
-
-               *p++ = port->x_char;
-
-               out_be16(&bdp->cbd_datlen, 1);
-               setbits16(&bdp->cbd_sc, BD_SC_READY);
-               /* Get next BD. */
-               if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
-                       bdp = pinfo->tx_bd_base;
-               else
-                       bdp++;
-               pinfo->tx_cur = bdp;
-
-               port->icount.tx++;
-               port->x_char = 0;
-               return 1;
-       }
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               cpm_uart_stop_tx(port);
-               return 0;
-       }
-
-       /* Pick next descriptor and fill from buffer */
-       bdp = pinfo->tx_cur;
-
-       while (!(in_be16(&bdp->cbd_sc) & BD_SC_READY) &&
-              xmit->tail != xmit->head) {
-               count = 0;
-               p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
-               while (count < pinfo->tx_fifosize) {
-                       *p++ = xmit->buf[xmit->tail];
-                       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-                       port->icount.tx++;
-                       count++;
-                       if (xmit->head == xmit->tail)
-                               break;
-               }
-               out_be16(&bdp->cbd_datlen, count);
-               setbits16(&bdp->cbd_sc, BD_SC_READY);
-               /* Get next BD. */
-               if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
-                       bdp = pinfo->tx_bd_base;
-               else
-                       bdp++;
-       }
-       pinfo->tx_cur = bdp;
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (uart_circ_empty(xmit)) {
-               cpm_uart_stop_tx(port);
-               return 0;
-       }
-
-       return 1;
-}
-
-/*
- * init buffer descriptors
- */
-static void cpm_uart_initbd(struct uart_cpm_port *pinfo)
-{
-       int i;
-       u8 *mem_addr;
-       cbd_t __iomem *bdp;
-
-       pr_debug("CPM uart[%d]:initbd\n", pinfo->port.line);
-
-       /* Set the physical address of the host memory
-        * buffers in the buffer descriptors, and the
-        * virtual address for us to work with.
-        */
-       mem_addr = pinfo->mem_addr;
-       bdp = pinfo->rx_cur = pinfo->rx_bd_base;
-       for (i = 0; i < (pinfo->rx_nrfifos - 1); i++, bdp++) {
-               out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
-               out_be16(&bdp->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT);
-               mem_addr += pinfo->rx_fifosize;
-       }
-
-       out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
-       out_be16(&bdp->cbd_sc, BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT);
-
-       /* Set the physical address of the host memory
-        * buffers in the buffer descriptors, and the
-        * virtual address for us to work with.
-        */
-       mem_addr = pinfo->mem_addr + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize);
-       bdp = pinfo->tx_cur = pinfo->tx_bd_base;
-       for (i = 0; i < (pinfo->tx_nrfifos - 1); i++, bdp++) {
-               out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
-               out_be16(&bdp->cbd_sc, BD_SC_INTRPT);
-               mem_addr += pinfo->tx_fifosize;
-       }
-
-       out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
-       out_be16(&bdp->cbd_sc, BD_SC_WRAP | BD_SC_INTRPT);
-}
-
-static void cpm_uart_init_scc(struct uart_cpm_port *pinfo)
-{
-       scc_t __iomem *scp;
-       scc_uart_t __iomem *sup;
-
-       pr_debug("CPM uart[%d]:init_scc\n", pinfo->port.line);
-
-       scp = pinfo->sccp;
-       sup = pinfo->sccup;
-
-       /* Store address */
-       out_be16(&pinfo->sccup->scc_genscc.scc_rbase,
-                (u8 __iomem *)pinfo->rx_bd_base - DPRAM_BASE);
-       out_be16(&pinfo->sccup->scc_genscc.scc_tbase,
-                (u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE);
-
-       /* Set up the uart parameters in the
-        * parameter ram.
-        */
-
-       cpm_set_scc_fcr(sup);
-
-       out_be16(&sup->scc_genscc.scc_mrblr, pinfo->rx_fifosize);
-       out_be16(&sup->scc_maxidl, pinfo->rx_fifosize);
-       out_be16(&sup->scc_brkcr, 1);
-       out_be16(&sup->scc_parec, 0);
-       out_be16(&sup->scc_frmec, 0);
-       out_be16(&sup->scc_nosec, 0);
-       out_be16(&sup->scc_brkec, 0);
-       out_be16(&sup->scc_uaddr1, 0);
-       out_be16(&sup->scc_uaddr2, 0);
-       out_be16(&sup->scc_toseq, 0);
-       out_be16(&sup->scc_char1, 0x8000);
-       out_be16(&sup->scc_char2, 0x8000);
-       out_be16(&sup->scc_char3, 0x8000);
-       out_be16(&sup->scc_char4, 0x8000);
-       out_be16(&sup->scc_char5, 0x8000);
-       out_be16(&sup->scc_char6, 0x8000);
-       out_be16(&sup->scc_char7, 0x8000);
-       out_be16(&sup->scc_char8, 0x8000);
-       out_be16(&sup->scc_rccm, 0xc0ff);
-
-       /* Send the CPM an initialize command.
-        */
-       cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
-
-       /* Set UART mode, 8 bit, no parity, one stop.
-        * Enable receive and transmit.
-        */
-       out_be32(&scp->scc_gsmrh, 0);
-       out_be32(&scp->scc_gsmrl,
-                SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
-
-       /* Enable rx interrupts  and clear all pending events.  */
-       out_be16(&scp->scc_sccm, 0);
-       out_be16(&scp->scc_scce, 0xffff);
-       out_be16(&scp->scc_dsr, 0x7e7e);
-       out_be16(&scp->scc_psmr, 0x3000);
-
-       setbits32(&scp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-}
-
-static void cpm_uart_init_smc(struct uart_cpm_port *pinfo)
-{
-       smc_t __iomem *sp;
-       smc_uart_t __iomem *up;
-
-       pr_debug("CPM uart[%d]:init_smc\n", pinfo->port.line);
-
-       sp = pinfo->smcp;
-       up = pinfo->smcup;
-
-       /* Store address */
-       out_be16(&pinfo->smcup->smc_rbase,
-                (u8 __iomem *)pinfo->rx_bd_base - DPRAM_BASE);
-       out_be16(&pinfo->smcup->smc_tbase,
-                (u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE);
-
-/*
- *  In case SMC1 is being relocated...
- */
-#if defined (CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
-       out_be16(&up->smc_rbptr, in_be16(&pinfo->smcup->smc_rbase));
-       out_be16(&up->smc_tbptr, in_be16(&pinfo->smcup->smc_tbase));
-       out_be32(&up->smc_rstate, 0);
-       out_be32(&up->smc_tstate, 0);
-       out_be16(&up->smc_brkcr, 1);              /* number of break chars */
-       out_be16(&up->smc_brkec, 0);
-#endif
-
-       /* Set up the uart parameters in the
-        * parameter ram.
-        */
-       cpm_set_smc_fcr(up);
-
-       /* Using idle character time requires some additional tuning.  */
-       out_be16(&up->smc_mrblr, pinfo->rx_fifosize);
-       out_be16(&up->smc_maxidl, pinfo->rx_fifosize);
-       out_be16(&up->smc_brklen, 0);
-       out_be16(&up->smc_brkec, 0);
-       out_be16(&up->smc_brkcr, 1);
-
-       cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
-
-       /* Set UART mode, 8 bit, no parity, one stop.
-        * Enable receive and transmit.
-        */
-       out_be16(&sp->smc_smcmr, smcr_mk_clen(9) | SMCMR_SM_UART);
-
-       /* Enable only rx interrupts clear all pending events. */
-       out_8(&sp->smc_smcm, 0);
-       out_8(&sp->smc_smce, 0xff);
-
-       setbits16(&sp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
-}
-
-/*
- * Initialize port. This is called from early_console stuff
- * so we have to be careful here !
- */
-static int cpm_uart_request_port(struct uart_port *port)
-{
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-       int ret;
-
-       pr_debug("CPM uart[%d]:request port\n", port->line);
-
-       if (pinfo->flags & FLAG_CONSOLE)
-               return 0;
-
-       if (IS_SMC(pinfo)) {
-               clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX | SMCM_TX);
-               clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
-       } else {
-               clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX);
-               clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-       }
-
-       ret = cpm_uart_allocbuf(pinfo, 0);
-
-       if (ret)
-               return ret;
-
-       cpm_uart_initbd(pinfo);
-       if (IS_SMC(pinfo))
-               cpm_uart_init_smc(pinfo);
-       else
-               cpm_uart_init_scc(pinfo);
-
-       return 0;
-}
-
-static void cpm_uart_release_port(struct uart_port *port)
-{
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-
-       if (!(pinfo->flags & FLAG_CONSOLE))
-               cpm_uart_freebuf(pinfo);
-}
-
-/*
- * Configure/autoconfigure the port.
- */
-static void cpm_uart_config_port(struct uart_port *port, int flags)
-{
-       pr_debug("CPM uart[%d]:config_port\n", port->line);
-
-       if (flags & UART_CONFIG_TYPE) {
-               port->type = PORT_CPM;
-               cpm_uart_request_port(port);
-       }
-}
-
-#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_CPM_CONSOLE)
-/*
- * Write a string to the serial port
- * Note that this is called with interrupts already disabled
- */
-static void cpm_uart_early_write(struct uart_cpm_port *pinfo,
-               const char *string, u_int count)
-{
-       unsigned int i;
-       cbd_t __iomem *bdp, *bdbase;
-       unsigned char *cpm_outp_addr;
-
-       /* Get the address of the host memory buffer.
-        */
-       bdp = pinfo->tx_cur;
-       bdbase = pinfo->tx_bd_base;
-
-       /*
-        * Now, do each character.  This is not as bad as it looks
-        * since this is a holding FIFO and not a transmitting FIFO.
-        * We could add the complexity of filling the entire transmit
-        * buffer, but we would just wait longer between accesses......
-        */
-       for (i = 0; i < count; i++, string++) {
-               /* Wait for transmitter fifo to empty.
-                * Ready indicates output is ready, and xmt is doing
-                * that, not that it is ready for us to send.
-                */
-               while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0)
-                       ;
-
-               /* Send the character out.
-                * If the buffer address is in the CPM DPRAM, don't
-                * convert it.
-                */
-               cpm_outp_addr = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr),
-                                       pinfo);
-               *cpm_outp_addr = *string;
-
-               out_be16(&bdp->cbd_datlen, 1);
-               setbits16(&bdp->cbd_sc, BD_SC_READY);
-
-               if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
-                       bdp = bdbase;
-               else
-                       bdp++;
-
-               /* if a LF, also do CR... */
-               if (*string == 10) {
-                       while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0)
-                               ;
-
-                       cpm_outp_addr = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr),
-                                               pinfo);
-                       *cpm_outp_addr = 13;
-
-                       out_be16(&bdp->cbd_datlen, 1);
-                       setbits16(&bdp->cbd_sc, BD_SC_READY);
-
-                       if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
-                               bdp = bdbase;
-                       else
-                               bdp++;
-               }
-       }
-
-       /*
-        * Finally, Wait for transmitter & holding register to empty
-        *  and restore the IER
-        */
-       while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0)
-               ;
-
-       pinfo->tx_cur = bdp;
-}
-#endif
-
-#ifdef CONFIG_CONSOLE_POLL
-/* Serial polling routines for writing and reading from the uart while
- * in an interrupt or debug context.
- */
-
-#define GDB_BUF_SIZE   512     /* power of 2, please */
-
-static char poll_buf[GDB_BUF_SIZE];
-static char *pollp;
-static int poll_chars;
-
-static int poll_wait_key(char *obuf, struct uart_cpm_port *pinfo)
-{
-       u_char          c, *cp;
-       volatile cbd_t  *bdp;
-       int             i;
-
-       /* Get the address of the host memory buffer.
-        */
-       bdp = pinfo->rx_cur;
-       while (bdp->cbd_sc & BD_SC_EMPTY)
-               ;
-
-       /* If the buffer address is in the CPM DPRAM, don't
-        * convert it.
-        */
-       cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
-
-       if (obuf) {
-               i = c = bdp->cbd_datlen;
-               while (i-- > 0)
-                       *obuf++ = *cp++;
-       } else
-               c = *cp;
-       bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV | BD_SC_ID);
-       bdp->cbd_sc |= BD_SC_EMPTY;
-
-       if (bdp->cbd_sc & BD_SC_WRAP)
-               bdp = pinfo->rx_bd_base;
-       else
-               bdp++;
-       pinfo->rx_cur = (cbd_t *)bdp;
-
-       return (int)c;
-}
-
-static int cpm_get_poll_char(struct uart_port *port)
-{
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-
-       if (!serial_polled) {
-               serial_polled = 1;
-               poll_chars = 0;
-       }
-       if (poll_chars <= 0) {
-               poll_chars = poll_wait_key(poll_buf, pinfo);
-               pollp = poll_buf;
-       }
-       poll_chars--;
-       return *pollp++;
-}
-
-static void cpm_put_poll_char(struct uart_port *port,
-                        unsigned char c)
-{
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-       static char ch[2];
-
-       ch[0] = (char)c;
-       cpm_uart_early_write(pinfo, ch, 1);
-}
-#endif /* CONFIG_CONSOLE_POLL */
-
-static struct uart_ops cpm_uart_pops = {
-       .tx_empty       = cpm_uart_tx_empty,
-       .set_mctrl      = cpm_uart_set_mctrl,
-       .get_mctrl      = cpm_uart_get_mctrl,
-       .stop_tx        = cpm_uart_stop_tx,
-       .start_tx       = cpm_uart_start_tx,
-       .stop_rx        = cpm_uart_stop_rx,
-       .enable_ms      = cpm_uart_enable_ms,
-       .break_ctl      = cpm_uart_break_ctl,
-       .startup        = cpm_uart_startup,
-       .shutdown       = cpm_uart_shutdown,
-       .set_termios    = cpm_uart_set_termios,
-       .type           = cpm_uart_type,
-       .release_port   = cpm_uart_release_port,
-       .request_port   = cpm_uart_request_port,
-       .config_port    = cpm_uart_config_port,
-       .verify_port    = cpm_uart_verify_port,
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_get_char = cpm_get_poll_char,
-       .poll_put_char = cpm_put_poll_char,
-#endif
-};
-
-struct uart_cpm_port cpm_uart_ports[UART_NR];
-
-static int cpm_uart_init_port(struct device_node *np,
-                              struct uart_cpm_port *pinfo)
-{
-       const u32 *data;
-       void __iomem *mem, *pram;
-       int len;
-       int ret;
-       int i;
-
-       data = of_get_property(np, "clock", NULL);
-       if (data) {
-               struct clk *clk = clk_get(NULL, (const char*)data);
-               if (!IS_ERR(clk))
-                       pinfo->clk = clk;
-       }
-       if (!pinfo->clk) {
-               data = of_get_property(np, "fsl,cpm-brg", &len);
-               if (!data || len != 4) {
-                       printk(KERN_ERR "CPM UART %s has no/invalid "
-                                       "fsl,cpm-brg property.\n", np->name);
-                       return -EINVAL;
-               }
-               pinfo->brg = *data;
-       }
-
-       data = of_get_property(np, "fsl,cpm-command", &len);
-       if (!data || len != 4) {
-               printk(KERN_ERR "CPM UART %s has no/invalid "
-                               "fsl,cpm-command property.\n", np->name);
-               return -EINVAL;
-       }
-       pinfo->command = *data;
-
-       mem = of_iomap(np, 0);
-       if (!mem)
-               return -ENOMEM;
-
-       if (of_device_is_compatible(np, "fsl,cpm1-scc-uart") ||
-           of_device_is_compatible(np, "fsl,cpm2-scc-uart")) {
-               pinfo->sccp = mem;
-               pinfo->sccup = pram = cpm_uart_map_pram(pinfo, np);
-       } else if (of_device_is_compatible(np, "fsl,cpm1-smc-uart") ||
-                  of_device_is_compatible(np, "fsl,cpm2-smc-uart")) {
-               pinfo->flags |= FLAG_SMC;
-               pinfo->smcp = mem;
-               pinfo->smcup = pram = cpm_uart_map_pram(pinfo, np);
-       } else {
-               ret = -ENODEV;
-               goto out_mem;
-       }
-
-       if (!pram) {
-               ret = -ENOMEM;
-               goto out_mem;
-       }
-
-       pinfo->tx_nrfifos = TX_NUM_FIFO;
-       pinfo->tx_fifosize = TX_BUF_SIZE;
-       pinfo->rx_nrfifos = RX_NUM_FIFO;
-       pinfo->rx_fifosize = RX_BUF_SIZE;
-
-       pinfo->port.uartclk = ppc_proc_freq;
-       pinfo->port.mapbase = (unsigned long)mem;
-       pinfo->port.type = PORT_CPM;
-       pinfo->port.ops = &cpm_uart_pops,
-       pinfo->port.iotype = UPIO_MEM;
-       pinfo->port.fifosize = pinfo->tx_nrfifos * pinfo->tx_fifosize;
-       spin_lock_init(&pinfo->port.lock);
-
-       pinfo->port.irq = of_irq_to_resource(np, 0, NULL);
-       if (pinfo->port.irq == NO_IRQ) {
-               ret = -EINVAL;
-               goto out_pram;
-       }
-
-       for (i = 0; i < NUM_GPIOS; i++)
-               pinfo->gpios[i] = of_get_gpio(np, i);
-
-#ifdef CONFIG_PPC_EARLY_DEBUG_CPM
-       udbg_putc = NULL;
-#endif
-
-       return cpm_uart_request_port(&pinfo->port);
-
-out_pram:
-       cpm_uart_unmap_pram(pinfo, pram);
-out_mem:
-       iounmap(mem);
-       return ret;
-}
-
-#ifdef CONFIG_SERIAL_CPM_CONSOLE
-/*
- *     Print a string to the serial port trying not to disturb
- *     any possible real use of the port...
- *
- *     Note that this is called with interrupts already disabled
- */
-static void cpm_uart_console_write(struct console *co, const char *s,
-                                  u_int count)
-{
-       struct uart_cpm_port *pinfo = &cpm_uart_ports[co->index];
-       unsigned long flags;
-       int nolock = oops_in_progress;
-
-       if (unlikely(nolock)) {
-               local_irq_save(flags);
-       } else {
-               spin_lock_irqsave(&pinfo->port.lock, flags);
-       }
-
-       cpm_uart_early_write(pinfo, s, count);
-
-       if (unlikely(nolock)) {
-               local_irq_restore(flags);
-       } else {
-               spin_unlock_irqrestore(&pinfo->port.lock, flags);
-       }
-}
-
-
-static int __init cpm_uart_console_setup(struct console *co, char *options)
-{
-       int baud = 38400;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-       int ret;
-       struct uart_cpm_port *pinfo;
-       struct uart_port *port;
-
-       struct device_node *np = NULL;
-       int i = 0;
-
-       if (co->index >= UART_NR) {
-               printk(KERN_ERR "cpm_uart: console index %d too high\n",
-                      co->index);
-               return -ENODEV;
-       }
-
-       do {
-               np = of_find_node_by_type(np, "serial");
-               if (!np)
-                       return -ENODEV;
-
-               if (!of_device_is_compatible(np, "fsl,cpm1-smc-uart") &&
-                   !of_device_is_compatible(np, "fsl,cpm1-scc-uart") &&
-                   !of_device_is_compatible(np, "fsl,cpm2-smc-uart") &&
-                   !of_device_is_compatible(np, "fsl,cpm2-scc-uart"))
-                       i--;
-       } while (i++ != co->index);
-
-       pinfo = &cpm_uart_ports[co->index];
-
-       pinfo->flags |= FLAG_CONSOLE;
-       port = &pinfo->port;
-
-       ret = cpm_uart_init_port(np, pinfo);
-       of_node_put(np);
-       if (ret)
-               return ret;
-
-       if (options) {
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       } else {
-               if ((baud = uart_baudrate()) == -1)
-                       baud = 9600;
-       }
-
-       if (IS_SMC(pinfo)) {
-               out_be16(&pinfo->smcup->smc_brkcr, 0);
-               cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX);
-               clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX | SMCM_TX);
-               clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
-       } else {
-               out_be16(&pinfo->sccup->scc_brkcr, 0);
-               cpm_line_cr_cmd(pinfo, CPM_CR_GRA_STOP_TX);
-               clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX);
-               clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-       }
-
-       ret = cpm_uart_allocbuf(pinfo, 1);
-
-       if (ret)
-               return ret;
-
-       cpm_uart_initbd(pinfo);
-
-       if (IS_SMC(pinfo))
-               cpm_uart_init_smc(pinfo);
-       else
-               cpm_uart_init_scc(pinfo);
-
-       uart_set_options(port, co, baud, parity, bits, flow);
-       cpm_line_cr_cmd(pinfo, CPM_CR_RESTART_TX);
-
-       return 0;
-}
-
-static struct uart_driver cpm_reg;
-static struct console cpm_scc_uart_console = {
-       .name           = "ttyCPM",
-       .write          = cpm_uart_console_write,
-       .device         = uart_console_device,
-       .setup          = cpm_uart_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &cpm_reg,
-};
-
-static int __init cpm_uart_console_init(void)
-{
-       register_console(&cpm_scc_uart_console);
-       return 0;
-}
-
-console_initcall(cpm_uart_console_init);
-
-#define CPM_UART_CONSOLE       &cpm_scc_uart_console
-#else
-#define CPM_UART_CONSOLE       NULL
-#endif
-
-static struct uart_driver cpm_reg = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "ttyCPM",
-       .dev_name       = "ttyCPM",
-       .major          = SERIAL_CPM_MAJOR,
-       .minor          = SERIAL_CPM_MINOR,
-       .cons           = CPM_UART_CONSOLE,
-       .nr             = UART_NR,
-};
-
-static int probe_index;
-
-static int __devinit cpm_uart_probe(struct platform_device *ofdev,
-                                    const struct of_device_id *match)
-{
-       int index = probe_index++;
-       struct uart_cpm_port *pinfo = &cpm_uart_ports[index];
-       int ret;
-
-       pinfo->port.line = index;
-
-       if (index >= UART_NR)
-               return -ENODEV;
-
-       dev_set_drvdata(&ofdev->dev, pinfo);
-
-       /* initialize the device pointer for the port */
-       pinfo->port.dev = &ofdev->dev;
-
-       ret = cpm_uart_init_port(ofdev->dev.of_node, pinfo);
-       if (ret)
-               return ret;
-
-       return uart_add_one_port(&cpm_reg, &pinfo->port);
-}
-
-static int __devexit cpm_uart_remove(struct platform_device *ofdev)
-{
-       struct uart_cpm_port *pinfo = dev_get_drvdata(&ofdev->dev);
-       return uart_remove_one_port(&cpm_reg, &pinfo->port);
-}
-
-static struct of_device_id cpm_uart_match[] = {
-       {
-               .compatible = "fsl,cpm1-smc-uart",
-       },
-       {
-               .compatible = "fsl,cpm1-scc-uart",
-       },
-       {
-               .compatible = "fsl,cpm2-smc-uart",
-       },
-       {
-               .compatible = "fsl,cpm2-scc-uart",
-       },
-       {}
-};
-
-static struct of_platform_driver cpm_uart_driver = {
-       .driver = {
-               .name = "cpm_uart",
-               .owner = THIS_MODULE,
-               .of_match_table = cpm_uart_match,
-       },
-       .probe = cpm_uart_probe,
-       .remove = cpm_uart_remove,
- };
-
-static int __init cpm_uart_init(void)
-{
-       int ret = uart_register_driver(&cpm_reg);
-       if (ret)
-               return ret;
-
-       ret = of_register_platform_driver(&cpm_uart_driver);
-       if (ret)
-               uart_unregister_driver(&cpm_reg);
-
-       return ret;
-}
-
-static void __exit cpm_uart_exit(void)
-{
-       of_unregister_platform_driver(&cpm_uart_driver);
-       uart_unregister_driver(&cpm_reg);
-}
-
-module_init(cpm_uart_init);
-module_exit(cpm_uart_exit);
-
-MODULE_AUTHOR("Kumar Gala/Antoniou Pantelis");
-MODULE_DESCRIPTION("CPM SCC/SMC port driver $Revision: 0.01 $");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV(SERIAL_CPM_MAJOR, SERIAL_CPM_MINOR);
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
deleted file mode 100644 (file)
index 3fc1d66..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- *  linux/drivers/serial/cpm_uart.c
- *
- *  Driver for CPM (SCC/SMC) serial ports; CPM1 definitions
- *
- *  Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2)
- *              Pantelis Antoniou (panto@intracom.gr) (CPM1)
- *
- *  Copyright (C) 2004 Freescale Semiconductor, Inc.
- *            (C) 2004 Intracom, S.A.
- *            (C) 2006 MontaVista Software, Inc.
- *             Vitaly Bordug <vbordug@ru.mvista.com>
- *
- * 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/module.h>
-#include <linux/tty.h>
-#include <linux/gfp.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/serial.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/device.h>
-#include <linux/bootmem.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/fs_pd.h>
-
-#include <linux/serial_core.h>
-#include <linux/kernel.h>
-
-#include <linux/of.h>
-
-#include "cpm_uart.h"
-
-/**************************************************************/
-
-void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd)
-{
-       cpm_command(port->command, cmd);
-}
-
-void __iomem *cpm_uart_map_pram(struct uart_cpm_port *port,
-                               struct device_node *np)
-{
-       return of_iomap(np, 1);
-}
-
-void cpm_uart_unmap_pram(struct uart_cpm_port *port, void __iomem *pram)
-{
-       iounmap(pram);
-}
-
-/*
- * Allocate DP-Ram and memory buffers. We need to allocate a transmit and
- * receive buffer descriptors from dual port ram, and a character
- * buffer area from host mem. If we are allocating for the console we need
- * to do it from bootmem
- */
-int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
-{
-       int dpmemsz, memsz;
-       u8 *dp_mem;
-       unsigned long dp_offset;
-       u8 *mem_addr;
-       dma_addr_t dma_addr = 0;
-
-       pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line);
-
-       dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos);
-       dp_offset = cpm_dpalloc(dpmemsz, 8);
-       if (IS_ERR_VALUE(dp_offset)) {
-               printk(KERN_ERR
-                      "cpm_uart_cpm1.c: could not allocate buffer descriptors\n");
-               return -ENOMEM;
-       }
-       dp_mem = cpm_dpram_addr(dp_offset);
-
-       memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) +
-           L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize);
-       if (is_con) {
-               /* was hostalloc but changed cause it blows away the */
-               /* large tlb mapping when pinning the kernel area    */
-               mem_addr = (u8 *) cpm_dpram_addr(cpm_dpalloc(memsz, 8));
-               dma_addr = (u32)cpm_dpram_phys(mem_addr);
-       } else
-               mem_addr = dma_alloc_coherent(pinfo->port.dev, memsz, &dma_addr,
-                                             GFP_KERNEL);
-
-       if (mem_addr == NULL) {
-               cpm_dpfree(dp_offset);
-               printk(KERN_ERR
-                      "cpm_uart_cpm1.c: could not allocate coherent memory\n");
-               return -ENOMEM;
-       }
-
-       pinfo->dp_addr = dp_offset;
-       pinfo->mem_addr = mem_addr;             /*  virtual address*/
-       pinfo->dma_addr = dma_addr;             /*  physical address*/
-       pinfo->mem_size = memsz;
-
-       pinfo->rx_buf = mem_addr;
-       pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
-                                                      * pinfo->rx_fifosize);
-
-       pinfo->rx_bd_base = (cbd_t __iomem __force *)dp_mem;
-       pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos;
-
-       return 0;
-}
-
-void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
-{
-       dma_free_coherent(pinfo->port.dev, L1_CACHE_ALIGN(pinfo->rx_nrfifos *
-                                                         pinfo->rx_fifosize) +
-                         L1_CACHE_ALIGN(pinfo->tx_nrfifos *
-                                        pinfo->tx_fifosize), pinfo->mem_addr,
-                         pinfo->dma_addr);
-
-       cpm_dpfree(pinfo->dp_addr);
-}
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/serial/cpm_uart/cpm_uart_cpm1.h
deleted file mode 100644 (file)
index 10eecd6..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * linux/drivers/serial/cpm_uart/cpm_uart_cpm1.h
- *
- * Driver for CPM (SCC/SMC) serial ports
- *
- * definitions for cpm1
- *
- */
-
-#ifndef CPM_UART_CPM1_H
-#define CPM_UART_CPM1_H
-
-#include <asm/cpm1.h>
-
-static inline void cpm_set_brg(int brg, int baud)
-{
-       cpm_setbrg(brg, baud);
-}
-
-static inline void cpm_set_scc_fcr(scc_uart_t __iomem * sup)
-{
-       out_8(&sup->scc_genscc.scc_rfcr, SMC_EB);
-       out_8(&sup->scc_genscc.scc_tfcr, SMC_EB);
-}
-
-static inline void cpm_set_smc_fcr(smc_uart_t __iomem * up)
-{
-       out_8(&up->smc_rfcr, SMC_EB);
-       out_8(&up->smc_tfcr, SMC_EB);
-}
-
-#define DPRAM_BASE     ((u8 __iomem __force *)cpm_dpram_addr(0))
-
-#endif
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
deleted file mode 100644 (file)
index 814ac00..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- *  linux/drivers/serial/cpm_uart_cpm2.c
- *
- *  Driver for CPM (SCC/SMC) serial ports; CPM2 definitions
- *
- *  Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2)
- *              Pantelis Antoniou (panto@intracom.gr) (CPM1)
- *
- *  Copyright (C) 2004 Freescale Semiconductor, Inc.
- *            (C) 2004 Intracom, S.A.
- *            (C) 2006 MontaVista Software, Inc.
- *             Vitaly Bordug <vbordug@ru.mvista.com>
- *
- * 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/module.h>
-#include <linux/tty.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/serial.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/device.h>
-#include <linux/bootmem.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/fs_pd.h>
-#include <asm/prom.h>
-
-#include <linux/serial_core.h>
-#include <linux/kernel.h>
-
-#include "cpm_uart.h"
-
-/**************************************************************/
-
-void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd)
-{
-       cpm_command(port->command, cmd);
-}
-
-void __iomem *cpm_uart_map_pram(struct uart_cpm_port *port,
-                               struct device_node *np)
-{
-       void __iomem *pram;
-       unsigned long offset;
-       struct resource res;
-       resource_size_t len;
-
-       /* Don't remap parameter RAM if it has already been initialized
-        * during console setup.
-        */
-       if (IS_SMC(port) && port->smcup)
-               return port->smcup;
-       else if (!IS_SMC(port) && port->sccup)
-               return port->sccup;
-
-       if (of_address_to_resource(np, 1, &res))
-               return NULL;
-
-       len = resource_size(&res);
-       pram = ioremap(res.start, len);
-       if (!pram)
-               return NULL;
-
-       if (!IS_SMC(port))
-               return pram;
-
-       if (len != 2) {
-               printk(KERN_WARNING "cpm_uart[%d]: device tree references "
-                       "SMC pram, using boot loader/wrapper pram mapping. "
-                       "Please fix your device tree to reference the pram "
-                       "base register instead.\n",
-                       port->port.line);
-               return pram;
-       }
-
-       offset = cpm_dpalloc(PROFF_SMC_SIZE, 64);
-       out_be16(pram, offset);
-       iounmap(pram);
-       return cpm_muram_addr(offset);
-}
-
-void cpm_uart_unmap_pram(struct uart_cpm_port *port, void __iomem *pram)
-{
-       if (!IS_SMC(port))
-               iounmap(pram);
-}
-
-/*
- * Allocate DP-Ram and memory buffers. We need to allocate a transmit and
- * receive buffer descriptors from dual port ram, and a character
- * buffer area from host mem. If we are allocating for the console we need
- * to do it from bootmem
- */
-int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
-{
-       int dpmemsz, memsz;
-       u8 __iomem *dp_mem;
-       unsigned long dp_offset;
-       u8 *mem_addr;
-       dma_addr_t dma_addr = 0;
-
-       pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line);
-
-       dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos);
-       dp_offset = cpm_dpalloc(dpmemsz, 8);
-       if (IS_ERR_VALUE(dp_offset)) {
-               printk(KERN_ERR
-                      "cpm_uart_cpm.c: could not allocate buffer descriptors\n");
-               return -ENOMEM;
-       }
-
-       dp_mem = cpm_dpram_addr(dp_offset);
-
-       memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) +
-           L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize);
-       if (is_con) {
-               mem_addr = kzalloc(memsz, GFP_NOWAIT);
-               dma_addr = virt_to_bus(mem_addr);
-       }
-       else
-               mem_addr = dma_alloc_coherent(pinfo->port.dev, memsz, &dma_addr,
-                                             GFP_KERNEL);
-
-       if (mem_addr == NULL) {
-               cpm_dpfree(dp_offset);
-               printk(KERN_ERR
-                      "cpm_uart_cpm.c: could not allocate coherent memory\n");
-               return -ENOMEM;
-       }
-
-       pinfo->dp_addr = dp_offset;
-       pinfo->mem_addr = mem_addr;
-       pinfo->dma_addr = dma_addr;
-       pinfo->mem_size = memsz;
-
-       pinfo->rx_buf = mem_addr;
-       pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
-                                                      * pinfo->rx_fifosize);
-
-       pinfo->rx_bd_base = (cbd_t __iomem *)dp_mem;
-       pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos;
-
-       return 0;
-}
-
-void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
-{
-       dma_free_coherent(pinfo->port.dev, L1_CACHE_ALIGN(pinfo->rx_nrfifos *
-                                                         pinfo->rx_fifosize) +
-                         L1_CACHE_ALIGN(pinfo->tx_nrfifos *
-                                        pinfo->tx_fifosize), (void __force *)pinfo->mem_addr,
-                         pinfo->dma_addr);
-
-       cpm_dpfree(pinfo->dp_addr);
-}
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.h b/drivers/serial/cpm_uart/cpm_uart_cpm2.h
deleted file mode 100644 (file)
index 7194c63..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * linux/drivers/serial/cpm_uart/cpm_uart_cpm2.h
- *
- * Driver for CPM (SCC/SMC) serial ports
- *
- * definitions for cpm2
- *
- */
-
-#ifndef CPM_UART_CPM2_H
-#define CPM_UART_CPM2_H
-
-#include <asm/cpm2.h>
-
-static inline void cpm_set_brg(int brg, int baud)
-{
-       cpm_setbrg(brg, baud);
-}
-
-static inline void cpm_set_scc_fcr(scc_uart_t __iomem *sup)
-{
-       out_8(&sup->scc_genscc.scc_rfcr, CPMFCR_GBL | CPMFCR_EB);
-       out_8(&sup->scc_genscc.scc_tfcr, CPMFCR_GBL | CPMFCR_EB);
-}
-
-static inline void cpm_set_smc_fcr(smc_uart_t __iomem *up)
-{
-       out_8(&up->smc_rfcr, CPMFCR_GBL | CPMFCR_EB);
-       out_8(&up->smc_tfcr, CPMFCR_GBL | CPMFCR_EB);
-}
-
-#define DPRAM_BASE     ((u8 __iomem __force *)cpm_dpram_addr(0))
-
-#endif
diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c
deleted file mode 100644 (file)
index bcc31f2..0000000
+++ /dev/null
@@ -1,4573 +0,0 @@
-/*
- * Serial port driver for the ETRAX 100LX chip
- *
- *    Copyright (C) 1998-2007  Axis Communications AB
- *
- *    Many, many authors. Based once upon a time on serial.c for 16x50.
- *
- */
-
-static char *serial_version = "$Revision: 1.25 $";
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.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/mm.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/mutex.h>
-#include <linux/bitops.h>
-#include <linux/seq_file.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/uaccess.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <asm/dma.h>
-#include <asm/system.h>
-
-#include <arch/svinto.h>
-
-/* non-arch dependent serial structures are in linux/serial.h */
-#include <linux/serial.h>
-/* while we keep our own stuff (struct e100_serial) in a local .h file */
-#include "crisv10.h"
-#include <asm/fasttimer.h>
-#include <arch/io_interface_mux.h>
-
-#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
-#ifndef CONFIG_ETRAX_FAST_TIMER
-#error "Enable FAST_TIMER to use SERIAL_FAST_TIMER"
-#endif
-#endif
-
-#if defined(CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS) && \
-           (CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS == 0)
-#error "RX_TIMEOUT_TICKS == 0 not allowed, use 1"
-#endif
-
-#if defined(CONFIG_ETRAX_RS485_ON_PA) && defined(CONFIG_ETRAX_RS485_ON_PORT_G)
-#error "Disable either CONFIG_ETRAX_RS485_ON_PA or CONFIG_ETRAX_RS485_ON_PORT_G"
-#endif
-
-/*
- * All of the compatibilty code so we can compile serial.c against
- * older kernels is hidden in serial_compat.h
- */
-#if defined(LOCAL_HEADERS)
-#include "serial_compat.h"
-#endif
-
-struct tty_driver *serial_driver;
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
-
-//#define SERIAL_DEBUG_INTR
-//#define SERIAL_DEBUG_OPEN
-//#define SERIAL_DEBUG_FLOW
-//#define SERIAL_DEBUG_DATA
-//#define SERIAL_DEBUG_THROTTLE
-//#define SERIAL_DEBUG_IO  /* Debug for Extra control and status pins */
-//#define SERIAL_DEBUG_LINE 0 /* What serport we want to debug */
-
-/* Enable this to use serial interrupts to handle when you
-   expect the first received event on the serial port to
-   be an error, break or similar. Used to be able to flash IRMA
-   from eLinux */
-#define SERIAL_HANDLE_EARLY_ERRORS
-
-/* Currently 16 descriptors x 128 bytes = 2048 bytes */
-#define SERIAL_DESCR_BUF_SIZE 256
-
-#define SERIAL_PRESCALE_BASE 3125000 /* 3.125MHz */
-#define DEF_BAUD_BASE SERIAL_PRESCALE_BASE
-
-/* We don't want to load the system with massive fast timer interrupt
- * on high baudrates so limit it to 250 us (4kHz) */
-#define MIN_FLUSH_TIME_USEC 250
-
-/* Add an x here to log a lot of timer stuff */
-#define TIMERD(x)
-/* Debug details of interrupt handling */
-#define DINTR1(x)  /* irq on/off, errors */
-#define DINTR2(x)    /* tx and rx */
-/* Debug flip buffer stuff */
-#define DFLIP(x)
-/* Debug flow control and overview of data flow */
-#define DFLOW(x)
-#define DBAUD(x)
-#define DLOG_INT_TRIG(x)
-
-//#define DEBUG_LOG_INCLUDED
-#ifndef DEBUG_LOG_INCLUDED
-#define DEBUG_LOG(line, string, value)
-#else
-struct debug_log_info
-{
-       unsigned long time;
-       unsigned long timer_data;
-//  int line;
-       const char *string;
-       int value;
-};
-#define DEBUG_LOG_SIZE 4096
-
-struct debug_log_info debug_log[DEBUG_LOG_SIZE];
-int debug_log_pos = 0;
-
-#define DEBUG_LOG(_line, _string, _value) do { \
-  if ((_line) == SERIAL_DEBUG_LINE) {\
-    debug_log_func(_line, _string, _value); \
-  }\
-}while(0)
-
-void debug_log_func(int line, const char *string, int value)
-{
-       if (debug_log_pos < DEBUG_LOG_SIZE) {
-               debug_log[debug_log_pos].time = jiffies;
-               debug_log[debug_log_pos].timer_data = *R_TIMER_DATA;
-//    debug_log[debug_log_pos].line = line;
-               debug_log[debug_log_pos].string = string;
-               debug_log[debug_log_pos].value = value;
-               debug_log_pos++;
-       }
-       /*printk(string, value);*/
-}
-#endif
-
-#ifndef CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS
-/* Default number of timer ticks before flushing rx fifo
- * When using "little data, low latency applications: use 0
- * When using "much data applications (PPP)" use ~5
- */
-#define CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5
-#endif
-
-unsigned long timer_data_to_ns(unsigned long timer_data);
-
-static void change_speed(struct e100_serial *info);
-static void rs_throttle(struct tty_struct * tty);
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
-static int rs_write(struct tty_struct *tty,
-               const unsigned char *buf, int count);
-#ifdef CONFIG_ETRAX_RS485
-static int e100_write_rs485(struct tty_struct *tty,
-               const unsigned char *buf, int count);
-#endif
-static int get_lsr_info(struct e100_serial *info, unsigned int *value);
-
-
-#define DEF_BAUD 115200   /* 115.2 kbit/s */
-#define STD_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-#define DEF_RX 0x20  /* or SERIAL_CTRL_W >> 8 */
-/* Default value of tx_ctrl register: has txd(bit 7)=1 (idle) as default */
-#define DEF_TX 0x80  /* or SERIAL_CTRL_B */
-
-/* offsets from R_SERIALx_CTRL */
-
-#define REG_DATA 0
-#define REG_DATA_STATUS32 0 /* this is the 32 bit register R_SERIALx_READ */
-#define REG_TR_DATA 0
-#define REG_STATUS 1
-#define REG_TR_CTRL 1
-#define REG_REC_CTRL 2
-#define REG_BAUD 3
-#define REG_XOFF 4  /* this is a 32 bit register */
-
-/* The bitfields are the same for all serial ports */
-#define SER_RXD_MASK         IO_MASK(R_SERIAL0_STATUS, rxd)
-#define SER_DATA_AVAIL_MASK  IO_MASK(R_SERIAL0_STATUS, data_avail)
-#define SER_FRAMING_ERR_MASK IO_MASK(R_SERIAL0_STATUS, framing_err)
-#define SER_PAR_ERR_MASK     IO_MASK(R_SERIAL0_STATUS, par_err)
-#define SER_OVERRUN_MASK     IO_MASK(R_SERIAL0_STATUS, overrun)
-
-#define SER_ERROR_MASK (SER_OVERRUN_MASK | SER_PAR_ERR_MASK | SER_FRAMING_ERR_MASK)
-
-/* Values for info->errorcode */
-#define ERRCODE_SET_BREAK    (TTY_BREAK)
-#define ERRCODE_INSERT        0x100
-#define ERRCODE_INSERT_BREAK (ERRCODE_INSERT | TTY_BREAK)
-
-#define FORCE_EOP(info)  *R_SET_EOP = 1U << info->iseteop;
-
-/*
- * General note regarding the use of IO_* macros in this file:
- *
- * We will use the bits defined for DMA channel 6 when using various
- * IO_* macros (e.g. IO_STATE, IO_MASK, IO_EXTRACT) and _assume_ they are
- * the same for all channels (which of course they are).
- *
- * We will also use the bits defined for serial port 0 when writing commands
- * to the different ports, as these bits too are the same for all ports.
- */
-
-
-/* Mask for the irqs possibly enabled in R_IRQ_MASK1_RD etc. */
-static const unsigned long e100_ser_int_mask = 0
-#ifdef CONFIG_ETRAX_SERIAL_PORT0
-| IO_MASK(R_IRQ_MASK1_RD, ser0_data) | IO_MASK(R_IRQ_MASK1_RD, ser0_ready)
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT1
-| IO_MASK(R_IRQ_MASK1_RD, ser1_data) | IO_MASK(R_IRQ_MASK1_RD, ser1_ready)
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT2
-| IO_MASK(R_IRQ_MASK1_RD, ser2_data) | IO_MASK(R_IRQ_MASK1_RD, ser2_ready)
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT3
-| IO_MASK(R_IRQ_MASK1_RD, ser3_data) | IO_MASK(R_IRQ_MASK1_RD, ser3_ready)
-#endif
-;
-unsigned long r_alt_ser_baudrate_shadow = 0;
-
-/* this is the data for the four serial ports in the etrax100 */
-/*  DMA2(ser2), DMA4(ser3), DMA6(ser0) or DMA8(ser1) */
-/* R_DMA_CHx_CLR_INTR, R_DMA_CHx_FIRST, R_DMA_CHx_CMD */
-
-static struct e100_serial rs_table[] = {
-       { .baud        = DEF_BAUD,
-         .ioport        = (unsigned char *)R_SERIAL0_CTRL,
-         .irq         = 1U << 12, /* uses DMA 6 and 7 */
-         .oclrintradr = R_DMA_CH6_CLR_INTR,
-         .ofirstadr   = R_DMA_CH6_FIRST,
-         .ocmdadr     = R_DMA_CH6_CMD,
-         .ostatusadr  = R_DMA_CH6_STATUS,
-         .iclrintradr = R_DMA_CH7_CLR_INTR,
-         .ifirstadr   = R_DMA_CH7_FIRST,
-         .icmdadr     = R_DMA_CH7_CMD,
-         .idescradr   = R_DMA_CH7_DESCR,
-         .flags       = STD_FLAGS,
-         .rx_ctrl     = DEF_RX,
-         .tx_ctrl     = DEF_TX,
-         .iseteop     = 2,
-         .dma_owner   = dma_ser0,
-         .io_if       = if_serial_0,
-#ifdef CONFIG_ETRAX_SERIAL_PORT0
-          .enabled  = 1,
-#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT
-         .dma_out_enabled = 1,
-         .dma_out_nbr = SER0_TX_DMA_NBR,
-         .dma_out_irq_nbr = SER0_DMA_TX_IRQ_NBR,
-         .dma_out_irq_flags = IRQF_DISABLED,
-         .dma_out_irq_description = "serial 0 dma tr",
-#else
-         .dma_out_enabled = 0,
-         .dma_out_nbr = UINT_MAX,
-         .dma_out_irq_nbr = 0,
-         .dma_out_irq_flags = 0,
-         .dma_out_irq_description = NULL,
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN
-         .dma_in_enabled = 1,
-         .dma_in_nbr = SER0_RX_DMA_NBR,
-         .dma_in_irq_nbr = SER0_DMA_RX_IRQ_NBR,
-         .dma_in_irq_flags = IRQF_DISABLED,
-         .dma_in_irq_description = "serial 0 dma rec",
-#else
-         .dma_in_enabled = 0,
-         .dma_in_nbr = UINT_MAX,
-         .dma_in_irq_nbr = 0,
-         .dma_in_irq_flags = 0,
-         .dma_in_irq_description = NULL,
-#endif
-#else
-          .enabled  = 0,
-         .io_if_description = NULL,
-         .dma_out_enabled = 0,
-         .dma_in_enabled = 0
-#endif
-
-},  /* ttyS0 */
-#ifndef CONFIG_SVINTO_SIM
-       { .baud        = DEF_BAUD,
-         .ioport        = (unsigned char *)R_SERIAL1_CTRL,
-         .irq         = 1U << 16, /* uses DMA 8 and 9 */
-         .oclrintradr = R_DMA_CH8_CLR_INTR,
-         .ofirstadr   = R_DMA_CH8_FIRST,
-         .ocmdadr     = R_DMA_CH8_CMD,
-         .ostatusadr  = R_DMA_CH8_STATUS,
-         .iclrintradr = R_DMA_CH9_CLR_INTR,
-         .ifirstadr   = R_DMA_CH9_FIRST,
-         .icmdadr     = R_DMA_CH9_CMD,
-         .idescradr   = R_DMA_CH9_DESCR,
-         .flags       = STD_FLAGS,
-         .rx_ctrl     = DEF_RX,
-         .tx_ctrl     = DEF_TX,
-         .iseteop     = 3,
-         .dma_owner   = dma_ser1,
-         .io_if       = if_serial_1,
-#ifdef CONFIG_ETRAX_SERIAL_PORT1
-          .enabled  = 1,
-         .io_if_description = "ser1",
-#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA8_OUT
-         .dma_out_enabled = 1,
-         .dma_out_nbr = SER1_TX_DMA_NBR,
-         .dma_out_irq_nbr = SER1_DMA_TX_IRQ_NBR,
-         .dma_out_irq_flags = IRQF_DISABLED,
-         .dma_out_irq_description = "serial 1 dma tr",
-#else
-         .dma_out_enabled = 0,
-         .dma_out_nbr = UINT_MAX,
-         .dma_out_irq_nbr = 0,
-         .dma_out_irq_flags = 0,
-         .dma_out_irq_description = NULL,
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA9_IN
-         .dma_in_enabled = 1,
-         .dma_in_nbr = SER1_RX_DMA_NBR,
-         .dma_in_irq_nbr = SER1_DMA_RX_IRQ_NBR,
-         .dma_in_irq_flags = IRQF_DISABLED,
-         .dma_in_irq_description = "serial 1 dma rec",
-#else
-         .dma_in_enabled = 0,
-         .dma_in_enabled = 0,
-         .dma_in_nbr = UINT_MAX,
-         .dma_in_irq_nbr = 0,
-         .dma_in_irq_flags = 0,
-         .dma_in_irq_description = NULL,
-#endif
-#else
-          .enabled  = 0,
-         .io_if_description = NULL,
-         .dma_in_irq_nbr = 0,
-         .dma_out_enabled = 0,
-         .dma_in_enabled = 0
-#endif
-},  /* ttyS1 */
-
-       { .baud        = DEF_BAUD,
-         .ioport        = (unsigned char *)R_SERIAL2_CTRL,
-         .irq         = 1U << 4,  /* uses DMA 2 and 3 */
-         .oclrintradr = R_DMA_CH2_CLR_INTR,
-         .ofirstadr   = R_DMA_CH2_FIRST,
-         .ocmdadr     = R_DMA_CH2_CMD,
-         .ostatusadr  = R_DMA_CH2_STATUS,
-         .iclrintradr = R_DMA_CH3_CLR_INTR,
-         .ifirstadr   = R_DMA_CH3_FIRST,
-         .icmdadr     = R_DMA_CH3_CMD,
-         .idescradr   = R_DMA_CH3_DESCR,
-         .flags       = STD_FLAGS,
-         .rx_ctrl     = DEF_RX,
-         .tx_ctrl     = DEF_TX,
-         .iseteop     = 0,
-         .dma_owner   = dma_ser2,
-         .io_if       = if_serial_2,
-#ifdef CONFIG_ETRAX_SERIAL_PORT2
-          .enabled  = 1,
-         .io_if_description = "ser2",
-#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT
-         .dma_out_enabled = 1,
-         .dma_out_nbr = SER2_TX_DMA_NBR,
-         .dma_out_irq_nbr = SER2_DMA_TX_IRQ_NBR,
-         .dma_out_irq_flags = IRQF_DISABLED,
-         .dma_out_irq_description = "serial 2 dma tr",
-#else
-         .dma_out_enabled = 0,
-         .dma_out_nbr = UINT_MAX,
-         .dma_out_irq_nbr = 0,
-         .dma_out_irq_flags = 0,
-         .dma_out_irq_description = NULL,
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN
-         .dma_in_enabled = 1,
-         .dma_in_nbr = SER2_RX_DMA_NBR,
-         .dma_in_irq_nbr = SER2_DMA_RX_IRQ_NBR,
-         .dma_in_irq_flags = IRQF_DISABLED,
-         .dma_in_irq_description = "serial 2 dma rec",
-#else
-         .dma_in_enabled = 0,
-         .dma_in_nbr = UINT_MAX,
-         .dma_in_irq_nbr = 0,
-         .dma_in_irq_flags = 0,
-         .dma_in_irq_description = NULL,
-#endif
-#else
-          .enabled  = 0,
-         .io_if_description = NULL,
-         .dma_out_enabled = 0,
-         .dma_in_enabled = 0
-#endif
- },  /* ttyS2 */
-
-       { .baud        = DEF_BAUD,
-         .ioport        = (unsigned char *)R_SERIAL3_CTRL,
-         .irq         = 1U << 8,  /* uses DMA 4 and 5 */
-         .oclrintradr = R_DMA_CH4_CLR_INTR,
-         .ofirstadr   = R_DMA_CH4_FIRST,
-         .ocmdadr     = R_DMA_CH4_CMD,
-         .ostatusadr  = R_DMA_CH4_STATUS,
-         .iclrintradr = R_DMA_CH5_CLR_INTR,
-         .ifirstadr   = R_DMA_CH5_FIRST,
-         .icmdadr     = R_DMA_CH5_CMD,
-         .idescradr   = R_DMA_CH5_DESCR,
-         .flags       = STD_FLAGS,
-         .rx_ctrl     = DEF_RX,
-         .tx_ctrl     = DEF_TX,
-         .iseteop     = 1,
-         .dma_owner   = dma_ser3,
-         .io_if       = if_serial_3,
-#ifdef CONFIG_ETRAX_SERIAL_PORT3
-          .enabled  = 1,
-         .io_if_description = "ser3",
-#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT
-         .dma_out_enabled = 1,
-         .dma_out_nbr = SER3_TX_DMA_NBR,
-         .dma_out_irq_nbr = SER3_DMA_TX_IRQ_NBR,
-         .dma_out_irq_flags = IRQF_DISABLED,
-         .dma_out_irq_description = "serial 3 dma tr",
-#else
-         .dma_out_enabled = 0,
-         .dma_out_nbr = UINT_MAX,
-         .dma_out_irq_nbr = 0,
-         .dma_out_irq_flags = 0,
-         .dma_out_irq_description = NULL,
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN
-         .dma_in_enabled = 1,
-         .dma_in_nbr = SER3_RX_DMA_NBR,
-         .dma_in_irq_nbr = SER3_DMA_RX_IRQ_NBR,
-         .dma_in_irq_flags = IRQF_DISABLED,
-         .dma_in_irq_description = "serial 3 dma rec",
-#else
-         .dma_in_enabled = 0,
-         .dma_in_nbr = UINT_MAX,
-         .dma_in_irq_nbr = 0,
-         .dma_in_irq_flags = 0,
-         .dma_in_irq_description = NULL
-#endif
-#else
-          .enabled  = 0,
-         .io_if_description = NULL,
-         .dma_out_enabled = 0,
-         .dma_in_enabled = 0
-#endif
- }   /* ttyS3 */
-#endif
-};
-
-
-#define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial))
-
-#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
-static struct fast_timer fast_timers[NR_PORTS];
-#endif
-
-#ifdef CONFIG_ETRAX_SERIAL_PROC_ENTRY
-#define PROCSTAT(x) x
-struct ser_statistics_type {
-       int overrun_cnt;
-       int early_errors_cnt;
-       int ser_ints_ok_cnt;
-       int errors_cnt;
-       unsigned long int processing_flip;
-       unsigned long processing_flip_still_room;
-       unsigned long int timeout_flush_cnt;
-       int rx_dma_ints;
-       int tx_dma_ints;
-       int rx_tot;
-       int tx_tot;
-};
-
-static struct ser_statistics_type ser_stat[NR_PORTS];
-
-#else
-
-#define PROCSTAT(x)
-
-#endif /* CONFIG_ETRAX_SERIAL_PROC_ENTRY */
-
-/* RS-485 */
-#if defined(CONFIG_ETRAX_RS485)
-#ifdef CONFIG_ETRAX_FAST_TIMER
-static struct fast_timer fast_timers_rs485[NR_PORTS];
-#endif
-#if defined(CONFIG_ETRAX_RS485_ON_PA)
-static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT;
-#endif
-#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
-static int rs485_port_g_bit = CONFIG_ETRAX_RS485_ON_PORT_G_BIT;
-#endif
-#endif
-
-/* Info and macros needed for each ports extra control/status signals. */
-#define E100_STRUCT_PORT(line, pinname) \
- ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
-               (R_PORT_PA_DATA): ( \
- (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
-               (R_PORT_PB_DATA):&dummy_ser[line]))
-
-#define E100_STRUCT_SHADOW(line, pinname) \
- ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
-               (&port_pa_data_shadow): ( \
- (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
-               (&port_pb_data_shadow):&dummy_ser[line]))
-#define E100_STRUCT_MASK(line, pinname) \
- ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
-               (1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT): ( \
- (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
-               (1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT):DUMMY_##pinname##_MASK))
-
-#define DUMMY_DTR_MASK 1
-#define DUMMY_RI_MASK  2
-#define DUMMY_DSR_MASK 4
-#define DUMMY_CD_MASK  8
-static unsigned char dummy_ser[NR_PORTS] = {0xFF, 0xFF, 0xFF,0xFF};
-
-/* If not all status pins are used or disabled, use mixed mode */
-#ifdef CONFIG_ETRAX_SERIAL_PORT0
-
-#define SER0_PA_BITSUM (CONFIG_ETRAX_SER0_DTR_ON_PA_BIT+CONFIG_ETRAX_SER0_RI_ON_PA_BIT+CONFIG_ETRAX_SER0_DSR_ON_PA_BIT+CONFIG_ETRAX_SER0_CD_ON_PA_BIT)
-
-#if SER0_PA_BITSUM != -4
-#  if CONFIG_ETRAX_SER0_DTR_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#   endif
-# if CONFIG_ETRAX_SER0_RI_ON_PA_BIT == -1
-#   ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
-#     define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
-#   endif
-#  endif
-#  if CONFIG_ETRAX_SER0_DSR_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#  if CONFIG_ETRAX_SER0_CD_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#endif
-
-#define SER0_PB_BITSUM (CONFIG_ETRAX_SER0_DTR_ON_PB_BIT+CONFIG_ETRAX_SER0_RI_ON_PB_BIT+CONFIG_ETRAX_SER0_DSR_ON_PB_BIT+CONFIG_ETRAX_SER0_CD_ON_PB_BIT)
-
-#if SER0_PB_BITSUM != -4
-#  if CONFIG_ETRAX_SER0_DTR_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#   endif
-# if CONFIG_ETRAX_SER0_RI_ON_PB_BIT == -1
-#   ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
-#     define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
-#   endif
-#  endif
-#  if CONFIG_ETRAX_SER0_DSR_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#  if CONFIG_ETRAX_SER0_CD_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#endif
-
-#endif /* PORT0 */
-
-
-#ifdef CONFIG_ETRAX_SERIAL_PORT1
-
-#define SER1_PA_BITSUM (CONFIG_ETRAX_SER1_DTR_ON_PA_BIT+CONFIG_ETRAX_SER1_RI_ON_PA_BIT+CONFIG_ETRAX_SER1_DSR_ON_PA_BIT+CONFIG_ETRAX_SER1_CD_ON_PA_BIT)
-
-#if SER1_PA_BITSUM != -4
-#  if CONFIG_ETRAX_SER1_DTR_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#   endif
-# if CONFIG_ETRAX_SER1_RI_ON_PA_BIT == -1
-#   ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
-#     define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
-#   endif
-#  endif
-#  if CONFIG_ETRAX_SER1_DSR_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#  if CONFIG_ETRAX_SER1_CD_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#endif
-
-#define SER1_PB_BITSUM (CONFIG_ETRAX_SER1_DTR_ON_PB_BIT+CONFIG_ETRAX_SER1_RI_ON_PB_BIT+CONFIG_ETRAX_SER1_DSR_ON_PB_BIT+CONFIG_ETRAX_SER1_CD_ON_PB_BIT)
-
-#if SER1_PB_BITSUM != -4
-#  if CONFIG_ETRAX_SER1_DTR_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#   endif
-# if CONFIG_ETRAX_SER1_RI_ON_PB_BIT == -1
-#   ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
-#     define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
-#   endif
-#  endif
-#  if CONFIG_ETRAX_SER1_DSR_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#  if CONFIG_ETRAX_SER1_CD_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#endif
-
-#endif /* PORT1 */
-
-#ifdef CONFIG_ETRAX_SERIAL_PORT2
-
-#define SER2_PA_BITSUM (CONFIG_ETRAX_SER2_DTR_ON_PA_BIT+CONFIG_ETRAX_SER2_RI_ON_PA_BIT+CONFIG_ETRAX_SER2_DSR_ON_PA_BIT+CONFIG_ETRAX_SER2_CD_ON_PA_BIT)
-
-#if SER2_PA_BITSUM != -4
-#  if CONFIG_ETRAX_SER2_DTR_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#   endif
-# if CONFIG_ETRAX_SER2_RI_ON_PA_BIT == -1
-#   ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
-#     define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
-#   endif
-#  endif
-#  if CONFIG_ETRAX_SER2_DSR_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#  if CONFIG_ETRAX_SER2_CD_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#endif
-
-#define SER2_PB_BITSUM (CONFIG_ETRAX_SER2_DTR_ON_PB_BIT+CONFIG_ETRAX_SER2_RI_ON_PB_BIT+CONFIG_ETRAX_SER2_DSR_ON_PB_BIT+CONFIG_ETRAX_SER2_CD_ON_PB_BIT)
-
-#if SER2_PB_BITSUM != -4
-#  if CONFIG_ETRAX_SER2_DTR_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#   endif
-# if CONFIG_ETRAX_SER2_RI_ON_PB_BIT == -1
-#   ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
-#     define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
-#   endif
-#  endif
-#  if CONFIG_ETRAX_SER2_DSR_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#  if CONFIG_ETRAX_SER2_CD_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#endif
-
-#endif /* PORT2 */
-
-#ifdef CONFIG_ETRAX_SERIAL_PORT3
-
-#define SER3_PA_BITSUM (CONFIG_ETRAX_SER3_DTR_ON_PA_BIT+CONFIG_ETRAX_SER3_RI_ON_PA_BIT+CONFIG_ETRAX_SER3_DSR_ON_PA_BIT+CONFIG_ETRAX_SER3_CD_ON_PA_BIT)
-
-#if SER3_PA_BITSUM != -4
-#  if CONFIG_ETRAX_SER3_DTR_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#   endif
-# if CONFIG_ETRAX_SER3_RI_ON_PA_BIT == -1
-#   ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
-#     define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
-#   endif
-#  endif
-#  if CONFIG_ETRAX_SER3_DSR_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#  if CONFIG_ETRAX_SER3_CD_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#endif
-
-#define SER3_PB_BITSUM (CONFIG_ETRAX_SER3_DTR_ON_PB_BIT+CONFIG_ETRAX_SER3_RI_ON_PB_BIT+CONFIG_ETRAX_SER3_DSR_ON_PB_BIT+CONFIG_ETRAX_SER3_CD_ON_PB_BIT)
-
-#if SER3_PB_BITSUM != -4
-#  if CONFIG_ETRAX_SER3_DTR_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#   endif
-# if CONFIG_ETRAX_SER3_RI_ON_PB_BIT == -1
-#   ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
-#     define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
-#   endif
-#  endif
-#  if CONFIG_ETRAX_SER3_DSR_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#  if CONFIG_ETRAX_SER3_CD_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#endif
-
-#endif /* PORT3 */
-
-
-#if defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED) || \
-    defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED) || \
-    defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED) || \
-    defined(CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED)
-#define CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
-#endif
-
-#ifdef CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
-/* The pins can be mixed on PA and PB */
-#define CONTROL_PINS_PORT_NOT_USED(line) \
-  &dummy_ser[line], &dummy_ser[line], \
-  &dummy_ser[line], &dummy_ser[line], \
-  &dummy_ser[line], &dummy_ser[line], \
-  &dummy_ser[line], &dummy_ser[line], \
-  DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK
-
-
-struct control_pins
-{
-       volatile unsigned char *dtr_port;
-       unsigned char          *dtr_shadow;
-       volatile unsigned char *ri_port;
-       unsigned char          *ri_shadow;
-       volatile unsigned char *dsr_port;
-       unsigned char          *dsr_shadow;
-       volatile unsigned char *cd_port;
-       unsigned char          *cd_shadow;
-
-       unsigned char dtr_mask;
-       unsigned char ri_mask;
-       unsigned char dsr_mask;
-       unsigned char cd_mask;
-};
-
-static const struct control_pins e100_modem_pins[NR_PORTS] =
-{
-       /* Ser 0 */
-       {
-#ifdef CONFIG_ETRAX_SERIAL_PORT0
-       E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR),
-       E100_STRUCT_PORT(0,RI),  E100_STRUCT_SHADOW(0,RI),
-       E100_STRUCT_PORT(0,DSR), E100_STRUCT_SHADOW(0,DSR),
-       E100_STRUCT_PORT(0,CD),  E100_STRUCT_SHADOW(0,CD),
-       E100_STRUCT_MASK(0,DTR),
-       E100_STRUCT_MASK(0,RI),
-       E100_STRUCT_MASK(0,DSR),
-       E100_STRUCT_MASK(0,CD)
-#else
-       CONTROL_PINS_PORT_NOT_USED(0)
-#endif
-       },
-
-       /* Ser 1 */
-       {
-#ifdef CONFIG_ETRAX_SERIAL_PORT1
-       E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR),
-       E100_STRUCT_PORT(1,RI),  E100_STRUCT_SHADOW(1,RI),
-       E100_STRUCT_PORT(1,DSR), E100_STRUCT_SHADOW(1,DSR),
-       E100_STRUCT_PORT(1,CD),  E100_STRUCT_SHADOW(1,CD),
-       E100_STRUCT_MASK(1,DTR),
-       E100_STRUCT_MASK(1,RI),
-       E100_STRUCT_MASK(1,DSR),
-       E100_STRUCT_MASK(1,CD)
-#else
-       CONTROL_PINS_PORT_NOT_USED(1)
-#endif
-       },
-
-       /* Ser 2 */
-       {
-#ifdef CONFIG_ETRAX_SERIAL_PORT2
-       E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR),
-       E100_STRUCT_PORT(2,RI),  E100_STRUCT_SHADOW(2,RI),
-       E100_STRUCT_PORT(2,DSR), E100_STRUCT_SHADOW(2,DSR),
-       E100_STRUCT_PORT(2,CD),  E100_STRUCT_SHADOW(2,CD),
-       E100_STRUCT_MASK(2,DTR),
-       E100_STRUCT_MASK(2,RI),
-       E100_STRUCT_MASK(2,DSR),
-       E100_STRUCT_MASK(2,CD)
-#else
-       CONTROL_PINS_PORT_NOT_USED(2)
-#endif
-       },
-
-       /* Ser 3 */
-       {
-#ifdef CONFIG_ETRAX_SERIAL_PORT3
-       E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR),
-       E100_STRUCT_PORT(3,RI),  E100_STRUCT_SHADOW(3,RI),
-       E100_STRUCT_PORT(3,DSR), E100_STRUCT_SHADOW(3,DSR),
-       E100_STRUCT_PORT(3,CD),  E100_STRUCT_SHADOW(3,CD),
-       E100_STRUCT_MASK(3,DTR),
-       E100_STRUCT_MASK(3,RI),
-       E100_STRUCT_MASK(3,DSR),
-       E100_STRUCT_MASK(3,CD)
-#else
-       CONTROL_PINS_PORT_NOT_USED(3)
-#endif
-       }
-};
-#else  /* CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
-
-/* All pins are on either PA or PB for each serial port */
-#define CONTROL_PINS_PORT_NOT_USED(line) \
-  &dummy_ser[line], &dummy_ser[line], \
-  DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK
-
-
-struct control_pins
-{
-       volatile unsigned char *port;
-       unsigned char          *shadow;
-
-       unsigned char dtr_mask;
-       unsigned char ri_mask;
-       unsigned char dsr_mask;
-       unsigned char cd_mask;
-};
-
-#define dtr_port port
-#define dtr_shadow shadow
-#define ri_port port
-#define ri_shadow shadow
-#define dsr_port port
-#define dsr_shadow shadow
-#define cd_port port
-#define cd_shadow shadow
-
-static const struct control_pins e100_modem_pins[NR_PORTS] =
-{
-       /* Ser 0 */
-       {
-#ifdef CONFIG_ETRAX_SERIAL_PORT0
-       E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR),
-       E100_STRUCT_MASK(0,DTR),
-       E100_STRUCT_MASK(0,RI),
-       E100_STRUCT_MASK(0,DSR),
-       E100_STRUCT_MASK(0,CD)
-#else
-       CONTROL_PINS_PORT_NOT_USED(0)
-#endif
-       },
-
-       /* Ser 1 */
-       {
-#ifdef CONFIG_ETRAX_SERIAL_PORT1
-       E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR),
-       E100_STRUCT_MASK(1,DTR),
-       E100_STRUCT_MASK(1,RI),
-       E100_STRUCT_MASK(1,DSR),
-       E100_STRUCT_MASK(1,CD)
-#else
-       CONTROL_PINS_PORT_NOT_USED(1)
-#endif
-       },
-
-       /* Ser 2 */
-       {
-#ifdef CONFIG_ETRAX_SERIAL_PORT2
-       E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR),
-       E100_STRUCT_MASK(2,DTR),
-       E100_STRUCT_MASK(2,RI),
-       E100_STRUCT_MASK(2,DSR),
-       E100_STRUCT_MASK(2,CD)
-#else
-       CONTROL_PINS_PORT_NOT_USED(2)
-#endif
-       },
-
-       /* Ser 3 */
-       {
-#ifdef CONFIG_ETRAX_SERIAL_PORT3
-       E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR),
-       E100_STRUCT_MASK(3,DTR),
-       E100_STRUCT_MASK(3,RI),
-       E100_STRUCT_MASK(3,DSR),
-       E100_STRUCT_MASK(3,CD)
-#else
-       CONTROL_PINS_PORT_NOT_USED(3)
-#endif
-       }
-};
-#endif /* !CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
-
-#define E100_RTS_MASK 0x20
-#define E100_CTS_MASK 0x40
-
-/* All serial port signals are active low:
- * active   = 0 -> 3.3V to RS-232 driver -> -12V on RS-232 level
- * inactive = 1 -> 0V   to RS-232 driver -> +12V on RS-232 level
- *
- * These macros returns the pin value: 0=0V, >=1 = 3.3V on ETRAX chip
- */
-
-/* Output */
-#define E100_RTS_GET(info) ((info)->rx_ctrl & E100_RTS_MASK)
-/* Input */
-#define E100_CTS_GET(info) ((info)->ioport[REG_STATUS] & E100_CTS_MASK)
-
-/* These are typically PA or PB and 0 means 0V, 1 means 3.3V */
-/* Is an output */
-#define E100_DTR_GET(info) ((*e100_modem_pins[(info)->line].dtr_shadow) & e100_modem_pins[(info)->line].dtr_mask)
-
-/* Normally inputs */
-#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].ri_port) & e100_modem_pins[(info)->line].ri_mask)
-#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].cd_port) & e100_modem_pins[(info)->line].cd_mask)
-
-/* Input */
-#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask)
-
-
-/*
- * tmp_buf is used as a temporary buffer by serial_write.  We need to
- * lock it in case the memcpy_fromfs blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
-static unsigned char *tmp_buf;
-static DEFINE_MUTEX(tmp_buf_mutex);
-
-/* Calculate the chartime depending on baudrate, numbor of bits etc. */
-static void update_char_time(struct e100_serial * info)
-{
-       tcflag_t cflags = info->port.tty->termios->c_cflag;
-       int bits;
-
-       /* calc. number of bits / data byte */
-       /* databits + startbit and 1 stopbit */
-       if ((cflags & CSIZE) == CS7)
-               bits = 9;
-       else
-               bits = 10;
-
-       if (cflags & CSTOPB)     /* 2 stopbits ? */
-               bits++;
-
-       if (cflags & PARENB)     /* parity bit ? */
-               bits++;
-
-       /* calc timeout */
-       info->char_time_usec = ((bits * 1000000) / info->baud) + 1;
-       info->flush_time_usec = 4*info->char_time_usec;
-       if (info->flush_time_usec < MIN_FLUSH_TIME_USEC)
-               info->flush_time_usec = MIN_FLUSH_TIME_USEC;
-
-}
-
-/*
- * This function maps from the Bxxxx defines in asm/termbits.h into real
- * baud rates.
- */
-
-static int
-cflag_to_baud(unsigned int cflag)
-{
-       static int baud_table[] = {
-               0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400,
-               4800, 9600, 19200, 38400 };
-
-       static int ext_baud_table[] = {
-               0, 57600, 115200, 230400, 460800, 921600, 1843200, 6250000,
-                0, 0, 0, 0, 0, 0, 0, 0 };
-
-       if (cflag & CBAUDEX)
-               return ext_baud_table[(cflag & CBAUD) & ~CBAUDEX];
-       else
-               return baud_table[cflag & CBAUD];
-}
-
-/* and this maps to an etrax100 hardware baud constant */
-
-static unsigned char
-cflag_to_etrax_baud(unsigned int cflag)
-{
-       char retval;
-
-       static char baud_table[] = {
-               -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, -1, 3, 4, 5, 6, 7 };
-
-       static char ext_baud_table[] = {
-               -1, 8, 9, 10, 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, -1, -1 };
-
-       if (cflag & CBAUDEX)
-               retval = ext_baud_table[(cflag & CBAUD) & ~CBAUDEX];
-       else
-               retval = baud_table[cflag & CBAUD];
-
-       if (retval < 0) {
-               printk(KERN_WARNING "serdriver tried setting invalid baud rate, flags %x.\n", cflag);
-               retval = 5; /* choose default 9600 instead */
-       }
-
-       return retval | (retval << 4); /* choose same for both TX and RX */
-}
-
-
-/* Various static support functions */
-
-/* Functions to set or clear DTR/RTS on the requested line */
-/* It is complicated by the fact that RTS is a serial port register, while
- * DTR might not be implemented in the HW at all, and if it is, it can be on
- * any general port.
- */
-
-
-static inline void
-e100_dtr(struct e100_serial *info, int set)
-{
-#ifndef CONFIG_SVINTO_SIM
-       unsigned char mask = e100_modem_pins[info->line].dtr_mask;
-
-#ifdef SERIAL_DEBUG_IO
-       printk("ser%i dtr %i mask: 0x%02X\n", info->line, set, mask);
-       printk("ser%i shadow before 0x%02X get: %i\n",
-              info->line, *e100_modem_pins[info->line].dtr_shadow,
-              E100_DTR_GET(info));
-#endif
-       /* DTR is active low */
-       {
-               unsigned long flags;
-
-               local_irq_save(flags);
-               *e100_modem_pins[info->line].dtr_shadow &= ~mask;
-               *e100_modem_pins[info->line].dtr_shadow |= (set ? 0 : mask);
-               *e100_modem_pins[info->line].dtr_port = *e100_modem_pins[info->line].dtr_shadow;
-               local_irq_restore(flags);
-       }
-
-#ifdef SERIAL_DEBUG_IO
-       printk("ser%i shadow after 0x%02X get: %i\n",
-              info->line, *e100_modem_pins[info->line].dtr_shadow,
-              E100_DTR_GET(info));
-#endif
-#endif
-}
-
-/* set = 0 means 3.3V on the pin, bitvalue: 0=active, 1=inactive
- *                                          0=0V    , 1=3.3V
- */
-static inline void
-e100_rts(struct e100_serial *info, int set)
-{
-#ifndef CONFIG_SVINTO_SIM
-       unsigned long flags;
-       local_irq_save(flags);
-       info->rx_ctrl &= ~E100_RTS_MASK;
-       info->rx_ctrl |= (set ? 0 : E100_RTS_MASK);  /* RTS is active low */
-       info->ioport[REG_REC_CTRL] = info->rx_ctrl;
-       local_irq_restore(flags);
-#ifdef SERIAL_DEBUG_IO
-       printk("ser%i rts %i\n", info->line, set);
-#endif
-#endif
-}
-
-
-/* If this behaves as a modem, RI and CD is an output */
-static inline void
-e100_ri_out(struct e100_serial *info, int set)
-{
-#ifndef CONFIG_SVINTO_SIM
-       /* RI is active low */
-       {
-               unsigned char mask = e100_modem_pins[info->line].ri_mask;
-               unsigned long flags;
-
-               local_irq_save(flags);
-               *e100_modem_pins[info->line].ri_shadow &= ~mask;
-               *e100_modem_pins[info->line].ri_shadow |= (set ? 0 : mask);
-               *e100_modem_pins[info->line].ri_port = *e100_modem_pins[info->line].ri_shadow;
-               local_irq_restore(flags);
-       }
-#endif
-}
-static inline void
-e100_cd_out(struct e100_serial *info, int set)
-{
-#ifndef CONFIG_SVINTO_SIM
-       /* CD is active low */
-       {
-               unsigned char mask = e100_modem_pins[info->line].cd_mask;
-               unsigned long flags;
-
-               local_irq_save(flags);
-               *e100_modem_pins[info->line].cd_shadow &= ~mask;
-               *e100_modem_pins[info->line].cd_shadow |= (set ? 0 : mask);
-               *e100_modem_pins[info->line].cd_port = *e100_modem_pins[info->line].cd_shadow;
-               local_irq_restore(flags);
-       }
-#endif
-}
-
-static inline void
-e100_disable_rx(struct e100_serial *info)
-{
-#ifndef CONFIG_SVINTO_SIM
-       /* disable the receiver */
-       info->ioport[REG_REC_CTRL] =
-               (info->rx_ctrl &= ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable));
-#endif
-}
-
-static inline void
-e100_enable_rx(struct e100_serial *info)
-{
-#ifndef CONFIG_SVINTO_SIM
-       /* enable the receiver */
-       info->ioport[REG_REC_CTRL] =
-               (info->rx_ctrl |= IO_MASK(R_SERIAL0_REC_CTRL, rec_enable));
-#endif
-}
-
-/* the rx DMA uses both the dma_descr and the dma_eop interrupts */
-
-static inline void
-e100_disable_rxdma_irq(struct e100_serial *info)
-{
-#ifdef SERIAL_DEBUG_INTR
-       printk("rxdma_irq(%d): 0\n",info->line);
-#endif
-       DINTR1(DEBUG_LOG(info->line,"IRQ disable_rxdma_irq %i\n", info->line));
-       *R_IRQ_MASK2_CLR = (info->irq << 2) | (info->irq << 3);
-}
-
-static inline void
-e100_enable_rxdma_irq(struct e100_serial *info)
-{
-#ifdef SERIAL_DEBUG_INTR
-       printk("rxdma_irq(%d): 1\n",info->line);
-#endif
-       DINTR1(DEBUG_LOG(info->line,"IRQ enable_rxdma_irq %i\n", info->line));
-       *R_IRQ_MASK2_SET = (info->irq << 2) | (info->irq << 3);
-}
-
-/* the tx DMA uses only dma_descr interrupt */
-
-static void e100_disable_txdma_irq(struct e100_serial *info)
-{
-#ifdef SERIAL_DEBUG_INTR
-       printk("txdma_irq(%d): 0\n",info->line);
-#endif
-       DINTR1(DEBUG_LOG(info->line,"IRQ disable_txdma_irq %i\n", info->line));
-       *R_IRQ_MASK2_CLR = info->irq;
-}
-
-static void e100_enable_txdma_irq(struct e100_serial *info)
-{
-#ifdef SERIAL_DEBUG_INTR
-       printk("txdma_irq(%d): 1\n",info->line);
-#endif
-       DINTR1(DEBUG_LOG(info->line,"IRQ enable_txdma_irq %i\n", info->line));
-       *R_IRQ_MASK2_SET = info->irq;
-}
-
-static void e100_disable_txdma_channel(struct e100_serial *info)
-{
-       unsigned long flags;
-
-       /* Disable output DMA channel for the serial port in question
-        * ( set to something other than serialX)
-        */
-       local_irq_save(flags);
-       DFLOW(DEBUG_LOG(info->line, "disable_txdma_channel %i\n", info->line));
-       if (info->line == 0) {
-               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma6)) ==
-                   IO_STATE(R_GEN_CONFIG, dma6, serial0)) {
-                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma6);
-                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused);
-               }
-       } else if (info->line == 1) {
-               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma8)) ==
-                   IO_STATE(R_GEN_CONFIG, dma8, serial1)) {
-                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma8);
-                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb);
-               }
-       } else if (info->line == 2) {
-               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma2)) ==
-                   IO_STATE(R_GEN_CONFIG, dma2, serial2)) {
-                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma2);
-                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0);
-               }
-       } else if (info->line == 3) {
-               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma4)) ==
-                   IO_STATE(R_GEN_CONFIG, dma4, serial3)) {
-                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma4);
-                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, par1);
-               }
-       }
-       *R_GEN_CONFIG = genconfig_shadow;
-       local_irq_restore(flags);
-}
-
-
-static void e100_enable_txdma_channel(struct e100_serial *info)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-       DFLOW(DEBUG_LOG(info->line, "enable_txdma_channel %i\n", info->line));
-       /* Enable output DMA channel for the serial port in question */
-       if (info->line == 0) {
-               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma6);
-               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, serial0);
-       } else if (info->line == 1) {
-               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma8);
-               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, serial1);
-       } else if (info->line == 2) {
-               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma2);
-               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, serial2);
-       } else if (info->line == 3) {
-               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma4);
-               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, serial3);
-       }
-       *R_GEN_CONFIG = genconfig_shadow;
-       local_irq_restore(flags);
-}
-
-static void e100_disable_rxdma_channel(struct e100_serial *info)
-{
-       unsigned long flags;
-
-       /* Disable input DMA channel for the serial port in question
-        * ( set to something other than serialX)
-        */
-       local_irq_save(flags);
-       if (info->line == 0) {
-               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma7)) ==
-                   IO_STATE(R_GEN_CONFIG, dma7, serial0)) {
-                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma7);
-                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma7, unused);
-               }
-       } else if (info->line == 1) {
-               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma9)) ==
-                   IO_STATE(R_GEN_CONFIG, dma9, serial1)) {
-                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma9);
-                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, usb);
-               }
-       } else if (info->line == 2) {
-               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma3)) ==
-                   IO_STATE(R_GEN_CONFIG, dma3, serial2)) {
-                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma3);
-                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, par0);
-               }
-       } else if (info->line == 3) {
-               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma5)) ==
-                   IO_STATE(R_GEN_CONFIG, dma5, serial3)) {
-                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma5);
-                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, par1);
-               }
-       }
-       *R_GEN_CONFIG = genconfig_shadow;
-       local_irq_restore(flags);
-}
-
-
-static void e100_enable_rxdma_channel(struct e100_serial *info)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-       /* Enable input DMA channel for the serial port in question */
-       if (info->line == 0) {
-               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma7);
-               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma7, serial0);
-       } else if (info->line == 1) {
-               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma9);
-               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, serial1);
-       } else if (info->line == 2) {
-               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma3);
-               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, serial2);
-       } else if (info->line == 3) {
-               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma5);
-               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, serial3);
-       }
-       *R_GEN_CONFIG = genconfig_shadow;
-       local_irq_restore(flags);
-}
-
-#ifdef SERIAL_HANDLE_EARLY_ERRORS
-/* in order to detect and fix errors on the first byte
-   we have to use the serial interrupts as well. */
-
-static inline void
-e100_disable_serial_data_irq(struct e100_serial *info)
-{
-#ifdef SERIAL_DEBUG_INTR
-       printk("ser_irq(%d): 0\n",info->line);
-#endif
-       DINTR1(DEBUG_LOG(info->line,"IRQ disable data_irq %i\n", info->line));
-       *R_IRQ_MASK1_CLR = (1U << (8+2*info->line));
-}
-
-static inline void
-e100_enable_serial_data_irq(struct e100_serial *info)
-{
-#ifdef SERIAL_DEBUG_INTR
-       printk("ser_irq(%d): 1\n",info->line);
-       printk("**** %d = %d\n",
-              (8+2*info->line),
-              (1U << (8+2*info->line)));
-#endif
-       DINTR1(DEBUG_LOG(info->line,"IRQ enable data_irq %i\n", info->line));
-       *R_IRQ_MASK1_SET = (1U << (8+2*info->line));
-}
-#endif
-
-static inline void
-e100_disable_serial_tx_ready_irq(struct e100_serial *info)
-{
-#ifdef SERIAL_DEBUG_INTR
-       printk("ser_tx_irq(%d): 0\n",info->line);
-#endif
-       DINTR1(DEBUG_LOG(info->line,"IRQ disable ready_irq %i\n", info->line));
-       *R_IRQ_MASK1_CLR = (1U << (8+1+2*info->line));
-}
-
-static inline void
-e100_enable_serial_tx_ready_irq(struct e100_serial *info)
-{
-#ifdef SERIAL_DEBUG_INTR
-       printk("ser_tx_irq(%d): 1\n",info->line);
-       printk("**** %d = %d\n",
-              (8+1+2*info->line),
-              (1U << (8+1+2*info->line)));
-#endif
-       DINTR2(DEBUG_LOG(info->line,"IRQ enable ready_irq %i\n", info->line));
-       *R_IRQ_MASK1_SET = (1U << (8+1+2*info->line));
-}
-
-static inline void e100_enable_rx_irq(struct e100_serial *info)
-{
-       if (info->uses_dma_in)
-               e100_enable_rxdma_irq(info);
-       else
-               e100_enable_serial_data_irq(info);
-}
-static inline void e100_disable_rx_irq(struct e100_serial *info)
-{
-       if (info->uses_dma_in)
-               e100_disable_rxdma_irq(info);
-       else
-               e100_disable_serial_data_irq(info);
-}
-
-#if defined(CONFIG_ETRAX_RS485)
-/* Enable RS-485 mode on selected port. This is UGLY. */
-static int
-e100_enable_rs485(struct tty_struct *tty, struct serial_rs485 *r)
-{
-       struct e100_serial * info = (struct e100_serial *)tty->driver_data;
-
-#if defined(CONFIG_ETRAX_RS485_ON_PA)
-       *R_PORT_PA_DATA = port_pa_data_shadow |= (1 << rs485_pa_bit);
-#endif
-#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
-       REG_SHADOW_SET(R_PORT_G_DATA,  port_g_data_shadow,
-                      rs485_port_g_bit, 1);
-#endif
-#if defined(CONFIG_ETRAX_RS485_LTC1387)
-       REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
-                      CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 1);
-       REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
-                      CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 1);
-#endif
-
-       info->rs485 = *r;
-
-       /* Maximum delay before RTS equal to 1000 */
-       if (info->rs485.delay_rts_before_send >= 1000)
-               info->rs485.delay_rts_before_send = 1000;
-
-/*     printk("rts: on send = %i, after = %i, enabled = %i",
-                   info->rs485.rts_on_send,
-                   info->rs485.rts_after_sent,
-                   info->rs485.enabled
-       );
-*/
-       return 0;
-}
-
-static int
-e100_write_rs485(struct tty_struct *tty,
-                 const unsigned char *buf, int count)
-{
-       struct e100_serial * info = (struct e100_serial *)tty->driver_data;
-       int old_value = (info->rs485.flags) & SER_RS485_ENABLED;
-
-       /* rs485 is always implicitly enabled if we're using the ioctl()
-        * but it doesn't have to be set in the serial_rs485
-        * (to be backward compatible with old apps)
-        * So we store, set and restore it.
-        */
-       info->rs485.flags |= SER_RS485_ENABLED;
-       /* rs_write now deals with RS485 if enabled */
-       count = rs_write(tty, buf, count);
-       if (!old_value)
-               info->rs485.flags &= ~(SER_RS485_ENABLED);
-       return count;
-}
-
-#ifdef CONFIG_ETRAX_FAST_TIMER
-/* Timer function to toggle RTS when using FAST_TIMER */
-static void rs485_toggle_rts_timer_function(unsigned long data)
-{
-       struct e100_serial *info = (struct e100_serial *)data;
-
-       fast_timers_rs485[info->line].function = NULL;
-       e100_rts(info, (info->rs485.flags & SER_RS485_RTS_AFTER_SEND));
-#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
-       e100_enable_rx(info);
-       e100_enable_rx_irq(info);
-#endif
-}
-#endif
-#endif /* CONFIG_ETRAX_RS485 */
-
-/*
- * ------------------------------------------------------------
- * rs_stop() and rs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter using the XOFF registers, as necessary.
- * ------------------------------------------------------------
- */
-
-static void
-rs_stop(struct tty_struct *tty)
-{
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-       if (info) {
-               unsigned long flags;
-               unsigned long xoff;
-
-               local_irq_save(flags);
-               DFLOW(DEBUG_LOG(info->line, "XOFF rs_stop xmit %i\n",
-                               CIRC_CNT(info->xmit.head,
-                                        info->xmit.tail,SERIAL_XMIT_SIZE)));
-
-               xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char,
-                               STOP_CHAR(info->port.tty));
-               xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop);
-               if (tty->termios->c_iflag & IXON ) {
-                       xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
-               }
-
-               *((unsigned long *)&info->ioport[REG_XOFF]) = xoff;
-               local_irq_restore(flags);
-       }
-}
-
-static void
-rs_start(struct tty_struct *tty)
-{
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-       if (info) {
-               unsigned long flags;
-               unsigned long xoff;
-
-               local_irq_save(flags);
-               DFLOW(DEBUG_LOG(info->line, "XOFF rs_start xmit %i\n",
-                               CIRC_CNT(info->xmit.head,
-                                        info->xmit.tail,SERIAL_XMIT_SIZE)));
-               xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty));
-               xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
-               if (tty->termios->c_iflag & IXON ) {
-                       xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
-               }
-
-               *((unsigned long *)&info->ioport[REG_XOFF]) = xoff;
-               if (!info->uses_dma_out &&
-                   info->xmit.head != info->xmit.tail && info->xmit.buf)
-                       e100_enable_serial_tx_ready_irq(info);
-
-               local_irq_restore(flags);
-       }
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Here starts the interrupt handling routines.  All of the following
- * subroutines are declared as inline and are folded into
- * rs_interrupt().  They were separated out for readability's sake.
- *
- * Note: rs_interrupt() is a "fast" interrupt, which means that it
- * runs with interrupts turned off.  People who may want to modify
- * rs_interrupt() should try to keep the interrupt handler as fast as
- * possible.  After you are done making modifications, it is not a bad
- * idea to do:
- *
- * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
- *
- * and look at the resulting assemble code in serial.s.
- *
- *                             - Ted Ts'o (tytso@mit.edu), 7-Mar-93
- * -----------------------------------------------------------------------
- */
-
-/*
- * This routine is used by the interrupt handler to schedule
- * processing in the software interrupt portion of the driver.
- */
-static void rs_sched_event(struct e100_serial *info, int event)
-{
-       if (info->event & (1 << event))
-               return;
-       info->event |= 1 << event;
-       schedule_work(&info->work);
-}
-
-/* The output DMA channel is free - use it to send as many chars as possible
- * NOTES:
- *   We don't pay attention to info->x_char, which means if the TTY wants to
- *   use XON/XOFF it will set info->x_char but we won't send any X char!
- *
- *   To implement this, we'd just start a DMA send of 1 byte pointing at a
- *   buffer containing the X char, and skip updating xmit. We'd also have to
- *   check if the last sent char was the X char when we enter this function
- *   the next time, to avoid updating xmit with the sent X value.
- */
-
-static void
-transmit_chars_dma(struct e100_serial *info)
-{
-       unsigned int c, sentl;
-       struct etrax_dma_descr *descr;
-
-#ifdef CONFIG_SVINTO_SIM
-       /* This will output too little if tail is not 0 always since
-        * we don't reloop to send the other part. Anyway this SHOULD be a
-        * no-op - transmit_chars_dma would never really be called during sim
-        * since rs_write does not write into the xmit buffer then.
-        */
-       if (info->xmit.tail)
-               printk("Error in serial.c:transmit_chars-dma(), tail!=0\n");
-       if (info->xmit.head != info->xmit.tail) {
-               SIMCOUT(info->xmit.buf + info->xmit.tail,
-                       CIRC_CNT(info->xmit.head,
-                                info->xmit.tail,
-                                SERIAL_XMIT_SIZE));
-               info->xmit.head = info->xmit.tail;  /* move back head */
-               info->tr_running = 0;
-       }
-       return;
-#endif
-       /* acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */
-       *info->oclrintradr =
-               IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
-               IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
-
-#ifdef SERIAL_DEBUG_INTR
-       if (info->line == SERIAL_DEBUG_LINE)
-               printk("tc\n");
-#endif
-       if (!info->tr_running) {
-               /* weirdo... we shouldn't get here! */
-               printk(KERN_WARNING "Achtung: transmit_chars_dma with !tr_running\n");
-               return;
-       }
-
-       descr = &info->tr_descr;
-
-       /* first get the amount of bytes sent during the last DMA transfer,
-          and update xmit accordingly */
-
-       /* if the stop bit was not set, all data has been sent */
-       if (!(descr->status & d_stop)) {
-               sentl = descr->sw_len;
-       } else
-               /* otherwise we find the amount of data sent here */
-               sentl = descr->hw_len;
-
-       DFLOW(DEBUG_LOG(info->line, "TX %i done\n", sentl));
-
-       /* update stats */
-       info->icount.tx += sentl;
-
-       /* update xmit buffer */
-       info->xmit.tail = (info->xmit.tail + sentl) & (SERIAL_XMIT_SIZE - 1);
-
-       /* if there is only a few chars left in the buf, wake up the blocked
-          write if any */
-       if (CIRC_CNT(info->xmit.head,
-                    info->xmit.tail,
-                    SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
-               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-
-       /* find out the largest amount of consecutive bytes we want to send now */
-
-       c = CIRC_CNT_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
-
-       /* Don't send all in one DMA transfer - divide it so we wake up
-        * application before all is sent
-        */
-
-       if (c >= 4*WAKEUP_CHARS)
-               c = c/2;
-
-       if (c <= 0) {
-               /* our job here is done, don't schedule any new DMA transfer */
-               info->tr_running = 0;
-
-#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER)
-               if (info->rs485.flags & SER_RS485_ENABLED) {
-                       /* Set a short timer to toggle RTS */
-                       start_one_shot_timer(&fast_timers_rs485[info->line],
-                                            rs485_toggle_rts_timer_function,
-                                            (unsigned long)info,
-                                            info->char_time_usec*2,
-                                            "RS-485");
-               }
-#endif /* RS485 */
-               return;
-       }
-
-       /* ok we can schedule a dma send of c chars starting at info->xmit.tail */
-       /* set up the descriptor correctly for output */
-       DFLOW(DEBUG_LOG(info->line, "TX %i\n", c));
-       descr->ctrl = d_int | d_eol | d_wait; /* Wait needed for tty_wait_until_sent() */
-       descr->sw_len = c;
-       descr->buf = virt_to_phys(info->xmit.buf + info->xmit.tail);
-       descr->status = 0;
-
-       *info->ofirstadr = virt_to_phys(descr); /* write to R_DMAx_FIRST */
-       *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start);
-
-       /* DMA is now running (hopefully) */
-} /* transmit_chars_dma */
-
-static void
-start_transmit(struct e100_serial *info)
-{
-#if 0
-       if (info->line == SERIAL_DEBUG_LINE)
-               printk("x\n");
-#endif
-
-       info->tr_descr.sw_len = 0;
-       info->tr_descr.hw_len = 0;
-       info->tr_descr.status = 0;
-       info->tr_running = 1;
-       if (info->uses_dma_out)
-               transmit_chars_dma(info);
-       else
-               e100_enable_serial_tx_ready_irq(info);
-} /* start_transmit */
-
-#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
-static int serial_fast_timer_started = 0;
-static int serial_fast_timer_expired = 0;
-static void flush_timeout_function(unsigned long data);
-#define START_FLUSH_FAST_TIMER_TIME(info, string, usec) {\
-  unsigned long timer_flags; \
-  local_irq_save(timer_flags); \
-  if (fast_timers[info->line].function == NULL) { \
-    serial_fast_timer_started++; \
-    TIMERD(DEBUG_LOG(info->line, "start_timer %i ", info->line)); \
-    TIMERD(DEBUG_LOG(info->line, "num started: %i\n", serial_fast_timer_started)); \
-    start_one_shot_timer(&fast_timers[info->line], \
-                         flush_timeout_function, \
-                         (unsigned long)info, \
-                         (usec), \
-                         string); \
-  } \
-  else { \
-    TIMERD(DEBUG_LOG(info->line, "timer %i already running\n", info->line)); \
-  } \
-  local_irq_restore(timer_flags); \
-}
-#define START_FLUSH_FAST_TIMER(info, string) START_FLUSH_FAST_TIMER_TIME(info, string, info->flush_time_usec)
-
-#else
-#define START_FLUSH_FAST_TIMER_TIME(info, string, usec)
-#define START_FLUSH_FAST_TIMER(info, string)
-#endif
-
-static struct etrax_recv_buffer *
-alloc_recv_buffer(unsigned int size)
-{
-       struct etrax_recv_buffer *buffer;
-
-       if (!(buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC)))
-               return NULL;
-
-       buffer->next = NULL;
-       buffer->length = 0;
-       buffer->error = TTY_NORMAL;
-
-       return buffer;
-}
-
-static void
-append_recv_buffer(struct e100_serial *info, struct etrax_recv_buffer *buffer)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       if (!info->first_recv_buffer)
-               info->first_recv_buffer = buffer;
-       else
-               info->last_recv_buffer->next = buffer;
-
-       info->last_recv_buffer = buffer;
-
-       info->recv_cnt += buffer->length;
-       if (info->recv_cnt > info->max_recv_cnt)
-               info->max_recv_cnt = info->recv_cnt;
-
-       local_irq_restore(flags);
-}
-
-static int
-add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char flag)
-{
-       struct etrax_recv_buffer *buffer;
-       if (info->uses_dma_in) {
-               if (!(buffer = alloc_recv_buffer(4)))
-                       return 0;
-
-               buffer->length = 1;
-               buffer->error = flag;
-               buffer->buffer[0] = data;
-
-               append_recv_buffer(info, buffer);
-
-               info->icount.rx++;
-       } else {
-               struct tty_struct *tty = info->port.tty;
-               tty_insert_flip_char(tty, data, flag);
-               info->icount.rx++;
-       }
-
-       return 1;
-}
-
-static unsigned int handle_descr_data(struct e100_serial *info,
-                                     struct etrax_dma_descr *descr,
-                                     unsigned int recvl)
-{
-       struct etrax_recv_buffer *buffer = phys_to_virt(descr->buf) - sizeof *buffer;
-
-       if (info->recv_cnt + recvl > 65536) {
-               printk(KERN_CRIT
-                      "%s: Too much pending incoming serial data! Dropping %u bytes.\n", __func__, recvl);
-               return 0;
-       }
-
-       buffer->length = recvl;
-
-       if (info->errorcode == ERRCODE_SET_BREAK)
-               buffer->error = TTY_BREAK;
-       info->errorcode = 0;
-
-       append_recv_buffer(info, buffer);
-
-       if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))
-               panic("%s: Failed to allocate memory for receive buffer!\n", __func__);
-
-       descr->buf = virt_to_phys(buffer->buffer);
-
-       return recvl;
-}
-
-static unsigned int handle_all_descr_data(struct e100_serial *info)
-{
-       struct etrax_dma_descr *descr;
-       unsigned int recvl;
-       unsigned int ret = 0;
-
-       while (1)
-       {
-               descr = &info->rec_descr[info->cur_rec_descr];
-
-               if (descr == phys_to_virt(*info->idescradr))
-                       break;
-
-               if (++info->cur_rec_descr == SERIAL_RECV_DESCRIPTORS)
-                       info->cur_rec_descr = 0;
-
-               /* find out how many bytes were read */
-
-               /* if the eop bit was not set, all data has been received */
-               if (!(descr->status & d_eop)) {
-                       recvl = descr->sw_len;
-               } else {
-                       /* otherwise we find the amount of data received here */
-                       recvl = descr->hw_len;
-               }
-
-               /* Reset the status information */
-               descr->status = 0;
-
-               DFLOW(  DEBUG_LOG(info->line, "RX %lu\n", recvl);
-                       if (info->port.tty->stopped) {
-                               unsigned char *buf = phys_to_virt(descr->buf);
-                               DEBUG_LOG(info->line, "rx 0x%02X\n", buf[0]);
-                               DEBUG_LOG(info->line, "rx 0x%02X\n", buf[1]);
-                               DEBUG_LOG(info->line, "rx 0x%02X\n", buf[2]);
-                       }
-                       );
-
-               /* update stats */
-               info->icount.rx += recvl;
-
-               ret += handle_descr_data(info, descr, recvl);
-       }
-
-       return ret;
-}
-
-static void receive_chars_dma(struct e100_serial *info)
-{
-       struct tty_struct *tty;
-       unsigned char rstat;
-
-#ifdef CONFIG_SVINTO_SIM
-       /* No receive in the simulator.  Will probably be when the rest of
-        * the serial interface works, and this piece will just be removed.
-        */
-       return;
-#endif
-
-       /* Acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */
-       *info->iclrintradr =
-               IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
-               IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
-
-       tty = info->port.tty;
-       if (!tty) /* Something wrong... */
-               return;
-
-#ifdef SERIAL_HANDLE_EARLY_ERRORS
-       if (info->uses_dma_in)
-               e100_enable_serial_data_irq(info);
-#endif
-
-       if (info->errorcode == ERRCODE_INSERT_BREAK)
-               add_char_and_flag(info, '\0', TTY_BREAK);
-
-       handle_all_descr_data(info);
-
-       /* Read the status register to detect errors */
-       rstat = info->ioport[REG_STATUS];
-       if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) {
-               DFLOW(DEBUG_LOG(info->line, "XOFF detect stat %x\n", rstat));
-       }
-
-       if (rstat & SER_ERROR_MASK) {
-               /* If we got an error, we must reset it by reading the
-                * data_in field
-                */
-               unsigned char data = info->ioport[REG_DATA];
-
-               PROCSTAT(ser_stat[info->line].errors_cnt++);
-               DEBUG_LOG(info->line, "#dERR: s d 0x%04X\n",
-                         ((rstat & SER_ERROR_MASK) << 8) | data);
-
-               if (rstat & SER_PAR_ERR_MASK)
-                       add_char_and_flag(info, data, TTY_PARITY);
-               else if (rstat & SER_OVERRUN_MASK)
-                       add_char_and_flag(info, data, TTY_OVERRUN);
-               else if (rstat & SER_FRAMING_ERR_MASK)
-                       add_char_and_flag(info, data, TTY_FRAME);
-       }
-
-       START_FLUSH_FAST_TIMER(info, "receive_chars");
-
-       /* Restart the receiving DMA */
-       *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
-}
-
-static int start_recv_dma(struct e100_serial *info)
-{
-       struct etrax_dma_descr *descr = info->rec_descr;
-       struct etrax_recv_buffer *buffer;
-        int i;
-
-       /* Set up the receiving descriptors */
-       for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) {
-               if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))
-                       panic("%s: Failed to allocate memory for receive buffer!\n", __func__);
-
-               descr[i].ctrl = d_int;
-               descr[i].buf = virt_to_phys(buffer->buffer);
-               descr[i].sw_len = SERIAL_DESCR_BUF_SIZE;
-               descr[i].hw_len = 0;
-               descr[i].status = 0;
-               descr[i].next = virt_to_phys(&descr[i+1]);
-       }
-
-       /* Link the last descriptor to the first */
-       descr[i-1].next = virt_to_phys(&descr[0]);
-
-       /* Start with the first descriptor in the list */
-       info->cur_rec_descr = 0;
-
-       /* Start the DMA */
-       *info->ifirstadr = virt_to_phys(&descr[info->cur_rec_descr]);
-       *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start);
-
-       /* Input DMA should be running now */
-       return 1;
-}
-
-static void
-start_receive(struct e100_serial *info)
-{
-#ifdef CONFIG_SVINTO_SIM
-       /* No receive in the simulator.  Will probably be when the rest of
-        * the serial interface works, and this piece will just be removed.
-        */
-       return;
-#endif
-       if (info->uses_dma_in) {
-               /* reset the input dma channel to be sure it works */
-
-               *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
-               while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
-                      IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
-
-               start_recv_dma(info);
-       }
-}
-
-
-/* the bits in the MASK2 register are laid out like this:
-   DMAI_EOP DMAI_DESCR DMAO_EOP DMAO_DESCR
-   where I is the input channel and O is the output channel for the port.
-   info->irq is the bit number for the DMAO_DESCR so to check the others we
-   shift info->irq to the left.
-*/
-
-/* dma output channel interrupt handler
-   this interrupt is called from DMA2(ser2), DMA4(ser3), DMA6(ser0) or
-   DMA8(ser1) when they have finished a descriptor with the intr flag set.
-*/
-
-static irqreturn_t
-tr_interrupt(int irq, void *dev_id)
-{
-       struct e100_serial *info;
-       unsigned long ireg;
-       int i;
-       int handled = 0;
-
-#ifdef CONFIG_SVINTO_SIM
-       /* No receive in the simulator.  Will probably be when the rest of
-        * the serial interface works, and this piece will just be removed.
-        */
-       {
-               const char *s = "What? tr_interrupt in simulator??\n";
-               SIMCOUT(s,strlen(s));
-       }
-       return IRQ_HANDLED;
-#endif
-
-       /* find out the line that caused this irq and get it from rs_table */
-
-       ireg = *R_IRQ_MASK2_RD;  /* get the active irq bits for the dma channels */
-
-       for (i = 0; i < NR_PORTS; i++) {
-               info = rs_table + i;
-               if (!info->enabled || !info->uses_dma_out)
-                       continue;
-               /* check for dma_descr (don't need to check for dma_eop in output dma for serial */
-               if (ireg & info->irq) {
-                       handled = 1;
-                       /* we can send a new dma bunch. make it so. */
-                       DINTR2(DEBUG_LOG(info->line, "tr_interrupt %i\n", i));
-                       /* Read jiffies_usec first,
-                        * we want this time to be as late as possible
-                        */
-                       PROCSTAT(ser_stat[info->line].tx_dma_ints++);
-                       info->last_tx_active_usec = GET_JIFFIES_USEC();
-                       info->last_tx_active = jiffies;
-                       transmit_chars_dma(info);
-               }
-
-               /* FIXME: here we should really check for a change in the
-                  status lines and if so call status_handle(info) */
-       }
-       return IRQ_RETVAL(handled);
-} /* tr_interrupt */
-
-/* dma input channel interrupt handler */
-
-static irqreturn_t
-rec_interrupt(int irq, void *dev_id)
-{
-       struct e100_serial *info;
-       unsigned long ireg;
-       int i;
-       int handled = 0;
-
-#ifdef CONFIG_SVINTO_SIM
-       /* No receive in the simulator.  Will probably be when the rest of
-        * the serial interface works, and this piece will just be removed.
-        */
-       {
-               const char *s = "What? rec_interrupt in simulator??\n";
-               SIMCOUT(s,strlen(s));
-       }
-       return IRQ_HANDLED;
-#endif
-
-       /* find out the line that caused this irq and get it from rs_table */
-
-       ireg = *R_IRQ_MASK2_RD;  /* get the active irq bits for the dma channels */
-
-       for (i = 0; i < NR_PORTS; i++) {
-               info = rs_table + i;
-               if (!info->enabled || !info->uses_dma_in)
-                       continue;
-               /* check for both dma_eop and dma_descr for the input dma channel */
-               if (ireg & ((info->irq << 2) | (info->irq << 3))) {
-                       handled = 1;
-                       /* we have received something */
-                       receive_chars_dma(info);
-               }
-
-               /* FIXME: here we should really check for a change in the
-                  status lines and if so call status_handle(info) */
-       }
-       return IRQ_RETVAL(handled);
-} /* rec_interrupt */
-
-static int force_eop_if_needed(struct e100_serial *info)
-{
-       /* We check data_avail bit to determine if data has
-        * arrived since last time
-        */
-       unsigned char rstat = info->ioport[REG_STATUS];
-
-       /* error or datavail? */
-       if (rstat & SER_ERROR_MASK) {
-               /* Some error has occurred. If there has been valid data, an
-                * EOP interrupt will be made automatically. If no data, the
-                * normal ser_interrupt should be enabled and handle it.
-                * So do nothing!
-                */
-               DEBUG_LOG(info->line, "timeout err: rstat 0x%03X\n",
-                         rstat | (info->line << 8));
-               return 0;
-       }
-
-       if (rstat & SER_DATA_AVAIL_MASK) {
-               /* Ok data, no error, count it */
-               TIMERD(DEBUG_LOG(info->line, "timeout: rstat 0x%03X\n",
-                         rstat | (info->line << 8)));
-               /* Read data to clear status flags */
-               (void)info->ioport[REG_DATA];
-
-               info->forced_eop = 0;
-               START_FLUSH_FAST_TIMER(info, "magic");
-               return 0;
-       }
-
-       /* hit the timeout, force an EOP for the input
-        * dma channel if we haven't already
-        */
-       if (!info->forced_eop) {
-               info->forced_eop = 1;
-               PROCSTAT(ser_stat[info->line].timeout_flush_cnt++);
-               TIMERD(DEBUG_LOG(info->line, "timeout EOP %i\n", info->line));
-               FORCE_EOP(info);
-       }
-
-       return 1;
-}
-
-static void flush_to_flip_buffer(struct e100_serial *info)
-{
-       struct tty_struct *tty;
-       struct etrax_recv_buffer *buffer;
-       unsigned long flags;
-
-       local_irq_save(flags);
-       tty = info->port.tty;
-
-       if (!tty) {
-               local_irq_restore(flags);
-               return;
-       }
-
-       while ((buffer = info->first_recv_buffer) != NULL) {
-               unsigned int count = buffer->length;
-
-               tty_insert_flip_string(tty, buffer->buffer, count);
-               info->recv_cnt -= count;
-
-               if (count == buffer->length) {
-                       info->first_recv_buffer = buffer->next;
-                       kfree(buffer);
-               } else {
-                       buffer->length -= count;
-                       memmove(buffer->buffer, buffer->buffer + count, buffer->length);
-                       buffer->error = TTY_NORMAL;
-               }
-       }
-
-       if (!info->first_recv_buffer)
-               info->last_recv_buffer = NULL;
-
-       local_irq_restore(flags);
-
-       /* This includes a check for low-latency */
-       tty_flip_buffer_push(tty);
-}
-
-static void check_flush_timeout(struct e100_serial *info)
-{
-       /* Flip what we've got (if we can) */
-       flush_to_flip_buffer(info);
-
-       /* We might need to flip later, but not to fast
-        * since the system is busy processing input... */
-       if (info->first_recv_buffer)
-               START_FLUSH_FAST_TIMER_TIME(info, "flip", 2000);
-
-       /* Force eop last, since data might have come while we're processing
-        * and if we started the slow timer above, we won't start a fast
-        * below.
-        */
-       force_eop_if_needed(info);
-}
-
-#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
-static void flush_timeout_function(unsigned long data)
-{
-       struct e100_serial *info = (struct e100_serial *)data;
-
-       fast_timers[info->line].function = NULL;
-       serial_fast_timer_expired++;
-       TIMERD(DEBUG_LOG(info->line, "flush_timout %i ", info->line));
-       TIMERD(DEBUG_LOG(info->line, "num expired: %i\n", serial_fast_timer_expired));
-       check_flush_timeout(info);
-}
-
-#else
-
-/* dma fifo/buffer timeout handler
-   forces an end-of-packet for the dma input channel if no chars
-   have been received for CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS/100 s.
-*/
-
-static struct timer_list flush_timer;
-
-static void
-timed_flush_handler(unsigned long ptr)
-{
-       struct e100_serial *info;
-       int i;
-
-#ifdef CONFIG_SVINTO_SIM
-       return;
-#endif
-
-       for (i = 0; i < NR_PORTS; i++) {
-               info = rs_table + i;
-               if (info->uses_dma_in)
-                       check_flush_timeout(info);
-       }
-
-       /* restart flush timer */
-       mod_timer(&flush_timer, jiffies + CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS);
-}
-#endif
-
-#ifdef SERIAL_HANDLE_EARLY_ERRORS
-
-/* If there is an error (ie break) when the DMA is running and
- * there are no bytes in the fifo the DMA is stopped and we get no
- * eop interrupt. Thus we have to monitor the first bytes on a DMA
- * transfer, and if it is without error we can turn the serial
- * interrupts off.
- */
-
-/*
-BREAK handling on ETRAX 100:
-ETRAX will generate interrupt although there is no stop bit between the
-characters.
-
-Depending on how long the break sequence is, the end of the breaksequence
-will look differently:
-| indicates start/end of a character.
-
-B= Break character (0x00) with framing error.
-E= Error byte with parity error received after B characters.
-F= "Faked" valid byte received immediately after B characters.
-V= Valid byte
-
-1.
-    B          BL         ___________________________ V
-.._|__________|__________|                           |valid data |
-
-Multiple frame errors with data == 0x00 (B),
-the timing matches up "perfectly" so no extra ending char is detected.
-The RXD pin is 1 in the last interrupt, in that case
-we set info->errorcode = ERRCODE_INSERT_BREAK, but we can't really
-know if another byte will come and this really is case 2. below
-(e.g F=0xFF or 0xFE)
-If RXD pin is 0 we can expect another character (see 2. below).
-
-
-2.
-
-    B          B          E or F__________________..__ V
-.._|__________|__________|______    |                 |valid data
-                          "valid" or
-                          parity error
-
-Multiple frame errors with data == 0x00 (B),
-but the part of the break trigs is interpreted as a start bit (and possibly
-some 0 bits followed by a number of 1 bits and a stop bit).
-Depending on parity settings etc. this last character can be either
-a fake "valid" char (F) or have a parity error (E).
-
-If the character is valid it will be put in the buffer,
-we set info->errorcode = ERRCODE_SET_BREAK so the receive interrupt
-will set the flags so the tty will handle it,
-if it's an error byte it will not be put in the buffer
-and we set info->errorcode = ERRCODE_INSERT_BREAK.
-
-To distinguish a V byte in 1. from an F byte in 2. we keep a timestamp
-of the last faulty char (B) and compares it with the current time:
-If the time elapsed time is less then 2*char_time_usec we will assume
-it's a faked F char and not a Valid char and set
-info->errorcode = ERRCODE_SET_BREAK.
-
-Flaws in the above solution:
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-We use the timer to distinguish a F character from a V character,
-if a V character is to close after the break we might make the wrong decision.
-
-TODO: The break will be delayed until an F or V character is received.
-
-*/
-
-static
-struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info)
-{
-       unsigned long data_read;
-       struct tty_struct *tty = info->port.tty;
-
-       if (!tty) {
-               printk("!NO TTY!\n");
-               return info;
-       }
-
-       /* Read data and status at the same time */
-       data_read = *((unsigned long *)&info->ioport[REG_DATA_STATUS32]);
-more_data:
-       if (data_read & IO_MASK(R_SERIAL0_READ, xoff_detect) ) {
-               DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0));
-       }
-       DINTR2(DEBUG_LOG(info->line, "ser_rx   %c\n", IO_EXTRACT(R_SERIAL0_READ, data_in, data_read)));
-
-       if (data_read & ( IO_MASK(R_SERIAL0_READ, framing_err) |
-                         IO_MASK(R_SERIAL0_READ, par_err) |
-                         IO_MASK(R_SERIAL0_READ, overrun) )) {
-               /* An error */
-               info->last_rx_active_usec = GET_JIFFIES_USEC();
-               info->last_rx_active = jiffies;
-               DINTR1(DEBUG_LOG(info->line, "ser_rx err stat_data %04X\n", data_read));
-               DLOG_INT_TRIG(
-               if (!log_int_trig1_pos) {
-                       log_int_trig1_pos = log_int_pos;
-                       log_int(rdpc(), 0, 0);
-               }
-               );
-
-
-               if ( ((data_read & IO_MASK(R_SERIAL0_READ, data_in)) == 0) &&
-                    (data_read & IO_MASK(R_SERIAL0_READ, framing_err)) ) {
-                       /* Most likely a break, but we get interrupts over and
-                        * over again.
-                        */
-
-                       if (!info->break_detected_cnt) {
-                               DEBUG_LOG(info->line, "#BRK start\n", 0);
-                       }
-                       if (data_read & IO_MASK(R_SERIAL0_READ, rxd)) {
-                               /* The RX pin is high now, so the break
-                                * must be over, but....
-                                * we can't really know if we will get another
-                                * last byte ending the break or not.
-                                * And we don't know if the byte (if any) will
-                                * have an error or look valid.
-                                */
-                               DEBUG_LOG(info->line, "# BL BRK\n", 0);
-                               info->errorcode = ERRCODE_INSERT_BREAK;
-                       }
-                       info->break_detected_cnt++;
-               } else {
-                       /* The error does not look like a break, but could be
-                        * the end of one
-                        */
-                       if (info->break_detected_cnt) {
-                               DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt);
-                               info->errorcode = ERRCODE_INSERT_BREAK;
-                       } else {
-                               unsigned char data = IO_EXTRACT(R_SERIAL0_READ,
-                                       data_in, data_read);
-                               char flag = TTY_NORMAL;
-                               if (info->errorcode == ERRCODE_INSERT_BREAK) {
-                                       struct tty_struct *tty = info->port.tty;
-                                       tty_insert_flip_char(tty, 0, flag);
-                                       info->icount.rx++;
-                               }
-
-                               if (data_read & IO_MASK(R_SERIAL0_READ, par_err)) {
-                                       info->icount.parity++;
-                                       flag = TTY_PARITY;
-                               } else if (data_read & IO_MASK(R_SERIAL0_READ, overrun)) {
-                                       info->icount.overrun++;
-                                       flag = TTY_OVERRUN;
-                               } else if (data_read & IO_MASK(R_SERIAL0_READ, framing_err)) {
-                                       info->icount.frame++;
-                                       flag = TTY_FRAME;
-                               }
-                               tty_insert_flip_char(tty, data, flag);
-                               info->errorcode = 0;
-                       }
-                       info->break_detected_cnt = 0;
-               }
-       } else if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) {
-               /* No error */
-               DLOG_INT_TRIG(
-               if (!log_int_trig1_pos) {
-                       if (log_int_pos >= log_int_size) {
-                               log_int_pos = 0;
-                       }
-                       log_int_trig0_pos = log_int_pos;
-                       log_int(rdpc(), 0, 0);
-               }
-               );
-               tty_insert_flip_char(tty,
-                       IO_EXTRACT(R_SERIAL0_READ, data_in, data_read),
-                       TTY_NORMAL);
-       } else {
-               DEBUG_LOG(info->line, "ser_rx int but no data_avail  %08lX\n", data_read);
-       }
-
-
-       info->icount.rx++;
-       data_read = *((unsigned long *)&info->ioport[REG_DATA_STATUS32]);
-       if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) {
-               DEBUG_LOG(info->line, "ser_rx   %c in loop\n", IO_EXTRACT(R_SERIAL0_READ, data_in, data_read));
-               goto more_data;
-       }
-
-       tty_flip_buffer_push(info->port.tty);
-       return info;
-}
-
-static struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info)
-{
-       unsigned char rstat;
-
-#ifdef SERIAL_DEBUG_INTR
-       printk("Interrupt from serport %d\n", i);
-#endif
-/*     DEBUG_LOG(info->line, "ser_interrupt stat %03X\n", rstat | (i << 8)); */
-       if (!info->uses_dma_in) {
-               return handle_ser_rx_interrupt_no_dma(info);
-       }
-       /* DMA is used */
-       rstat = info->ioport[REG_STATUS];
-       if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) {
-               DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0));
-       }
-
-       if (rstat & SER_ERROR_MASK) {
-               unsigned char data;
-
-               info->last_rx_active_usec = GET_JIFFIES_USEC();
-               info->last_rx_active = jiffies;
-               /* If we got an error, we must reset it by reading the
-                * data_in field
-                */
-               data = info->ioport[REG_DATA];
-               DINTR1(DEBUG_LOG(info->line, "ser_rx!  %c\n", data));
-               DINTR1(DEBUG_LOG(info->line, "ser_rx err stat %02X\n", rstat));
-               if (!data && (rstat & SER_FRAMING_ERR_MASK)) {
-                       /* Most likely a break, but we get interrupts over and
-                        * over again.
-                        */
-
-                       if (!info->break_detected_cnt) {
-                               DEBUG_LOG(info->line, "#BRK start\n", 0);
-                       }
-                       if (rstat & SER_RXD_MASK) {
-                               /* The RX pin is high now, so the break
-                                * must be over, but....
-                                * we can't really know if we will get another
-                                * last byte ending the break or not.
-                                * And we don't know if the byte (if any) will
-                                * have an error or look valid.
-                                */
-                               DEBUG_LOG(info->line, "# BL BRK\n", 0);
-                               info->errorcode = ERRCODE_INSERT_BREAK;
-                       }
-                       info->break_detected_cnt++;
-               } else {
-                       /* The error does not look like a break, but could be
-                        * the end of one
-                        */
-                       if (info->break_detected_cnt) {
-                               DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt);
-                               info->errorcode = ERRCODE_INSERT_BREAK;
-                       } else {
-                               if (info->errorcode == ERRCODE_INSERT_BREAK) {
-                                       info->icount.brk++;
-                                       add_char_and_flag(info, '\0', TTY_BREAK);
-                               }
-
-                               if (rstat & SER_PAR_ERR_MASK) {
-                                       info->icount.parity++;
-                                       add_char_and_flag(info, data, TTY_PARITY);
-                               } else if (rstat & SER_OVERRUN_MASK) {
-                                       info->icount.overrun++;
-                                       add_char_and_flag(info, data, TTY_OVERRUN);
-                               } else if (rstat & SER_FRAMING_ERR_MASK) {
-                                       info->icount.frame++;
-                                       add_char_and_flag(info, data, TTY_FRAME);
-                               }
-
-                               info->errorcode = 0;
-                       }
-                       info->break_detected_cnt = 0;
-                       DEBUG_LOG(info->line, "#iERR s d %04X\n",
-                                 ((rstat & SER_ERROR_MASK) << 8) | data);
-               }
-               PROCSTAT(ser_stat[info->line].early_errors_cnt++);
-       } else { /* It was a valid byte, now let the DMA do the rest */
-               unsigned long curr_time_u = GET_JIFFIES_USEC();
-               unsigned long curr_time = jiffies;
-
-               if (info->break_detected_cnt) {
-                       /* Detect if this character is a new valid char or the
-                        * last char in a break sequence: If LSBits are 0 and
-                        * MSBits are high AND the time is close to the
-                        * previous interrupt we should discard it.
-                        */
-                       long elapsed_usec =
-                         (curr_time - info->last_rx_active) * (1000000/HZ) +
-                         curr_time_u - info->last_rx_active_usec;
-                       if (elapsed_usec < 2*info->char_time_usec) {
-                               DEBUG_LOG(info->line, "FBRK %i\n", info->line);
-                               /* Report as BREAK (error) and let
-                                * receive_chars_dma() handle it
-                                */
-                               info->errorcode = ERRCODE_SET_BREAK;
-                       } else {
-                               DEBUG_LOG(info->line, "Not end of BRK (V)%i\n", info->line);
-                       }
-                       DEBUG_LOG(info->line, "num brk %i\n", info->break_detected_cnt);
-               }
-
-#ifdef SERIAL_DEBUG_INTR
-               printk("** OK, disabling ser_interrupts\n");
-#endif
-               e100_disable_serial_data_irq(info);
-               DINTR2(DEBUG_LOG(info->line, "ser_rx OK %d\n", info->line));
-               info->break_detected_cnt = 0;
-
-               PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++);
-       }
-       /* Restarting the DMA never hurts */
-       *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
-       START_FLUSH_FAST_TIMER(info, "ser_int");
-       return info;
-} /* handle_ser_rx_interrupt */
-
-static void handle_ser_tx_interrupt(struct e100_serial *info)
-{
-       unsigned long flags;
-
-       if (info->x_char) {
-               unsigned char rstat;
-               DFLOW(DEBUG_LOG(info->line, "tx_int: xchar 0x%02X\n", info->x_char));
-               local_irq_save(flags);
-               rstat = info->ioport[REG_STATUS];
-               DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat));
-
-               info->ioport[REG_TR_DATA] = info->x_char;
-               info->icount.tx++;
-               info->x_char = 0;
-               /* We must enable since it is disabled in ser_interrupt */
-               e100_enable_serial_tx_ready_irq(info);
-               local_irq_restore(flags);
-               return;
-       }
-       if (info->uses_dma_out) {
-               unsigned char rstat;
-               int i;
-               /* We only use normal tx interrupt when sending x_char */
-               DFLOW(DEBUG_LOG(info->line, "tx_int: xchar sent\n", 0));
-               local_irq_save(flags);
-               rstat = info->ioport[REG_STATUS];
-               DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat));
-               e100_disable_serial_tx_ready_irq(info);
-               if (info->port.tty->stopped)
-                       rs_stop(info->port.tty);
-               /* Enable the DMA channel and tell it to continue */
-               e100_enable_txdma_channel(info);
-               /* Wait 12 cycles before doing the DMA command */
-               for(i = 6;  i > 0; i--)
-                       nop();
-
-               *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, continue);
-               local_irq_restore(flags);
-               return;
-       }
-       /* Normal char-by-char interrupt */
-       if (info->xmit.head == info->xmit.tail
-           || info->port.tty->stopped
-           || info->port.tty->hw_stopped) {
-               DFLOW(DEBUG_LOG(info->line, "tx_int: stopped %i\n",
-                               info->port.tty->stopped));
-               e100_disable_serial_tx_ready_irq(info);
-               info->tr_running = 0;
-               return;
-       }
-       DINTR2(DEBUG_LOG(info->line, "tx_int %c\n", info->xmit.buf[info->xmit.tail]));
-       /* Send a byte, rs485 timing is critical so turn of ints */
-       local_irq_save(flags);
-       info->ioport[REG_TR_DATA] = info->xmit.buf[info->xmit.tail];
-       info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1);
-       info->icount.tx++;
-       if (info->xmit.head == info->xmit.tail) {
-#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER)
-               if (info->rs485.flags & SER_RS485_ENABLED) {
-                       /* Set a short timer to toggle RTS */
-                       start_one_shot_timer(&fast_timers_rs485[info->line],
-                                            rs485_toggle_rts_timer_function,
-                                            (unsigned long)info,
-                                            info->char_time_usec*2,
-                                            "RS-485");
-               }
-#endif /* RS485 */
-               info->last_tx_active_usec = GET_JIFFIES_USEC();
-               info->last_tx_active = jiffies;
-               e100_disable_serial_tx_ready_irq(info);
-               info->tr_running = 0;
-               DFLOW(DEBUG_LOG(info->line, "tx_int: stop2\n", 0));
-       } else {
-               /* We must enable since it is disabled in ser_interrupt */
-               e100_enable_serial_tx_ready_irq(info);
-       }
-       local_irq_restore(flags);
-
-       if (CIRC_CNT(info->xmit.head,
-                    info->xmit.tail,
-                    SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
-               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-
-} /* handle_ser_tx_interrupt */
-
-/* result of time measurements:
- * RX duration 54-60 us when doing something, otherwise 6-9 us
- * ser_int duration: just sending: 8-15 us normally, up to 73 us
- */
-static irqreturn_t
-ser_interrupt(int irq, void *dev_id)
-{
-       static volatile int tx_started = 0;
-       struct e100_serial *info;
-       int i;
-       unsigned long flags;
-       unsigned long irq_mask1_rd;
-       unsigned long data_mask = (1 << (8+2*0)); /* ser0 data_avail */
-       int handled = 0;
-       static volatile unsigned long reentered_ready_mask = 0;
-
-       local_irq_save(flags);
-       irq_mask1_rd = *R_IRQ_MASK1_RD;
-       /* First handle all rx interrupts with ints disabled */
-       info = rs_table;
-       irq_mask1_rd &= e100_ser_int_mask;
-       for (i = 0; i < NR_PORTS; i++) {
-               /* Which line caused the data irq? */
-               if (irq_mask1_rd & data_mask) {
-                       handled = 1;
-                       handle_ser_rx_interrupt(info);
-               }
-               info += 1;
-               data_mask <<= 2;
-       }
-       /* Handle tx interrupts with interrupts enabled so we
-        * can take care of new data interrupts while transmitting
-        * We protect the tx part with the tx_started flag.
-        * We disable the tr_ready interrupts we are about to handle and
-        * unblock the serial interrupt so new serial interrupts may come.
-        *
-        * If we get a new interrupt:
-        *  - it migth be due to synchronous serial ports.
-        *  - serial irq will be blocked by general irq handler.
-        *  - async data will be handled above (sync will be ignored).
-        *  - tx_started flag will prevent us from trying to send again and
-        *    we will exit fast - no need to unblock serial irq.
-        *  - Next (sync) serial interrupt handler will be runned with
-        *    disabled interrupt due to restore_flags() at end of function,
-        *    so sync handler will not be preempted or reentered.
-        */
-       if (!tx_started) {
-               unsigned long ready_mask;
-               unsigned long
-               tx_started = 1;
-               /* Only the tr_ready interrupts left */
-               irq_mask1_rd &= (IO_MASK(R_IRQ_MASK1_RD, ser0_ready) |
-                                IO_MASK(R_IRQ_MASK1_RD, ser1_ready) |
-                                IO_MASK(R_IRQ_MASK1_RD, ser2_ready) |
-                                IO_MASK(R_IRQ_MASK1_RD, ser3_ready));
-               while (irq_mask1_rd) {
-                       /* Disable those we are about to handle */
-                       *R_IRQ_MASK1_CLR = irq_mask1_rd;
-                       /* Unblock the serial interrupt */
-                       *R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, serial, set);
-
-                       local_irq_enable();
-                       ready_mask = (1 << (8+1+2*0)); /* ser0 tr_ready */
-                       info = rs_table;
-                       for (i = 0; i < NR_PORTS; i++) {
-                               /* Which line caused the ready irq? */
-                               if (irq_mask1_rd & ready_mask) {
-                                       handled = 1;
-                                       handle_ser_tx_interrupt(info);
-                               }
-                               info += 1;
-                               ready_mask <<= 2;
-                       }
-                       /* handle_ser_tx_interrupt enables tr_ready interrupts */
-                       local_irq_disable();
-                       /* Handle reentered TX interrupt */
-                       irq_mask1_rd = reentered_ready_mask;
-               }
-               local_irq_disable();
-               tx_started = 0;
-       } else {
-               unsigned long ready_mask;
-               ready_mask = irq_mask1_rd & (IO_MASK(R_IRQ_MASK1_RD, ser0_ready) |
-                                            IO_MASK(R_IRQ_MASK1_RD, ser1_ready) |
-                                            IO_MASK(R_IRQ_MASK1_RD, ser2_ready) |
-                                            IO_MASK(R_IRQ_MASK1_RD, ser3_ready));
-               if (ready_mask) {
-                       reentered_ready_mask |= ready_mask;
-                       /* Disable those we are about to handle */
-                       *R_IRQ_MASK1_CLR = ready_mask;
-                       DFLOW(DEBUG_LOG(SERIAL_DEBUG_LINE, "ser_int reentered with TX %X\n", ready_mask));
-               }
-       }
-
-       local_irq_restore(flags);
-       return IRQ_RETVAL(handled);
-} /* ser_interrupt */
-#endif
-
-/*
- * -------------------------------------------------------------------
- * Here ends the serial interrupt routines.
- * -------------------------------------------------------------------
- */
-
-/*
- * This routine is used to handle the "bottom half" processing for the
- * serial driver, known also the "software interrupt" processing.
- * This processing is done at the kernel interrupt level, after the
- * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
- * is where time-consuming activities which can not be done in the
- * interrupt driver proper are done; the interrupt driver schedules
- * them using rs_sched_event(), and they get done here.
- */
-static void
-do_softint(struct work_struct *work)
-{
-       struct e100_serial      *info;
-       struct tty_struct       *tty;
-
-       info = container_of(work, struct e100_serial, work);
-
-       tty = info->port.tty;
-       if (!tty)
-               return;
-
-       if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event))
-               tty_wakeup(tty);
-}
-
-static int
-startup(struct e100_serial * info)
-{
-       unsigned long flags;
-       unsigned long xmit_page;
-       int i;
-
-       xmit_page = get_zeroed_page(GFP_KERNEL);
-       if (!xmit_page)
-               return -ENOMEM;
-
-       local_irq_save(flags);
-
-       /* if it was already initialized, skip this */
-
-       if (info->flags & ASYNC_INITIALIZED) {
-               local_irq_restore(flags);
-               free_page(xmit_page);
-               return 0;
-       }
-
-       if (info->xmit.buf)
-               free_page(xmit_page);
-       else
-               info->xmit.buf = (unsigned char *) xmit_page;
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("starting up ttyS%d (xmit_buf 0x%p)...\n", info->line, info->xmit.buf);
-#endif
-
-#ifdef CONFIG_SVINTO_SIM
-       /* Bits and pieces collected from below.  Better to have them
-          in one ifdef:ed clause than to mix in a lot of ifdefs,
-          right? */
-       if (info->port.tty)
-               clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
-
-       info->xmit.head = info->xmit.tail = 0;
-       info->first_recv_buffer = info->last_recv_buffer = NULL;
-       info->recv_cnt = info->max_recv_cnt = 0;
-
-       for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++)
-               info->rec_descr[i].buf = NULL;
-
-       /* No real action in the simulator, but may set info important
-          to ioctl. */
-       change_speed(info);
-#else
-
-       /*
-        * Clear the FIFO buffers and disable them
-        * (they will be reenabled in change_speed())
-        */
-
-       /*
-        * Reset the DMA channels and make sure their interrupts are cleared
-        */
-
-       if (info->dma_in_enabled) {
-               info->uses_dma_in = 1;
-               e100_enable_rxdma_channel(info);
-
-               *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
-
-               /* Wait until reset cycle is complete */
-               while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
-                      IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
-
-               /* Make sure the irqs are cleared */
-               *info->iclrintradr =
-                       IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
-                       IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
-       } else {
-               e100_disable_rxdma_channel(info);
-       }
-
-       if (info->dma_out_enabled) {
-               info->uses_dma_out = 1;
-               e100_enable_txdma_channel(info);
-               *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
-
-               while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) ==
-                      IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
-
-               /* Make sure the irqs are cleared */
-               *info->oclrintradr =
-                       IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
-                       IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
-       } else {
-               e100_disable_txdma_channel(info);
-       }
-
-       if (info->port.tty)
-               clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
-
-       info->xmit.head = info->xmit.tail = 0;
-       info->first_recv_buffer = info->last_recv_buffer = NULL;
-       info->recv_cnt = info->max_recv_cnt = 0;
-
-       for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++)
-               info->rec_descr[i].buf = 0;
-
-       /*
-        * and set the speed and other flags of the serial port
-        * this will start the rx/tx as well
-        */
-#ifdef SERIAL_HANDLE_EARLY_ERRORS
-       e100_enable_serial_data_irq(info);
-#endif
-       change_speed(info);
-
-       /* dummy read to reset any serial errors */
-
-       (void)info->ioport[REG_DATA];
-
-       /* enable the interrupts */
-       if (info->uses_dma_out)
-               e100_enable_txdma_irq(info);
-
-       e100_enable_rx_irq(info);
-
-       info->tr_running = 0; /* to be sure we don't lock up the transmitter */
-
-       /* setup the dma input descriptor and start dma */
-
-       start_receive(info);
-
-       /* for safety, make sure the descriptors last result is 0 bytes written */
-
-       info->tr_descr.sw_len = 0;
-       info->tr_descr.hw_len = 0;
-       info->tr_descr.status = 0;
-
-       /* enable RTS/DTR last */
-
-       e100_rts(info, 1);
-       e100_dtr(info, 1);
-
-#endif /* CONFIG_SVINTO_SIM */
-
-       info->flags |= ASYNC_INITIALIZED;
-
-       local_irq_restore(flags);
-       return 0;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void
-shutdown(struct e100_serial * info)
-{
-       unsigned long flags;
-       struct etrax_dma_descr *descr = info->rec_descr;
-       struct etrax_recv_buffer *buffer;
-       int i;
-
-#ifndef CONFIG_SVINTO_SIM
-       /* shut down the transmitter and receiver */
-       DFLOW(DEBUG_LOG(info->line, "shutdown %i\n", info->line));
-       e100_disable_rx(info);
-       info->ioport[REG_TR_CTRL] = (info->tx_ctrl &= ~0x40);
-
-       /* disable interrupts, reset dma channels */
-       if (info->uses_dma_in) {
-               e100_disable_rxdma_irq(info);
-               *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
-               info->uses_dma_in = 0;
-       } else {
-               e100_disable_serial_data_irq(info);
-       }
-
-       if (info->uses_dma_out) {
-               e100_disable_txdma_irq(info);
-               info->tr_running = 0;
-               *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
-               info->uses_dma_out = 0;
-       } else {
-               e100_disable_serial_tx_ready_irq(info);
-               info->tr_running = 0;
-       }
-
-#endif /* CONFIG_SVINTO_SIM */
-
-       if (!(info->flags & ASYNC_INITIALIZED))
-               return;
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("Shutting down serial port %d (irq %d)....\n", info->line,
-              info->irq);
-#endif
-
-       local_irq_save(flags);
-
-       if (info->xmit.buf) {
-               free_page((unsigned long)info->xmit.buf);
-               info->xmit.buf = NULL;
-       }
-
-       for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++)
-               if (descr[i].buf) {
-                       buffer = phys_to_virt(descr[i].buf) - sizeof *buffer;
-                       kfree(buffer);
-                       descr[i].buf = 0;
-               }
-
-       if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) {
-               /* hang up DTR and RTS if HUPCL is enabled */
-               e100_dtr(info, 0);
-               e100_rts(info, 0); /* could check CRTSCTS before doing this */
-       }
-
-       if (info->port.tty)
-               set_bit(TTY_IO_ERROR, &info->port.tty->flags);
-
-       info->flags &= ~ASYNC_INITIALIZED;
-       local_irq_restore(flags);
-}
-
-
-/* change baud rate and other assorted parameters */
-
-static void
-change_speed(struct e100_serial *info)
-{
-       unsigned int cflag;
-       unsigned long xoff;
-       unsigned long flags;
-       /* first some safety checks */
-
-       if (!info->port.tty || !info->port.tty->termios)
-               return;
-       if (!info->ioport)
-               return;
-
-       cflag = info->port.tty->termios->c_cflag;
-
-       /* possibly, the tx/rx should be disabled first to do this safely */
-
-       /* change baud-rate and write it to the hardware */
-       if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) {
-               /* Special baudrate */
-               u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */
-               unsigned long alt_source =
-                               IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, normal) |
-                               IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal);
-               /* R_ALT_SER_BAUDRATE selects the source */
-               DBAUD(printk("Custom baudrate: baud_base/divisor %lu/%i\n",
-                      (unsigned long)info->baud_base, info->custom_divisor));
-               if (info->baud_base == SERIAL_PRESCALE_BASE) {
-                       /* 0, 2-65535 (0=65536) */
-                       u16 divisor = info->custom_divisor;
-                       /* R_SERIAL_PRESCALE (upper 16 bits of R_CLOCK_PRESCALE) */
-                       /* baudrate is 3.125MHz/custom_divisor */
-                       alt_source =
-                               IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, prescale) |
-                               IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, prescale);
-                       alt_source = 0x11;
-                       DBAUD(printk("Writing SERIAL_PRESCALE: divisor %i\n", divisor));
-                       *R_SERIAL_PRESCALE = divisor;
-                       info->baud = SERIAL_PRESCALE_BASE/divisor;
-               }
-#ifdef CONFIG_ETRAX_EXTERN_PB6CLK_ENABLED
-               else if ((info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8 &&
-                         info->custom_divisor == 1) ||
-                        (info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ &&
-                         info->custom_divisor == 8)) {
-                               /* ext_clk selected */
-                               alt_source =
-                                       IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, extern) |
-                                       IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, extern);
-                               DBAUD(printk("using external baudrate: %lu\n", CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8));
-                               info->baud = CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8;
-                       }
-#endif
-               else
-               {
-                       /* Bad baudbase, we don't support using timer0
-                        * for baudrate.
-                        */
-                       printk(KERN_WARNING "Bad baud_base/custom_divisor: %lu/%i\n",
-                              (unsigned long)info->baud_base, info->custom_divisor);
-               }
-               r_alt_ser_baudrate_shadow &= ~mask;
-               r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8));
-               *R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow;
-       } else {
-               /* Normal baudrate */
-               /* Make sure we use normal baudrate */
-               u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */
-               unsigned long alt_source =
-                       IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, normal) |
-                       IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal);
-               r_alt_ser_baudrate_shadow &= ~mask;
-               r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8));
-#ifndef CONFIG_SVINTO_SIM
-               *R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow;
-#endif /* CONFIG_SVINTO_SIM */
-
-               info->baud = cflag_to_baud(cflag);
-#ifndef CONFIG_SVINTO_SIM
-               info->ioport[REG_BAUD] = cflag_to_etrax_baud(cflag);
-#endif /* CONFIG_SVINTO_SIM */
-       }
-
-#ifndef CONFIG_SVINTO_SIM
-       /* start with default settings and then fill in changes */
-       local_irq_save(flags);
-       /* 8 bit, no/even parity */
-       info->rx_ctrl &= ~(IO_MASK(R_SERIAL0_REC_CTRL, rec_bitnr) |
-                          IO_MASK(R_SERIAL0_REC_CTRL, rec_par_en) |
-                          IO_MASK(R_SERIAL0_REC_CTRL, rec_par));
-
-       /* 8 bit, no/even parity, 1 stop bit, no cts */
-       info->tx_ctrl &= ~(IO_MASK(R_SERIAL0_TR_CTRL, tr_bitnr) |
-                          IO_MASK(R_SERIAL0_TR_CTRL, tr_par_en) |
-                          IO_MASK(R_SERIAL0_TR_CTRL, tr_par) |
-                          IO_MASK(R_SERIAL0_TR_CTRL, stop_bits) |
-                          IO_MASK(R_SERIAL0_TR_CTRL, auto_cts));
-
-       if ((cflag & CSIZE) == CS7) {
-               /* set 7 bit mode */
-               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_7bit);
-               info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_7bit);
-       }
-
-       if (cflag & CSTOPB) {
-               /* set 2 stop bit mode */
-               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, stop_bits, two_bits);
-       }
-
-       if (cflag & PARENB) {
-               /* enable parity */
-               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable);
-               info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable);
-       }
-
-       if (cflag & CMSPAR) {
-               /* enable stick parity, PARODD mean Mark which matches ETRAX */
-               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_stick_par, stick);
-               info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_stick_par, stick);
-       }
-       if (cflag & PARODD) {
-               /* set odd parity (or Mark if CMSPAR) */
-               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd);
-               info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd);
-       }
-
-       if (cflag & CRTSCTS) {
-               /* enable automatic CTS handling */
-               DFLOW(DEBUG_LOG(info->line, "FLOW auto_cts enabled\n", 0));
-               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, auto_cts, active);
-       }
-
-       /* make sure the tx and rx are enabled */
-
-       info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_enable, enable);
-       info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable);
-
-       /* actually write the control regs to the hardware */
-
-       info->ioport[REG_TR_CTRL] = info->tx_ctrl;
-       info->ioport[REG_REC_CTRL] = info->rx_ctrl;
-       xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->port.tty));
-       xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
-       if (info->port.tty->termios->c_iflag & IXON ) {
-               DFLOW(DEBUG_LOG(info->line, "FLOW XOFF enabled 0x%02X\n",
-                               STOP_CHAR(info->port.tty)));
-               xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
-       }
-
-       *((unsigned long *)&info->ioport[REG_XOFF]) = xoff;
-       local_irq_restore(flags);
-#endif /* !CONFIG_SVINTO_SIM */
-
-       update_char_time(info);
-
-} /* change_speed */
-
-/* start transmitting chars NOW */
-
-static void
-rs_flush_chars(struct tty_struct *tty)
-{
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-       unsigned long flags;
-
-       if (info->tr_running ||
-           info->xmit.head == info->xmit.tail ||
-           tty->stopped ||
-           tty->hw_stopped ||
-           !info->xmit.buf)
-               return;
-
-#ifdef SERIAL_DEBUG_FLOW
-       printk("rs_flush_chars\n");
-#endif
-
-       /* this protection might not exactly be necessary here */
-
-       local_irq_save(flags);
-       start_transmit(info);
-       local_irq_restore(flags);
-}
-
-static int rs_raw_write(struct tty_struct *tty,
-                       const unsigned char *buf, int count)
-{
-       int     c, ret = 0;
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-       unsigned long flags;
-
-       /* first some sanity checks */
-
-       if (!tty || !info->xmit.buf || !tmp_buf)
-               return 0;
-
-#ifdef SERIAL_DEBUG_DATA
-       if (info->line == SERIAL_DEBUG_LINE)
-               printk("rs_raw_write (%d), status %d\n",
-                      count, info->ioport[REG_STATUS]);
-#endif
-
-#ifdef CONFIG_SVINTO_SIM
-       /* Really simple.  The output is here and now. */
-       SIMCOUT(buf, count);
-       return count;
-#endif
-       local_save_flags(flags);
-       DFLOW(DEBUG_LOG(info->line, "write count %i ", count));
-       DFLOW(DEBUG_LOG(info->line, "ldisc %i\n", tty->ldisc.chars_in_buffer(tty)));
-
-
-       /* The local_irq_disable/restore_flags pairs below are needed
-        * because the DMA interrupt handler moves the info->xmit values.
-        * the memcpy needs to be in the critical region unfortunately,
-        * because we need to read xmit values, memcpy, write xmit values
-        * in one atomic operation... this could perhaps be avoided by
-        * more clever design.
-        */
-       local_irq_disable();
-               while (count) {
-                       c = CIRC_SPACE_TO_END(info->xmit.head,
-                                             info->xmit.tail,
-                                             SERIAL_XMIT_SIZE);
-
-                       if (count < c)
-                               c = count;
-                       if (c <= 0)
-                               break;
-
-                       memcpy(info->xmit.buf + info->xmit.head, buf, c);
-                       info->xmit.head = (info->xmit.head + c) &
-                               (SERIAL_XMIT_SIZE-1);
-                       buf += c;
-                       count -= c;
-                       ret += c;
-               }
-       local_irq_restore(flags);
-
-       /* enable transmitter if not running, unless the tty is stopped
-        * this does not need IRQ protection since if tr_running == 0
-        * the IRQ's are not running anyway for this port.
-        */
-       DFLOW(DEBUG_LOG(info->line, "write ret %i\n", ret));
-
-       if (info->xmit.head != info->xmit.tail &&
-           !tty->stopped &&
-           !tty->hw_stopped &&
-           !info->tr_running) {
-               start_transmit(info);
-       }
-
-       return ret;
-} /* raw_raw_write() */
-
-static int
-rs_write(struct tty_struct *tty,
-        const unsigned char *buf, int count)
-{
-#if defined(CONFIG_ETRAX_RS485)
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-
-       if (info->rs485.flags & SER_RS485_ENABLED)
-       {
-               /* If we are in RS-485 mode, we need to toggle RTS and disable
-                * the receiver before initiating a DMA transfer
-                */
-#ifdef CONFIG_ETRAX_FAST_TIMER
-               /* Abort any started timer */
-               fast_timers_rs485[info->line].function = NULL;
-               del_fast_timer(&fast_timers_rs485[info->line]);
-#endif
-               e100_rts(info, (info->rs485.flags & SER_RS485_RTS_ON_SEND));
-#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
-               e100_disable_rx(info);
-               e100_enable_rx_irq(info);
-#endif
-               if ((info->rs485.flags & SER_RS485_RTS_BEFORE_SEND) &&
-                       (info->rs485.delay_rts_before_send > 0))
-                               msleep(info->rs485.delay_rts_before_send);
-       }
-#endif /* CONFIG_ETRAX_RS485 */
-
-       count = rs_raw_write(tty, buf, count);
-
-#if defined(CONFIG_ETRAX_RS485)
-       if (info->rs485.flags & SER_RS485_ENABLED)
-       {
-               unsigned int val;
-               /* If we are in RS-485 mode the following has to be done:
-                * wait until DMA is ready
-                * wait on transmit shift register
-                * toggle RTS
-                * enable the receiver
-                */
-
-               /* Sleep until all sent */
-               tty_wait_until_sent(tty, 0);
-#ifdef CONFIG_ETRAX_FAST_TIMER
-               /* Now sleep a little more so that shift register is empty */
-               schedule_usleep(info->char_time_usec * 2);
-#endif
-               /* wait on transmit shift register */
-               do{
-                       get_lsr_info(info, &val);
-               }while (!(val & TIOCSER_TEMT));
-
-               e100_rts(info, (info->rs485.flags & SER_RS485_RTS_AFTER_SEND));
-
-#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
-               e100_enable_rx(info);
-               e100_enable_rxdma_irq(info);
-#endif
-       }
-#endif /* CONFIG_ETRAX_RS485 */
-
-       return count;
-} /* rs_write */
-
-
-/* how much space is available in the xmit buffer? */
-
-static int
-rs_write_room(struct tty_struct *tty)
-{
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-
-       return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
-}
-
-/* How many chars are in the xmit buffer?
- * This does not include any chars in the transmitter FIFO.
- * Use wait_until_sent for waiting for FIFO drain.
- */
-
-static int
-rs_chars_in_buffer(struct tty_struct *tty)
-{
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-
-       return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
-}
-
-/* discard everything in the xmit buffer */
-
-static void
-rs_flush_buffer(struct tty_struct *tty)
-{
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-       unsigned long flags;
-
-       local_irq_save(flags);
-       info->xmit.head = info->xmit.tail = 0;
-       local_irq_restore(flags);
-
-       tty_wakeup(tty);
-}
-
-/*
- * This function is used to send a high-priority XON/XOFF character to
- * the device
- *
- * Since we use DMA we don't check for info->x_char in transmit_chars_dma(),
- * but we do it in handle_ser_tx_interrupt().
- * We disable DMA channel and enable tx ready interrupt and write the
- * character when possible.
- */
-static void rs_send_xchar(struct tty_struct *tty, char ch)
-{
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-       unsigned long flags;
-       local_irq_save(flags);
-       if (info->uses_dma_out) {
-               /* Put the DMA on hold and disable the channel */
-               *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, hold);
-               while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) !=
-                      IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, hold));
-               e100_disable_txdma_channel(info);
-       }
-
-       /* Must make sure transmitter is not stopped before we can transmit */
-       if (tty->stopped)
-               rs_start(tty);
-
-       /* Enable manual transmit interrupt and send from there */
-       DFLOW(DEBUG_LOG(info->line, "rs_send_xchar 0x%02X\n", ch));
-       info->x_char = ch;
-       e100_enable_serial_tx_ready_irq(info);
-       local_irq_restore(flags);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_throttle()
- *
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void
-rs_throttle(struct tty_struct * tty)
-{
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-#ifdef SERIAL_DEBUG_THROTTLE
-       char    buf[64];
-
-       printk("throttle %s: %lu....\n", tty_name(tty, buf),
-              (unsigned long)tty->ldisc.chars_in_buffer(tty));
-#endif
-       DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty)));
-
-       /* Do RTS before XOFF since XOFF might take some time */
-       if (tty->termios->c_cflag & CRTSCTS) {
-               /* Turn off RTS line */
-               e100_rts(info, 0);
-       }
-       if (I_IXOFF(tty))
-               rs_send_xchar(tty, STOP_CHAR(tty));
-
-}
-
-static void
-rs_unthrottle(struct tty_struct * tty)
-{
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-#ifdef SERIAL_DEBUG_THROTTLE
-       char    buf[64];
-
-       printk("unthrottle %s: %lu....\n", tty_name(tty, buf),
-              (unsigned long)tty->ldisc.chars_in_buffer(tty));
-#endif
-       DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty)));
-       DFLOW(DEBUG_LOG(info->line,"rs_unthrottle flip.count: %i\n", tty->flip.count));
-       /* Do RTS before XOFF since XOFF might take some time */
-       if (tty->termios->c_cflag & CRTSCTS) {
-               /* Assert RTS line  */
-               e100_rts(info, 1);
-       }
-
-       if (I_IXOFF(tty)) {
-               if (info->x_char)
-                       info->x_char = 0;
-               else
-                       rs_send_xchar(tty, START_CHAR(tty));
-       }
-
-}
-
-/*
- * ------------------------------------------------------------
- * rs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-static int
-get_serial_info(struct e100_serial * info,
-               struct serial_struct * retinfo)
-{
-       struct serial_struct tmp;
-
-       /* this is all probably wrong, there are a lot of fields
-        * here that we don't have in e100_serial and maybe we
-        * should set them to something else than 0.
-        */
-
-       if (!retinfo)
-               return -EFAULT;
-       memset(&tmp, 0, sizeof(tmp));
-       tmp.type = info->type;
-       tmp.line = info->line;
-       tmp.port = (int)info->ioport;
-       tmp.irq = info->irq;
-       tmp.flags = info->flags;
-       tmp.baud_base = info->baud_base;
-       tmp.close_delay = info->close_delay;
-       tmp.closing_wait = info->closing_wait;
-       tmp.custom_divisor = info->custom_divisor;
-       if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
-               return -EFAULT;
-       return 0;
-}
-
-static int
-set_serial_info(struct e100_serial *info,
-               struct serial_struct *new_info)
-{
-       struct serial_struct new_serial;
-       struct e100_serial old_info;
-       int retval = 0;
-
-       if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
-               return -EFAULT;
-
-       old_info = *info;
-
-       if (!capable(CAP_SYS_ADMIN)) {
-               if ((new_serial.type != info->type) ||
-                   (new_serial.close_delay != info->close_delay) ||
-                   ((new_serial.flags & ~ASYNC_USR_MASK) !=
-                    (info->flags & ~ASYNC_USR_MASK)))
-                       return -EPERM;
-               info->flags = ((info->flags & ~ASYNC_USR_MASK) |
-                              (new_serial.flags & ASYNC_USR_MASK));
-               goto check_and_exit;
-       }
-
-       if (info->count > 1)
-               return -EBUSY;
-
-       /*
-        * OK, past this point, all the error checking has been done.
-        * At this point, we start making changes.....
-        */
-
-       info->baud_base = new_serial.baud_base;
-       info->flags = ((info->flags & ~ASYNC_FLAGS) |
-                      (new_serial.flags & ASYNC_FLAGS));
-       info->custom_divisor = new_serial.custom_divisor;
-       info->type = new_serial.type;
-       info->close_delay = new_serial.close_delay;
-       info->closing_wait = new_serial.closing_wait;
-       info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-
- check_and_exit:
-       if (info->flags & ASYNC_INITIALIZED) {
-               change_speed(info);
-       } else
-               retval = startup(info);
-       return retval;
-}
-
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- *         is emptied.  On bus types like RS485, the transmitter must
- *         release the bus after transmitting. This must be done when
- *         the transmit shift register is empty, not be done when the
- *         transmit holding register is empty.  This functionality
- *         allows an RS485 driver to be written in user space.
- */
-static int
-get_lsr_info(struct e100_serial * info, unsigned int *value)
-{
-       unsigned int result = TIOCSER_TEMT;
-#ifndef CONFIG_SVINTO_SIM
-       unsigned long curr_time = jiffies;
-       unsigned long curr_time_usec = GET_JIFFIES_USEC();
-       unsigned long elapsed_usec =
-               (curr_time - info->last_tx_active) * 1000000/HZ +
-               curr_time_usec - info->last_tx_active_usec;
-
-       if (info->xmit.head != info->xmit.tail ||
-           elapsed_usec < 2*info->char_time_usec) {
-               result = 0;
-       }
-#endif
-
-       if (copy_to_user(value, &result, sizeof(int)))
-               return -EFAULT;
-       return 0;
-}
-
-#ifdef SERIAL_DEBUG_IO
-struct state_str
-{
-       int state;
-       const char *str;
-};
-
-const struct state_str control_state_str[] = {
-       {TIOCM_DTR, "DTR" },
-       {TIOCM_RTS, "RTS"},
-       {TIOCM_ST, "ST?" },
-       {TIOCM_SR, "SR?" },
-       {TIOCM_CTS, "CTS" },
-       {TIOCM_CD, "CD" },
-       {TIOCM_RI, "RI" },
-       {TIOCM_DSR, "DSR" },
-       {0, NULL }
-};
-
-char *get_control_state_str(int MLines, char *s)
-{
-       int i = 0;
-
-       s[0]='\0';
-       while (control_state_str[i].str != NULL) {
-               if (MLines & control_state_str[i].state) {
-                       if (s[0] != '\0') {
-                               strcat(s, ", ");
-                       }
-                       strcat(s, control_state_str[i].str);
-               }
-               i++;
-       }
-       return s;
-}
-#endif
-
-static int
-rs_break(struct tty_struct *tty, int break_state)
-{
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-       unsigned long flags;
-
-       if (!info->ioport)
-               return -EIO;
-
-       local_irq_save(flags);
-       if (break_state == -1) {
-               /* Go to manual mode and set the txd pin to 0 */
-               /* Clear bit 7 (txd) and 6 (tr_enable) */
-               info->tx_ctrl &= 0x3F;
-       } else {
-               /* Set bit 7 (txd) and 6 (tr_enable) */
-               info->tx_ctrl |= (0x80 | 0x40);
-       }
-       info->ioport[REG_TR_CTRL] = info->tx_ctrl;
-       local_irq_restore(flags);
-       return 0;
-}
-
-static int
-rs_tiocmset(struct tty_struct *tty, struct file *file,
-               unsigned int set, unsigned int clear)
-{
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       if (clear & TIOCM_RTS)
-               e100_rts(info, 0);
-       if (clear & TIOCM_DTR)
-               e100_dtr(info, 0);
-       /* Handle FEMALE behaviour */
-       if (clear & TIOCM_RI)
-               e100_ri_out(info, 0);
-       if (clear & TIOCM_CD)
-               e100_cd_out(info, 0);
-
-       if (set & TIOCM_RTS)
-               e100_rts(info, 1);
-       if (set & TIOCM_DTR)
-               e100_dtr(info, 1);
-       /* Handle FEMALE behaviour */
-       if (set & TIOCM_RI)
-               e100_ri_out(info, 1);
-       if (set & TIOCM_CD)
-               e100_cd_out(info, 1);
-
-       local_irq_restore(flags);
-       return 0;
-}
-
-static int
-rs_tiocmget(struct tty_struct *tty, struct file *file)
-{
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-       unsigned int result;
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       result =
-               (!E100_RTS_GET(info) ? TIOCM_RTS : 0)
-               | (!E100_DTR_GET(info) ? TIOCM_DTR : 0)
-               | (!E100_RI_GET(info) ? TIOCM_RNG : 0)
-               | (!E100_DSR_GET(info) ? TIOCM_DSR : 0)
-               | (!E100_CD_GET(info) ? TIOCM_CAR : 0)
-               | (!E100_CTS_GET(info) ? TIOCM_CTS : 0);
-
-       local_irq_restore(flags);
-
-#ifdef SERIAL_DEBUG_IO
-       printk(KERN_DEBUG "ser%i: modem state: %i 0x%08X\n",
-               info->line, result, result);
-       {
-               char s[100];
-
-               get_control_state_str(result, s);
-               printk(KERN_DEBUG "state: %s\n", s);
-       }
-#endif
-       return result;
-
-}
-
-
-static int
-rs_ioctl(struct tty_struct *tty, struct file * file,
-        unsigned int cmd, unsigned long arg)
-{
-       struct e100_serial * info = (struct e100_serial *)tty->driver_data;
-
-       if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
-           (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
-           (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
-               if (tty->flags & (1 << TTY_IO_ERROR))
-                       return -EIO;
-       }
-
-       switch (cmd) {
-       case TIOCGSERIAL:
-               return get_serial_info(info,
-                                      (struct serial_struct *) arg);
-       case TIOCSSERIAL:
-               return set_serial_info(info,
-                                      (struct serial_struct *) arg);
-       case TIOCSERGETLSR: /* Get line status register */
-               return get_lsr_info(info, (unsigned int *) arg);
-
-       case TIOCSERGSTRUCT:
-               if (copy_to_user((struct e100_serial *) arg,
-                                info, sizeof(struct e100_serial)))
-                       return -EFAULT;
-               return 0;
-
-#if defined(CONFIG_ETRAX_RS485)
-       case TIOCSERSETRS485:
-       {
-               /* In this ioctl we still use the old structure
-                * rs485_control for backward compatibility
-                * (if we use serial_rs485, then old user-level code
-                * wouldn't work anymore...).
-                * The use of this ioctl is deprecated: use TIOCSRS485
-                * instead.*/
-               struct rs485_control rs485ctrl;
-               struct serial_rs485 rs485data;
-               printk(KERN_DEBUG "The use of this ioctl is deprecated. Use TIOCSRS485 instead\n");
-               if (copy_from_user(&rs485ctrl, (struct rs485_control *)arg,
-                               sizeof(rs485ctrl)))
-                       return -EFAULT;
-
-               rs485data.delay_rts_before_send = rs485ctrl.delay_rts_before_send;
-               rs485data.flags = 0;
-               if (rs485data.delay_rts_before_send != 0)
-                       rs485data.flags |= SER_RS485_RTS_BEFORE_SEND;
-               else
-                       rs485data.flags &= ~(SER_RS485_RTS_BEFORE_SEND);
-
-               if (rs485ctrl.enabled)
-                       rs485data.flags |= SER_RS485_ENABLED;
-               else
-                       rs485data.flags &= ~(SER_RS485_ENABLED);
-
-               if (rs485ctrl.rts_on_send)
-                       rs485data.flags |= SER_RS485_RTS_ON_SEND;
-               else
-                       rs485data.flags &= ~(SER_RS485_RTS_ON_SEND);
-
-               if (rs485ctrl.rts_after_sent)
-                       rs485data.flags |= SER_RS485_RTS_AFTER_SEND;
-               else
-                       rs485data.flags &= ~(SER_RS485_RTS_AFTER_SEND);
-
-               return e100_enable_rs485(tty, &rs485data);
-       }
-
-       case TIOCSRS485:
-       {
-               /* This is the new version of TIOCSRS485, with new
-                * data structure serial_rs485 */
-               struct serial_rs485 rs485data;
-               if (copy_from_user(&rs485data, (struct rs485_control *)arg,
-                               sizeof(rs485data)))
-                       return -EFAULT;
-
-               return e100_enable_rs485(tty, &rs485data);
-       }
-
-       case TIOCGRS485:
-       {
-               struct serial_rs485 *rs485data =
-                       &(((struct e100_serial *)tty->driver_data)->rs485);
-               /* This is the ioctl to get RS485 data from user-space */
-               if (copy_to_user((struct serial_rs485 *) arg,
-                                       rs485data,
-                                       sizeof(struct serial_rs485)))
-                       return -EFAULT;
-               break;
-       }
-
-       case TIOCSERWRRS485:
-       {
-               struct rs485_write rs485wr;
-               if (copy_from_user(&rs485wr, (struct rs485_write *)arg,
-                               sizeof(rs485wr)))
-                       return -EFAULT;
-
-               return e100_write_rs485(tty, rs485wr.outc, rs485wr.outc_size);
-       }
-#endif
-
-       default:
-               return -ENOIOCTLCMD;
-       }
-       return 0;
-}
-
-static void
-rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-
-       change_speed(info);
-
-       /* Handle turning off CRTSCTS */
-       if ((old_termios->c_cflag & CRTSCTS) &&
-           !(tty->termios->c_cflag & CRTSCTS)) {
-               tty->hw_stopped = 0;
-               rs_start(tty);
-       }
-
-}
-
-/*
- * ------------------------------------------------------------
- * rs_close()
- *
- * This routine is called when the serial port gets closed.  First, we
- * wait for the last remaining data to be sent.  Then, we unlink its
- * S structure from the interrupt chain if necessary, and we free
- * that IRQ if nothing is left in the chain.
- * ------------------------------------------------------------
- */
-static void
-rs_close(struct tty_struct *tty, struct file * filp)
-{
-       struct e100_serial * info = (struct e100_serial *)tty->driver_data;
-       unsigned long flags;
-
-       if (!info)
-               return;
-
-       /* interrupts are disabled for this entire function */
-
-       local_irq_save(flags);
-
-       if (tty_hung_up_p(filp)) {
-               local_irq_restore(flags);
-               return;
-       }
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("[%d] rs_close ttyS%d, count = %d\n", current->pid,
-              info->line, info->count);
-#endif
-       if ((tty->count == 1) && (info->count != 1)) {
-               /*
-                * Uh, oh.  tty->count is 1, which means that the tty
-                * structure will be freed.  Info->count should always
-                * be one in these conditions.  If it's greater than
-                * one, we've got real problems, since it means the
-                * serial port won't be shutdown.
-                */
-               printk(KERN_CRIT
-                      "rs_close: bad serial port count; tty->count is 1, "
-                      "info->count is %d\n", info->count);
-               info->count = 1;
-       }
-       if (--info->count < 0) {
-               printk(KERN_CRIT "rs_close: bad serial port count for ttyS%d: %d\n",
-                      info->line, info->count);
-               info->count = 0;
-       }
-       if (info->count) {
-               local_irq_restore(flags);
-               return;
-       }
-       info->flags |= ASYNC_CLOSING;
-       /*
-        * Save the termios structure, since this port may have
-        * separate termios for callout and dialin.
-        */
-       if (info->flags & ASYNC_NORMAL_ACTIVE)
-               info->normal_termios = *tty->termios;
-       /*
-        * 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 (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, info->closing_wait);
-       /*
-        * At this point we stop accepting input.  To do this, we
-        * disable the serial receiver and the DMA receive interrupt.
-        */
-#ifdef SERIAL_HANDLE_EARLY_ERRORS
-       e100_disable_serial_data_irq(info);
-#endif
-
-#ifndef CONFIG_SVINTO_SIM
-       e100_disable_rx(info);
-       e100_disable_rx_irq(info);
-
-       if (info->flags & ASYNC_INITIALIZED) {
-               /*
-                * Before we drop DTR, make sure the UART transmitter
-                * has completely drained; this is especially
-                * important as we have a transmit FIFO!
-                */
-               rs_wait_until_sent(tty, HZ);
-       }
-#endif
-
-       shutdown(info);
-       rs_flush_buffer(tty);
-       tty_ldisc_flush(tty);
-       tty->closing = 0;
-       info->event = 0;
-       info->port.tty = NULL;
-       if (info->blocked_open) {
-               if (info->close_delay)
-                       schedule_timeout_interruptible(info->close_delay);
-               wake_up_interruptible(&info->open_wait);
-       }
-       info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-       wake_up_interruptible(&info->close_wait);
-       local_irq_restore(flags);
-
-       /* port closed */
-
-#if defined(CONFIG_ETRAX_RS485)
-       if (info->rs485.flags & SER_RS485_ENABLED) {
-               info->rs485.flags &= ~(SER_RS485_ENABLED);
-#if defined(CONFIG_ETRAX_RS485_ON_PA)
-               *R_PORT_PA_DATA = port_pa_data_shadow &= ~(1 << rs485_pa_bit);
-#endif
-#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
-               REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
-                              rs485_port_g_bit, 0);
-#endif
-#if defined(CONFIG_ETRAX_RS485_LTC1387)
-               REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
-                              CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 0);
-               REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
-                              CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 0);
-#endif
-       }
-#endif
-
-       /*
-        * Release any allocated DMA irq's.
-        */
-       if (info->dma_in_enabled) {
-               free_irq(info->dma_in_irq_nbr, info);
-               cris_free_dma(info->dma_in_nbr, info->dma_in_irq_description);
-               info->uses_dma_in = 0;
-#ifdef SERIAL_DEBUG_OPEN
-               printk(KERN_DEBUG "DMA irq '%s' freed\n",
-                       info->dma_in_irq_description);
-#endif
-       }
-       if (info->dma_out_enabled) {
-               free_irq(info->dma_out_irq_nbr, info);
-               cris_free_dma(info->dma_out_nbr, info->dma_out_irq_description);
-               info->uses_dma_out = 0;
-#ifdef SERIAL_DEBUG_OPEN
-               printk(KERN_DEBUG "DMA irq '%s' freed\n",
-                       info->dma_out_irq_description);
-#endif
-       }
-}
-
-/*
- * rs_wait_until_sent() --- wait until the transmitter is empty
- */
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-       unsigned long orig_jiffies;
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-       unsigned long curr_time = jiffies;
-       unsigned long curr_time_usec = GET_JIFFIES_USEC();
-       long elapsed_usec =
-               (curr_time - info->last_tx_active) * (1000000/HZ) +
-               curr_time_usec - info->last_tx_active_usec;
-
-       /*
-        * Check R_DMA_CHx_STATUS bit 0-6=number of available bytes in FIFO
-        * R_DMA_CHx_HWSW bit 31-16=nbr of bytes left in DMA buffer (0=64k)
-        */
-       orig_jiffies = jiffies;
-       while (info->xmit.head != info->xmit.tail || /* More in send queue */
-              (*info->ostatusadr & 0x007f) ||  /* more in FIFO */
-              (elapsed_usec < 2*info->char_time_usec)) {
-               schedule_timeout_interruptible(1);
-               if (signal_pending(current))
-                       break;
-               if (timeout && time_after(jiffies, orig_jiffies + timeout))
-                       break;
-               curr_time = jiffies;
-               curr_time_usec = GET_JIFFIES_USEC();
-               elapsed_usec =
-                       (curr_time - info->last_tx_active) * (1000000/HZ) +
-                       curr_time_usec - info->last_tx_active_usec;
-       }
-       set_current_state(TASK_RUNNING);
-}
-
-/*
- * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-void
-rs_hangup(struct tty_struct *tty)
-{
-       struct e100_serial * info = (struct e100_serial *)tty->driver_data;
-
-       rs_flush_buffer(tty);
-       shutdown(info);
-       info->event = 0;
-       info->count = 0;
-       info->flags &= ~ASYNC_NORMAL_ACTIVE;
-       info->port.tty = NULL;
-       wake_up_interruptible(&info->open_wait);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_open() and friends
- * ------------------------------------------------------------
- */
-static int
-block_til_ready(struct tty_struct *tty, struct file * filp,
-               struct e100_serial *info)
-{
-       DECLARE_WAITQUEUE(wait, current);
-       unsigned long   flags;
-       int             retval;
-       int             do_clocal = 0, extra_count = 0;
-
-       /*
-        * 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) ||
-           (info->flags & ASYNC_CLOSING)) {
-               wait_event_interruptible_tty(info->close_wait,
-                       !(info->flags & ASYNC_CLOSING));
-#ifdef SERIAL_DO_RESTART
-               if (info->flags & ASYNC_HUP_NOTIFY)
-                       return -EAGAIN;
-               else
-                       return -ERESTARTSYS;
-#else
-               return -EAGAIN;
-#endif
-       }
-
-       /*
-        * 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))) {
-               info->flags |= ASYNC_NORMAL_ACTIVE;
-               return 0;
-       }
-
-       if (tty->termios->c_cflag & CLOCAL) {
-                       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, info->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(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
-       printk("block_til_ready before block: ttyS%d, count = %d\n",
-              info->line, info->count);
-#endif
-       local_irq_save(flags);
-       if (!tty_hung_up_p(filp)) {
-               extra_count++;
-               info->count--;
-       }
-       local_irq_restore(flags);
-       info->blocked_open++;
-       while (1) {
-               local_irq_save(flags);
-               /* assert RTS and DTR */
-               e100_rts(info, 1);
-               e100_dtr(info, 1);
-               local_irq_restore(flags);
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (tty_hung_up_p(filp) ||
-                   !(info->flags & ASYNC_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
-                       if (info->flags & ASYNC_HUP_NOTIFY)
-                               retval = -EAGAIN;
-                       else
-                               retval = -ERESTARTSYS;
-#else
-                       retval = -EAGAIN;
-#endif
-                       break;
-               }
-               if (!(info->flags & ASYNC_CLOSING) && do_clocal)
-                       /* && (do_clocal || DCD_IS_ASSERTED) */
-                       break;
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-#ifdef SERIAL_DEBUG_OPEN
-               printk("block_til_ready blocking: ttyS%d, count = %d\n",
-                      info->line, info->count);
-#endif
-               tty_unlock();
-               schedule();
-               tty_lock();
-       }
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&info->open_wait, &wait);
-       if (extra_count)
-               info->count++;
-       info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
-       printk("block_til_ready after blocking: ttyS%d, count = %d\n",
-              info->line, info->count);
-#endif
-       if (retval)
-               return retval;
-       info->flags |= ASYNC_NORMAL_ACTIVE;
-       return 0;
-}
-
-static void
-deinit_port(struct e100_serial *info)
-{
-       if (info->dma_out_enabled) {
-               cris_free_dma(info->dma_out_nbr, info->dma_out_irq_description);
-               free_irq(info->dma_out_irq_nbr, info);
-       }
-       if (info->dma_in_enabled) {
-               cris_free_dma(info->dma_in_nbr, info->dma_in_irq_description);
-               free_irq(info->dma_in_irq_nbr, info);
-       }
-}
-
-/*
- * This routine is called whenever a serial port is opened.
- * It performs the serial-specific initialization for the tty structure.
- */
-static int
-rs_open(struct tty_struct *tty, struct file * filp)
-{
-       struct e100_serial      *info;
-       int                     retval, line;
-       unsigned long           page;
-       int                     allocated_resources = 0;
-
-       /* find which port we want to open */
-       line = tty->index;
-
-       if (line < 0 || line >= NR_PORTS)
-               return -ENODEV;
-
-       /* find the corresponding e100_serial struct in the table */
-       info = rs_table + line;
-
-       /* don't allow the opening of ports that are not enabled in the HW config */
-       if (!info->enabled)
-               return -ENODEV;
-
-#ifdef SERIAL_DEBUG_OPEN
-        printk("[%d] rs_open %s, count = %d\n", current->pid, tty->name,
-              info->count);
-#endif
-
-       info->count++;
-       tty->driver_data = info;
-       info->port.tty = tty;
-
-       info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-
-       if (!tmp_buf) {
-               page = get_zeroed_page(GFP_KERNEL);
-               if (!page) {
-                       return -ENOMEM;
-               }
-               if (tmp_buf)
-                       free_page(page);
-               else
-                       tmp_buf = (unsigned char *) page;
-       }
-
-       /*
-        * If the port is in the middle of closing, bail out now
-        */
-       if (tty_hung_up_p(filp) ||
-           (info->flags & ASYNC_CLOSING)) {
-               wait_event_interruptible_tty(info->close_wait,
-                       !(info->flags & ASYNC_CLOSING));
-#ifdef SERIAL_DO_RESTART
-               return ((info->flags & ASYNC_HUP_NOTIFY) ?
-                       -EAGAIN : -ERESTARTSYS);
-#else
-               return -EAGAIN;
-#endif
-       }
-
-       /*
-        * If DMA is enabled try to allocate the irq's.
-        */
-       if (info->count == 1) {
-               allocated_resources = 1;
-               if (info->dma_in_enabled) {
-                       if (request_irq(info->dma_in_irq_nbr,
-                                       rec_interrupt,
-                                       info->dma_in_irq_flags,
-                                       info->dma_in_irq_description,
-                                       info)) {
-                               printk(KERN_WARNING "DMA irq '%s' busy; "
-                                       "falling back to non-DMA mode\n",
-                                       info->dma_in_irq_description);
-                               /* Make sure we never try to use DMA in */
-                               /* for the port again. */
-                               info->dma_in_enabled = 0;
-                       } else if (cris_request_dma(info->dma_in_nbr,
-                                       info->dma_in_irq_description,
-                                       DMA_VERBOSE_ON_ERROR,
-                                       info->dma_owner)) {
-                               free_irq(info->dma_in_irq_nbr, info);
-                               printk(KERN_WARNING "DMA '%s' busy; "
-                                       "falling back to non-DMA mode\n",
-                                       info->dma_in_irq_description);
-                               /* Make sure we never try to use DMA in */
-                               /* for the port again. */
-                               info->dma_in_enabled = 0;
-                       }
-#ifdef SERIAL_DEBUG_OPEN
-                       else
-                               printk(KERN_DEBUG "DMA irq '%s' allocated\n",
-                                       info->dma_in_irq_description);
-#endif
-               }
-               if (info->dma_out_enabled) {
-                       if (request_irq(info->dma_out_irq_nbr,
-                                              tr_interrupt,
-                                              info->dma_out_irq_flags,
-                                              info->dma_out_irq_description,
-                                              info)) {
-                               printk(KERN_WARNING "DMA irq '%s' busy; "
-                                       "falling back to non-DMA mode\n",
-                                       info->dma_out_irq_description);
-                               /* Make sure we never try to use DMA out */
-                               /* for the port again. */
-                               info->dma_out_enabled = 0;
-                       } else if (cris_request_dma(info->dma_out_nbr,
-                                            info->dma_out_irq_description,
-                                            DMA_VERBOSE_ON_ERROR,
-                                            info->dma_owner)) {
-                               free_irq(info->dma_out_irq_nbr, info);
-                               printk(KERN_WARNING "DMA '%s' busy; "
-                                       "falling back to non-DMA mode\n",
-                                       info->dma_out_irq_description);
-                               /* Make sure we never try to use DMA out */
-                               /* for the port again. */
-                               info->dma_out_enabled = 0;
-                       }
-#ifdef SERIAL_DEBUG_OPEN
-                       else
-                               printk(KERN_DEBUG "DMA irq '%s' allocated\n",
-                                       info->dma_out_irq_description);
-#endif
-               }
-       }
-
-       /*
-        * Start up the serial port
-        */
-
-       retval = startup(info);
-       if (retval) {
-               if (allocated_resources)
-                       deinit_port(info);
-
-               /* FIXME Decrease count info->count here too? */
-               return retval;
-       }
-
-
-       retval = block_til_ready(tty, filp, info);
-       if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
-               printk("rs_open returning after block_til_ready with %d\n",
-                      retval);
-#endif
-               if (allocated_resources)
-                       deinit_port(info);
-
-               return retval;
-       }
-
-       if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
-               *tty->termios = info->normal_termios;
-               change_speed(info);
-       }
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("rs_open ttyS%d successful...\n", info->line);
-#endif
-       DLOG_INT_TRIG( log_int_pos = 0);
-
-       DFLIP(  if (info->line == SERIAL_DEBUG_LINE) {
-                       info->icount.rx = 0;
-               } );
-
-       return 0;
-}
-
-#ifdef CONFIG_PROC_FS
-/*
- * /proc fs routines....
- */
-
-static void seq_line_info(struct seq_file *m, struct e100_serial *info)
-{
-       unsigned long tmp;
-
-       seq_printf(m, "%d: uart:E100 port:%lX irq:%d",
-                  info->line, (unsigned long)info->ioport, info->irq);
-
-       if (!info->ioport || (info->type == PORT_UNKNOWN)) {
-               seq_printf(m, "\n");
-               return;
-       }
-
-       seq_printf(m, " baud:%d", info->baud);
-       seq_printf(m, " tx:%lu rx:%lu",
-                      (unsigned long)info->icount.tx,
-                      (unsigned long)info->icount.rx);
-       tmp = CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
-       if (tmp)
-               seq_printf(m, " tx_pend:%lu/%lu",
-                          (unsigned long)tmp,
-                          (unsigned long)SERIAL_XMIT_SIZE);
-
-       seq_printf(m, " rx_pend:%lu/%lu",
-                  (unsigned long)info->recv_cnt,
-                  (unsigned long)info->max_recv_cnt);
-
-#if 1
-       if (info->port.tty) {
-               if (info->port.tty->stopped)
-                       seq_printf(m, " stopped:%i",
-                                  (int)info->port.tty->stopped);
-               if (info->port.tty->hw_stopped)
-                       seq_printf(m, " hw_stopped:%i",
-                                  (int)info->port.tty->hw_stopped);
-       }
-
-       {
-               unsigned char rstat = info->ioport[REG_STATUS];
-               if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect))
-                       seq_printf(m, " xoff_detect:1");
-       }
-
-#endif
-
-       if (info->icount.frame)
-               seq_printf(m, " fe:%lu", (unsigned long)info->icount.frame);
-
-       if (info->icount.parity)
-               seq_printf(m, " pe:%lu", (unsigned long)info->icount.parity);
-
-       if (info->icount.brk)
-               seq_printf(m, " brk:%lu", (unsigned long)info->icount.brk);
-
-       if (info->icount.overrun)
-               seq_printf(m, " oe:%lu", (unsigned long)info->icount.overrun);
-
-       /*
-        * Last thing is the RS-232 status lines
-        */
-       if (!E100_RTS_GET(info))
-               seq_puts(m, "|RTS");
-       if (!E100_CTS_GET(info))
-               seq_puts(m, "|CTS");
-       if (!E100_DTR_GET(info))
-               seq_puts(m, "|DTR");
-       if (!E100_DSR_GET(info))
-               seq_puts(m, "|DSR");
-       if (!E100_CD_GET(info))
-               seq_puts(m, "|CD");
-       if (!E100_RI_GET(info))
-               seq_puts(m, "|RI");
-       seq_puts(m, "\n");
-}
-
-
-static int crisv10_proc_show(struct seq_file *m, void *v)
-{
-       int i;
-
-       seq_printf(m, "serinfo:1.0 driver:%s\n", serial_version);
-
-       for (i = 0; i < NR_PORTS; i++) {
-               if (!rs_table[i].enabled)
-                       continue;
-               seq_line_info(m, &rs_table[i]);
-       }
-#ifdef DEBUG_LOG_INCLUDED
-       for (i = 0; i < debug_log_pos; i++) {
-               seq_printf(m, "%-4i %lu.%lu ",
-                        i, debug_log[i].time,
-                        timer_data_to_ns(debug_log[i].timer_data));
-               seq_printf(m, debug_log[i].string, debug_log[i].value);
-       }
-       seq_printf(m, "debug_log %i/%i\n", i, DEBUG_LOG_SIZE);
-       debug_log_pos = 0;
-#endif
-       return 0;
-}
-
-static int crisv10_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, crisv10_proc_show, NULL);
-}
-
-static const struct file_operations crisv10_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = crisv10_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-#endif
-
-
-/* Finally, routines used to initialize the serial driver. */
-
-static void show_serial_version(void)
-{
-       printk(KERN_INFO
-              "ETRAX 100LX serial-driver %s, "
-              "(c) 2000-2004 Axis Communications AB\r\n",
-              &serial_version[11]); /* "$Revision: x.yy" */
-}
-
-/* rs_init inits the driver at boot (using the module_init chain) */
-
-static const struct tty_operations rs_ops = {
-       .open = rs_open,
-       .close = rs_close,
-       .write = rs_write,
-       .flush_chars = rs_flush_chars,
-       .write_room = rs_write_room,
-       .chars_in_buffer = rs_chars_in_buffer,
-       .flush_buffer = rs_flush_buffer,
-       .ioctl = rs_ioctl,
-       .throttle = rs_throttle,
-        .unthrottle = rs_unthrottle,
-       .set_termios = rs_set_termios,
-       .stop = rs_stop,
-       .start = rs_start,
-       .hangup = rs_hangup,
-       .break_ctl = rs_break,
-       .send_xchar = rs_send_xchar,
-       .wait_until_sent = rs_wait_until_sent,
-       .tiocmget = rs_tiocmget,
-       .tiocmset = rs_tiocmset,
-#ifdef CONFIG_PROC_FS
-       .proc_fops = &crisv10_proc_fops,
-#endif
-};
-
-static int __init rs_init(void)
-{
-       int i;
-       struct e100_serial *info;
-       struct tty_driver *driver = alloc_tty_driver(NR_PORTS);
-
-       if (!driver)
-               return -ENOMEM;
-
-       show_serial_version();
-
-       /* Setup the timed flush handler system */
-
-#if !defined(CONFIG_ETRAX_SERIAL_FAST_TIMER)
-       setup_timer(&flush_timer, timed_flush_handler, 0);
-       mod_timer(&flush_timer, jiffies + 5);
-#endif
-
-#if defined(CONFIG_ETRAX_RS485)
-#if defined(CONFIG_ETRAX_RS485_ON_PA)
-       if (cris_io_interface_allocate_pins(if_ser0, 'a', rs485_pa_bit,
-                       rs485_pa_bit)) {
-               printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
-                       "RS485 pin\n");
-               put_tty_driver(driver);
-               return -EBUSY;
-       }
-#endif
-#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
-       if (cris_io_interface_allocate_pins(if_ser0, 'g', rs485_pa_bit,
-                       rs485_port_g_bit)) {
-               printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
-                       "RS485 pin\n");
-               put_tty_driver(driver);
-               return -EBUSY;
-       }
-#endif
-#endif
-
-       /* Initialize the tty_driver structure */
-
-       driver->driver_name = "serial";
-       driver->name = "ttyS";
-       driver->major = TTY_MAJOR;
-       driver->minor_start = 64;
-       driver->type = TTY_DRIVER_TYPE_SERIAL;
-       driver->subtype = SERIAL_TYPE_NORMAL;
-       driver->init_termios = tty_std_termios;
-       driver->init_termios.c_cflag =
-               B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */
-       driver->init_termios.c_ispeed = 115200;
-       driver->init_termios.c_ospeed = 115200;
-       driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
-
-       tty_set_operations(driver, &rs_ops);
-        serial_driver = driver;
-       if (tty_register_driver(driver))
-               panic("Couldn't register serial driver\n");
-       /* do some initializing for the separate ports */
-
-       for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
-               if (info->enabled) {
-                       if (cris_request_io_interface(info->io_if,
-                                       info->io_if_description)) {
-                               printk(KERN_CRIT "ETRAX100LX async serial: "
-                                       "Could not allocate IO pins for "
-                                       "%s, port %d\n",
-                                       info->io_if_description, i);
-                               info->enabled = 0;
-                       }
-               }
-               info->uses_dma_in = 0;
-               info->uses_dma_out = 0;
-               info->line = i;
-               info->port.tty = NULL;
-               info->type = PORT_ETRAX;
-               info->tr_running = 0;
-               info->forced_eop = 0;
-               info->baud_base = DEF_BAUD_BASE;
-               info->custom_divisor = 0;
-               info->flags = 0;
-               info->close_delay = 5*HZ/10;
-               info->closing_wait = 30*HZ;
-               info->x_char = 0;
-               info->event = 0;
-               info->count = 0;
-               info->blocked_open = 0;
-               info->normal_termios = driver->init_termios;
-               init_waitqueue_head(&info->open_wait);
-               init_waitqueue_head(&info->close_wait);
-               info->xmit.buf = NULL;
-               info->xmit.tail = info->xmit.head = 0;
-               info->first_recv_buffer = info->last_recv_buffer = NULL;
-               info->recv_cnt = info->max_recv_cnt = 0;
-               info->last_tx_active_usec = 0;
-               info->last_tx_active = 0;
-
-#if defined(CONFIG_ETRAX_RS485)
-               /* Set sane defaults */
-               info->rs485.flags &= ~(SER_RS485_RTS_ON_SEND);
-               info->rs485.flags |= SER_RS485_RTS_AFTER_SEND;
-               info->rs485.flags &= ~(SER_RS485_RTS_BEFORE_SEND);
-               info->rs485.delay_rts_before_send = 0;
-               info->rs485.flags &= ~(SER_RS485_ENABLED);
-#endif
-               INIT_WORK(&info->work, do_softint);
-
-               if (info->enabled) {
-                       printk(KERN_INFO "%s%d at %p is a builtin UART with DMA\n",
-                              serial_driver->name, info->line, info->ioport);
-               }
-       }
-#ifdef CONFIG_ETRAX_FAST_TIMER
-#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
-       memset(fast_timers, 0, sizeof(fast_timers));
-#endif
-#ifdef CONFIG_ETRAX_RS485
-       memset(fast_timers_rs485, 0, sizeof(fast_timers_rs485));
-#endif
-       fast_timer_init();
-#endif
-
-#ifndef CONFIG_SVINTO_SIM
-#ifndef CONFIG_ETRAX_KGDB
-       /* Not needed in simulator.  May only complicate stuff. */
-       /* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */
-
-       if (request_irq(SERIAL_IRQ_NBR, ser_interrupt,
-                       IRQF_SHARED | IRQF_DISABLED, "serial ", driver))
-               panic("%s: Failed to request irq8", __func__);
-
-#endif
-#endif /* CONFIG_SVINTO_SIM */
-
-       return 0;
-}
-
-/* this makes sure that rs_init is called during kernel boot */
-
-module_init(rs_init);
diff --git a/drivers/serial/crisv10.h b/drivers/serial/crisv10.h
deleted file mode 100644 (file)
index ea0beb4..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * serial.h: Arch-dep definitions for the Etrax100 serial driver.
- *
- * Copyright (C) 1998-2007 Axis Communications AB
- */
-
-#ifndef _ETRAX_SERIAL_H
-#define _ETRAX_SERIAL_H
-
-#include <linux/circ_buf.h>
-#include <asm/termios.h>
-#include <asm/dma.h>
-#include <arch/io_interface_mux.h>
-
-/* Software state per channel */
-
-#ifdef __KERNEL__
-/*
- * This is our internal structure for each serial port's state.
- *
- * Many fields are paralleled by the structure used by the serial_struct
- * structure.
- *
- * For definitions of the flags field, see tty.h
- */
-
-#define SERIAL_RECV_DESCRIPTORS 8
-
-struct etrax_recv_buffer {
-       struct etrax_recv_buffer *next;
-       unsigned short length;
-       unsigned char error;
-       unsigned char pad;
-
-       unsigned char buffer[0];
-};
-
-struct e100_serial {
-       struct tty_port port;
-       int baud;
-       volatile u8     *ioport;        /* R_SERIALx_CTRL */
-       u32             irq;    /* bitnr in R_IRQ_MASK2 for dmaX_descr */
-
-       /* Output registers */
-       volatile u8 *oclrintradr;       /* adr to R_DMA_CHx_CLR_INTR */
-       volatile u32 *ofirstadr;        /* adr to R_DMA_CHx_FIRST */
-       volatile u8 *ocmdadr;           /* adr to R_DMA_CHx_CMD */
-       const volatile u8 *ostatusadr;  /* adr to R_DMA_CHx_STATUS */
-
-       /* Input registers */
-       volatile u8 *iclrintradr;       /* adr to R_DMA_CHx_CLR_INTR */
-       volatile u32 *ifirstadr;        /* adr to R_DMA_CHx_FIRST */
-       volatile u8 *icmdadr;           /* adr to R_DMA_CHx_CMD */
-       volatile u32 *idescradr;        /* adr to R_DMA_CHx_DESCR */
-
-       int flags;      /* defined in tty.h */
-
-       u8 rx_ctrl;     /* shadow for R_SERIALx_REC_CTRL */
-       u8 tx_ctrl;     /* shadow for R_SERIALx_TR_CTRL */
-       u8 iseteop;     /* bit number for R_SET_EOP for the input dma */
-       int enabled;    /* Set to 1 if the port is enabled in HW config */
-
-       u8 dma_out_enabled;     /* Set to 1 if DMA should be used */
-       u8 dma_in_enabled;      /* Set to 1 if DMA should be used */
-
-       /* end of fields defined in rs_table[] in .c-file */
-       int             dma_owner;
-       unsigned int    dma_in_nbr;
-       unsigned int    dma_out_nbr;
-       unsigned int    dma_in_irq_nbr;
-       unsigned int    dma_out_irq_nbr;
-       unsigned long   dma_in_irq_flags;
-       unsigned long   dma_out_irq_flags;
-       char            *dma_in_irq_description;
-       char            *dma_out_irq_description;
-
-       enum cris_io_interface io_if;
-       char            *io_if_description;
-
-       u8              uses_dma_in;  /* Set to 1 if DMA is used */
-       u8              uses_dma_out; /* Set to 1 if DMA is used */
-       u8              forced_eop;   /* a fifo eop has been forced */
-       int                     baud_base;     /* For special baudrates */
-       int                     custom_divisor; /* For special baudrates */
-       struct etrax_dma_descr  tr_descr;
-       struct etrax_dma_descr  rec_descr[SERIAL_RECV_DESCRIPTORS];
-       int                     cur_rec_descr;
-
-       volatile int            tr_running; /* 1 if output is running */
-
-       struct tty_struct       *tty;
-       int                     read_status_mask;
-       int                     ignore_status_mask;
-       int                     x_char; /* xon/xoff character */
-       int                     close_delay;
-       unsigned short          closing_wait;
-       unsigned short          closing_wait2;
-       unsigned long           event;
-       unsigned long           last_active;
-       int                     line;
-       int                     type;  /* PORT_ETRAX */
-       int                     count;      /* # of fd on device */
-       int                     blocked_open; /* # of blocked opens */
-       struct circ_buf         xmit;
-       struct etrax_recv_buffer *first_recv_buffer;
-       struct etrax_recv_buffer *last_recv_buffer;
-       unsigned int            recv_cnt;
-       unsigned int            max_recv_cnt;
-
-       struct work_struct      work;
-       struct async_icount     icount;   /* error-statistics etc.*/
-       struct ktermios         normal_termios;
-       struct ktermios         callout_termios;
-       wait_queue_head_t       open_wait;
-       wait_queue_head_t       close_wait;
-
-       unsigned long char_time_usec;       /* The time for 1 char, in usecs */
-       unsigned long flush_time_usec;      /* How often we should flush */
-       unsigned long last_tx_active_usec;  /* Last tx usec in the jiffies */
-       unsigned long last_tx_active;       /* Last tx time in jiffies */
-       unsigned long last_rx_active_usec;  /* Last rx usec in the jiffies */
-       unsigned long last_rx_active;       /* Last rx time in jiffies */
-
-       int break_detected_cnt;
-       int errorcode;
-
-#ifdef CONFIG_ETRAX_RS485
-       struct serial_rs485     rs485;  /* RS-485 support */
-#endif
-};
-
-/* this PORT is not in the standard serial.h. it's not actually used for
- * anything since we only have one type of async serial-port anyway in this
- * system.
- */
-
-#define PORT_ETRAX 1
-
-/*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at rs interrupt time.
- */
-#define RS_EVENT_WRITE_WAKEUP  0
-
-#endif /* __KERNEL__ */
-
-#endif /* !_ETRAX_SERIAL_H */
diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c
deleted file mode 100644 (file)
index 57421d7..0000000
+++ /dev/null
@@ -1,955 +0,0 @@
-/*
- * dz.c: Serial port driver for DECstations equipped
- *       with the DZ chipset.
- *
- * Copyright (C) 1998 Olivier A. D. Lebaillif
- *
- * Email: olivier.lebaillif@ifrsys.com
- *
- * Copyright (C) 2004, 2006, 2007  Maciej W. Rozycki
- *
- * [31-AUG-98] triemer
- * Changed IRQ to use Harald's dec internals interrupts.h
- * removed base_addr code - moving address assignment to setup.c
- * Changed name of dz_init to rs_init to be consistent with tc code
- * [13-NOV-98] triemer fixed code to receive characters
- *    after patches by harald to irq code.
- * [09-JAN-99] triemer minor fix for schedule - due to removal of timeout
- *            field from "current" - somewhere between 2.1.121 and 2.1.131
- Qua Jun 27 15:02:26 BRT 2001
- * [27-JUN-2001] Arnaldo Carvalho de Melo <acme@conectiva.com.br> - cleanups
- *
- * Parts (C) 1999 David Airlie, airlied@linux.ie
- * [07-SEP-99] Bugfixes
- *
- * [06-Jan-2002] Russell King <rmk@arm.linux.org.uk>
- * Converted to new serial core
- */
-
-#undef DEBUG_DZ
-
-#if defined(CONFIG_SERIAL_DZ_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/bitops.h>
-#include <linux/compiler.h>
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/module.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <linux/sysrq.h>
-#include <linux/tty.h>
-
-#include <asm/atomic.h>
-#include <asm/bootinfo.h>
-#include <asm/io.h>
-#include <asm/system.h>
-
-#include <asm/dec/interrupts.h>
-#include <asm/dec/kn01.h>
-#include <asm/dec/kn02.h>
-#include <asm/dec/machtype.h>
-#include <asm/dec/prom.h>
-#include <asm/dec/system.h>
-
-#include "dz.h"
-
-
-MODULE_DESCRIPTION("DECstation DZ serial driver");
-MODULE_LICENSE("GPL");
-
-
-static char dz_name[] __initdata = "DECstation DZ serial driver version ";
-static char dz_version[] __initdata = "1.04";
-
-struct dz_port {
-       struct dz_mux           *mux;
-       struct uart_port        port;
-       unsigned int            cflag;
-};
-
-struct dz_mux {
-       struct dz_port          dport[DZ_NB_PORT];
-       atomic_t                map_guard;
-       atomic_t                irq_guard;
-       int                     initialised;
-};
-
-static struct dz_mux dz_mux;
-
-static inline struct dz_port *to_dport(struct uart_port *uport)
-{
-       return container_of(uport, struct dz_port, port);
-}
-
-/*
- * ------------------------------------------------------------
- * dz_in () and dz_out ()
- *
- * These routines are used to access the registers of the DZ
- * chip, hiding relocation differences between implementation.
- * ------------------------------------------------------------
- */
-
-static u16 dz_in(struct dz_port *dport, unsigned offset)
-{
-       void __iomem *addr = dport->port.membase + offset;
-
-       return readw(addr);
-}
-
-static void dz_out(struct dz_port *dport, unsigned offset, u16 value)
-{
-       void __iomem *addr = dport->port.membase + offset;
-
-       writew(value, addr);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_stop () and rs_start ()
- *
- * These routines are called before setting or resetting
- * tty->stopped. They enable or disable transmitter interrupts,
- * as necessary.
- * ------------------------------------------------------------
- */
-
-static void dz_stop_tx(struct uart_port *uport)
-{
-       struct dz_port *dport = to_dport(uport);
-       u16 tmp, mask = 1 << dport->port.line;
-
-       tmp = dz_in(dport, DZ_TCR);     /* read the TX flag */
-       tmp &= ~mask;                   /* clear the TX flag */
-       dz_out(dport, DZ_TCR, tmp);
-}
-
-static void dz_start_tx(struct uart_port *uport)
-{
-       struct dz_port *dport = to_dport(uport);
-       u16 tmp, mask = 1 << dport->port.line;
-
-       tmp = dz_in(dport, DZ_TCR);     /* read the TX flag */
-       tmp |= mask;                    /* set the TX flag */
-       dz_out(dport, DZ_TCR, tmp);
-}
-
-static void dz_stop_rx(struct uart_port *uport)
-{
-       struct dz_port *dport = to_dport(uport);
-
-       dport->cflag &= ~DZ_RXENAB;
-       dz_out(dport, DZ_LPR, dport->cflag);
-}
-
-static void dz_enable_ms(struct uart_port *uport)
-{
-       /* nothing to do */
-}
-
-/*
- * ------------------------------------------------------------
- *
- * Here start the interrupt handling routines.  All of the following
- * subroutines are declared as inline and are folded into
- * dz_interrupt.  They were separated out for readability's sake.
- *
- * Note: dz_interrupt() is a "fast" interrupt, which means that it
- * runs with interrupts turned off.  People who may want to modify
- * dz_interrupt() should try to keep the interrupt handler as fast as
- * possible.  After you are done making modifications, it is not a bad
- * idea to do:
- *
- *     make drivers/serial/dz.s
- *
- * and look at the resulting assemble code in dz.s.
- *
- * ------------------------------------------------------------
- */
-
-/*
- * ------------------------------------------------------------
- * receive_char ()
- *
- * This routine deals with inputs from any lines.
- * ------------------------------------------------------------
- */
-static inline void dz_receive_chars(struct dz_mux *mux)
-{
-       struct uart_port *uport;
-       struct dz_port *dport = &mux->dport[0];
-       struct tty_struct *tty = NULL;
-       struct uart_icount *icount;
-       int lines_rx[DZ_NB_PORT] = { [0 ... DZ_NB_PORT - 1] = 0 };
-       unsigned char ch, flag;
-       u16 status;
-       int i;
-
-       while ((status = dz_in(dport, DZ_RBUF)) & DZ_DVAL) {
-               dport = &mux->dport[LINE(status)];
-               uport = &dport->port;
-               tty = uport->state->port.tty;   /* point to the proper dev */
-
-               ch = UCHAR(status);             /* grab the char */
-               flag = TTY_NORMAL;
-
-               icount = &uport->icount;
-               icount->rx++;
-
-               if (unlikely(status & (DZ_OERR | DZ_FERR | DZ_PERR))) {
-
-                       /*
-                        * There is no separate BREAK status bit, so treat
-                        * null characters with framing errors as BREAKs;
-                        * normally, otherwise.  For this move the Framing
-                        * Error bit to a simulated BREAK bit.
-                        */
-                       if (!ch) {
-                               status |= (status & DZ_FERR) >>
-                                         (ffs(DZ_FERR) - ffs(DZ_BREAK));
-                               status &= ~DZ_FERR;
-                       }
-
-                       /* Handle SysRq/SAK & keep track of the statistics. */
-                       if (status & DZ_BREAK) {
-                               icount->brk++;
-                               if (uart_handle_break(uport))
-                                       continue;
-                       } else if (status & DZ_FERR)
-                               icount->frame++;
-                       else if (status & DZ_PERR)
-                               icount->parity++;
-                       if (status & DZ_OERR)
-                               icount->overrun++;
-
-                       status &= uport->read_status_mask;
-                       if (status & DZ_BREAK)
-                               flag = TTY_BREAK;
-                       else if (status & DZ_FERR)
-                               flag = TTY_FRAME;
-                       else if (status & DZ_PERR)
-                               flag = TTY_PARITY;
-
-               }
-
-               if (uart_handle_sysrq_char(uport, ch))
-                       continue;
-
-               uart_insert_char(uport, status, DZ_OERR, ch, flag);
-               lines_rx[LINE(status)] = 1;
-       }
-       for (i = 0; i < DZ_NB_PORT; i++)
-               if (lines_rx[i])
-                       tty_flip_buffer_push(mux->dport[i].port.state->port.tty);
-}
-
-/*
- * ------------------------------------------------------------
- * transmit_char ()
- *
- * This routine deals with outputs to any lines.
- * ------------------------------------------------------------
- */
-static inline void dz_transmit_chars(struct dz_mux *mux)
-{
-       struct dz_port *dport = &mux->dport[0];
-       struct circ_buf *xmit;
-       unsigned char tmp;
-       u16 status;
-
-       status = dz_in(dport, DZ_CSR);
-       dport = &mux->dport[LINE(status)];
-       xmit = &dport->port.state->xmit;
-
-       if (dport->port.x_char) {               /* XON/XOFF chars */
-               dz_out(dport, DZ_TDR, dport->port.x_char);
-               dport->port.icount.tx++;
-               dport->port.x_char = 0;
-               return;
-       }
-       /* If nothing to do or stopped or hardware stopped. */
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&dport->port)) {
-               spin_lock(&dport->port.lock);
-               dz_stop_tx(&dport->port);
-               spin_unlock(&dport->port.lock);
-               return;
-       }
-
-       /*
-        * If something to do... (remember the dz has no output fifo,
-        * so we go one char at a time) :-<
-        */
-       tmp = xmit->buf[xmit->tail];
-       xmit->tail = (xmit->tail + 1) & (DZ_XMIT_SIZE - 1);
-       dz_out(dport, DZ_TDR, tmp);
-       dport->port.icount.tx++;
-
-       if (uart_circ_chars_pending(xmit) < DZ_WAKEUP_CHARS)
-               uart_write_wakeup(&dport->port);
-
-       /* Are we are done. */
-       if (uart_circ_empty(xmit)) {
-               spin_lock(&dport->port.lock);
-               dz_stop_tx(&dport->port);
-               spin_unlock(&dport->port.lock);
-       }
-}
-
-/*
- * ------------------------------------------------------------
- * check_modem_status()
- *
- * DS 3100 & 5100: Only valid for the MODEM line, duh!
- * DS 5000/200: Valid for the MODEM and PRINTER line.
- * ------------------------------------------------------------
- */
-static inline void check_modem_status(struct dz_port *dport)
-{
-       /*
-        * FIXME:
-        * 1. No status change interrupt; use a timer.
-        * 2. Handle the 3100/5000 as appropriate. --macro
-        */
-       u16 status;
-
-       /* If not the modem line just return.  */
-       if (dport->port.line != DZ_MODEM)
-               return;
-
-       status = dz_in(dport, DZ_MSR);
-
-       /* it's easy, since DSR2 is the only bit in the register */
-       if (status)
-               dport->port.icount.dsr++;
-}
-
-/*
- * ------------------------------------------------------------
- * dz_interrupt ()
- *
- * this is the main interrupt routine for the DZ chip.
- * It deals with the multiple ports.
- * ------------------------------------------------------------
- */
-static irqreturn_t dz_interrupt(int irq, void *dev_id)
-{
-       struct dz_mux *mux = dev_id;
-       struct dz_port *dport = &mux->dport[0];
-       u16 status;
-
-       /* get the reason why we just got an irq */
-       status = dz_in(dport, DZ_CSR);
-
-       if ((status & (DZ_RDONE | DZ_RIE)) == (DZ_RDONE | DZ_RIE))
-               dz_receive_chars(mux);
-
-       if ((status & (DZ_TRDY | DZ_TIE)) == (DZ_TRDY | DZ_TIE))
-               dz_transmit_chars(mux);
-
-       return IRQ_HANDLED;
-}
-
-/*
- * -------------------------------------------------------------------
- * Here ends the DZ interrupt routines.
- * -------------------------------------------------------------------
- */
-
-static unsigned int dz_get_mctrl(struct uart_port *uport)
-{
-       /*
-        * FIXME: Handle the 3100/5000 as appropriate. --macro
-        */
-       struct dz_port *dport = to_dport(uport);
-       unsigned int mctrl = TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
-
-       if (dport->port.line == DZ_MODEM) {
-               if (dz_in(dport, DZ_MSR) & DZ_MODEM_DSR)
-                       mctrl &= ~TIOCM_DSR;
-       }
-
-       return mctrl;
-}
-
-static void dz_set_mctrl(struct uart_port *uport, unsigned int mctrl)
-{
-       /*
-        * FIXME: Handle the 3100/5000 as appropriate. --macro
-        */
-       struct dz_port *dport = to_dport(uport);
-       u16 tmp;
-
-       if (dport->port.line == DZ_MODEM) {
-               tmp = dz_in(dport, DZ_TCR);
-               if (mctrl & TIOCM_DTR)
-                       tmp &= ~DZ_MODEM_DTR;
-               else
-                       tmp |= DZ_MODEM_DTR;
-               dz_out(dport, DZ_TCR, tmp);
-       }
-}
-
-/*
- * -------------------------------------------------------------------
- * startup ()
- *
- * various initialization tasks
- * -------------------------------------------------------------------
- */
-static int dz_startup(struct uart_port *uport)
-{
-       struct dz_port *dport = to_dport(uport);
-       struct dz_mux *mux = dport->mux;
-       unsigned long flags;
-       int irq_guard;
-       int ret;
-       u16 tmp;
-
-       irq_guard = atomic_add_return(1, &mux->irq_guard);
-       if (irq_guard != 1)
-               return 0;
-
-       ret = request_irq(dport->port.irq, dz_interrupt,
-                         IRQF_SHARED, "dz", mux);
-       if (ret) {
-               atomic_add(-1, &mux->irq_guard);
-               printk(KERN_ERR "dz: Cannot get IRQ %d!\n", dport->port.irq);
-               return ret;
-       }
-
-       spin_lock_irqsave(&dport->port.lock, flags);
-
-       /* Enable interrupts.  */
-       tmp = dz_in(dport, DZ_CSR);
-       tmp |= DZ_RIE | DZ_TIE;
-       dz_out(dport, DZ_CSR, tmp);
-
-       spin_unlock_irqrestore(&dport->port.lock, flags);
-
-       return 0;
-}
-
-/*
- * -------------------------------------------------------------------
- * shutdown ()
- *
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- * -------------------------------------------------------------------
- */
-static void dz_shutdown(struct uart_port *uport)
-{
-       struct dz_port *dport = to_dport(uport);
-       struct dz_mux *mux = dport->mux;
-       unsigned long flags;
-       int irq_guard;
-       u16 tmp;
-
-       spin_lock_irqsave(&dport->port.lock, flags);
-       dz_stop_tx(&dport->port);
-       spin_unlock_irqrestore(&dport->port.lock, flags);
-
-       irq_guard = atomic_add_return(-1, &mux->irq_guard);
-       if (!irq_guard) {
-               /* Disable interrupts.  */
-               tmp = dz_in(dport, DZ_CSR);
-               tmp &= ~(DZ_RIE | DZ_TIE);
-               dz_out(dport, DZ_CSR, tmp);
-
-               free_irq(dport->port.irq, mux);
-       }
-}
-
-/*
- * -------------------------------------------------------------------
- * dz_tx_empty() -- get the transmitter empty status
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- *          is emptied.  On bus types like RS485, the transmitter must
- *          release the bus after transmitting. This must be done when
- *          the transmit shift register is empty, not be done when the
- *          transmit holding register is empty.  This functionality
- *          allows an RS485 driver to be written in user space.
- * -------------------------------------------------------------------
- */
-static unsigned int dz_tx_empty(struct uart_port *uport)
-{
-       struct dz_port *dport = to_dport(uport);
-       unsigned short tmp, mask = 1 << dport->port.line;
-
-       tmp = dz_in(dport, DZ_TCR);
-       tmp &= mask;
-
-       return tmp ? 0 : TIOCSER_TEMT;
-}
-
-static void dz_break_ctl(struct uart_port *uport, int break_state)
-{
-       /*
-        * FIXME: Can't access BREAK bits in TDR easily;
-        * reuse the code for polled TX. --macro
-        */
-       struct dz_port *dport = to_dport(uport);
-       unsigned long flags;
-       unsigned short tmp, mask = 1 << dport->port.line;
-
-       spin_lock_irqsave(&uport->lock, flags);
-       tmp = dz_in(dport, DZ_TCR);
-       if (break_state)
-               tmp |= mask;
-       else
-               tmp &= ~mask;
-       dz_out(dport, DZ_TCR, tmp);
-       spin_unlock_irqrestore(&uport->lock, flags);
-}
-
-static int dz_encode_baud_rate(unsigned int baud)
-{
-       switch (baud) {
-       case 50:
-               return DZ_B50;
-       case 75:
-               return DZ_B75;
-       case 110:
-               return DZ_B110;
-       case 134:
-               return DZ_B134;
-       case 150:
-               return DZ_B150;
-       case 300:
-               return DZ_B300;
-       case 600:
-               return DZ_B600;
-       case 1200:
-               return DZ_B1200;
-       case 1800:
-               return DZ_B1800;
-       case 2000:
-               return DZ_B2000;
-       case 2400:
-               return DZ_B2400;
-       case 3600:
-               return DZ_B3600;
-       case 4800:
-               return DZ_B4800;
-       case 7200:
-               return DZ_B7200;
-       case 9600:
-               return DZ_B9600;
-       default:
-               return -1;
-       }
-}
-
-
-static void dz_reset(struct dz_port *dport)
-{
-       struct dz_mux *mux = dport->mux;
-
-       if (mux->initialised)
-               return;
-
-       dz_out(dport, DZ_CSR, DZ_CLR);
-       while (dz_in(dport, DZ_CSR) & DZ_CLR);
-       iob();
-
-       /* Enable scanning.  */
-       dz_out(dport, DZ_CSR, DZ_MSE);
-
-       mux->initialised = 1;
-}
-
-static void dz_set_termios(struct uart_port *uport, struct ktermios *termios,
-                          struct ktermios *old_termios)
-{
-       struct dz_port *dport = to_dport(uport);
-       unsigned long flags;
-       unsigned int cflag, baud;
-       int bflag;
-
-       cflag = dport->port.line;
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               cflag |= DZ_CS5;
-               break;
-       case CS6:
-               cflag |= DZ_CS6;
-               break;
-       case CS7:
-               cflag |= DZ_CS7;
-               break;
-       case CS8:
-       default:
-               cflag |= DZ_CS8;
-       }
-
-       if (termios->c_cflag & CSTOPB)
-               cflag |= DZ_CSTOPB;
-       if (termios->c_cflag & PARENB)
-               cflag |= DZ_PARENB;
-       if (termios->c_cflag & PARODD)
-               cflag |= DZ_PARODD;
-
-       baud = uart_get_baud_rate(uport, termios, old_termios, 50, 9600);
-       bflag = dz_encode_baud_rate(baud);
-       if (bflag < 0)  {                       /* Try to keep unchanged.  */
-               baud = uart_get_baud_rate(uport, old_termios, NULL, 50, 9600);
-               bflag = dz_encode_baud_rate(baud);
-               if (bflag < 0)  {               /* Resort to 9600.  */
-                       baud = 9600;
-                       bflag = DZ_B9600;
-               }
-               tty_termios_encode_baud_rate(termios, baud, baud);
-       }
-       cflag |= bflag;
-
-       if (termios->c_cflag & CREAD)
-               cflag |= DZ_RXENAB;
-
-       spin_lock_irqsave(&dport->port.lock, flags);
-
-       uart_update_timeout(uport, termios->c_cflag, baud);
-
-       dz_out(dport, DZ_LPR, cflag);
-       dport->cflag = cflag;
-
-       /* setup accept flag */
-       dport->port.read_status_mask = DZ_OERR;
-       if (termios->c_iflag & INPCK)
-               dport->port.read_status_mask |= DZ_FERR | DZ_PERR;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               dport->port.read_status_mask |= DZ_BREAK;
-
-       /* characters to ignore */
-       uport->ignore_status_mask = 0;
-       if ((termios->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
-               dport->port.ignore_status_mask |= DZ_OERR;
-       if (termios->c_iflag & IGNPAR)
-               dport->port.ignore_status_mask |= DZ_FERR | DZ_PERR;
-       if (termios->c_iflag & IGNBRK)
-               dport->port.ignore_status_mask |= DZ_BREAK;
-
-       spin_unlock_irqrestore(&dport->port.lock, flags);
-}
-
-/*
- * Hack alert!
- * Required solely so that the initial PROM-based console
- * works undisturbed in parallel with this one.
- */
-static void dz_pm(struct uart_port *uport, unsigned int state,
-                 unsigned int oldstate)
-{
-       struct dz_port *dport = to_dport(uport);
-       unsigned long flags;
-
-       spin_lock_irqsave(&dport->port.lock, flags);
-       if (state < 3)
-               dz_start_tx(&dport->port);
-       else
-               dz_stop_tx(&dport->port);
-       spin_unlock_irqrestore(&dport->port.lock, flags);
-}
-
-
-static const char *dz_type(struct uart_port *uport)
-{
-       return "DZ";
-}
-
-static void dz_release_port(struct uart_port *uport)
-{
-       struct dz_mux *mux = to_dport(uport)->mux;
-       int map_guard;
-
-       iounmap(uport->membase);
-       uport->membase = NULL;
-
-       map_guard = atomic_add_return(-1, &mux->map_guard);
-       if (!map_guard)
-               release_mem_region(uport->mapbase, dec_kn_slot_size);
-}
-
-static int dz_map_port(struct uart_port *uport)
-{
-       if (!uport->membase)
-               uport->membase = ioremap_nocache(uport->mapbase,
-                                                dec_kn_slot_size);
-       if (!uport->membase) {
-               printk(KERN_ERR "dz: Cannot map MMIO\n");
-               return -ENOMEM;
-       }
-       return 0;
-}
-
-static int dz_request_port(struct uart_port *uport)
-{
-       struct dz_mux *mux = to_dport(uport)->mux;
-       int map_guard;
-       int ret;
-
-       map_guard = atomic_add_return(1, &mux->map_guard);
-       if (map_guard == 1) {
-               if (!request_mem_region(uport->mapbase, dec_kn_slot_size,
-                                       "dz")) {
-                       atomic_add(-1, &mux->map_guard);
-                       printk(KERN_ERR
-                              "dz: Unable to reserve MMIO resource\n");
-                       return -EBUSY;
-               }
-       }
-       ret = dz_map_port(uport);
-       if (ret) {
-               map_guard = atomic_add_return(-1, &mux->map_guard);
-               if (!map_guard)
-                       release_mem_region(uport->mapbase, dec_kn_slot_size);
-               return ret;
-       }
-       return 0;
-}
-
-static void dz_config_port(struct uart_port *uport, int flags)
-{
-       struct dz_port *dport = to_dport(uport);
-
-       if (flags & UART_CONFIG_TYPE) {
-               if (dz_request_port(uport))
-                       return;
-
-               uport->type = PORT_DZ;
-
-               dz_reset(dport);
-       }
-}
-
-/*
- * Verify the new serial_struct (for TIOCSSERIAL).
- */
-static int dz_verify_port(struct uart_port *uport, struct serial_struct *ser)
-{
-       int ret = 0;
-
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_DZ)
-               ret = -EINVAL;
-       if (ser->irq != uport->irq)
-               ret = -EINVAL;
-       return ret;
-}
-
-static struct uart_ops dz_ops = {
-       .tx_empty       = dz_tx_empty,
-       .get_mctrl      = dz_get_mctrl,
-       .set_mctrl      = dz_set_mctrl,
-       .stop_tx        = dz_stop_tx,
-       .start_tx       = dz_start_tx,
-       .stop_rx        = dz_stop_rx,
-       .enable_ms      = dz_enable_ms,
-       .break_ctl      = dz_break_ctl,
-       .startup        = dz_startup,
-       .shutdown       = dz_shutdown,
-       .set_termios    = dz_set_termios,
-       .pm             = dz_pm,
-       .type           = dz_type,
-       .release_port   = dz_release_port,
-       .request_port   = dz_request_port,
-       .config_port    = dz_config_port,
-       .verify_port    = dz_verify_port,
-};
-
-static void __init dz_init_ports(void)
-{
-       static int first = 1;
-       unsigned long base;
-       int line;
-
-       if (!first)
-               return;
-       first = 0;
-
-       if (mips_machtype == MACH_DS23100 || mips_machtype == MACH_DS5100)
-               base = dec_kn_slot_base + KN01_DZ11;
-       else
-               base = dec_kn_slot_base + KN02_DZ11;
-
-       for (line = 0; line < DZ_NB_PORT; line++) {
-               struct dz_port *dport = &dz_mux.dport[line];
-               struct uart_port *uport = &dport->port;
-
-               dport->mux      = &dz_mux;
-
-               uport->irq      = dec_interrupt[DEC_IRQ_DZ11];
-               uport->fifosize = 1;
-               uport->iotype   = UPIO_MEM;
-               uport->flags    = UPF_BOOT_AUTOCONF;
-               uport->ops      = &dz_ops;
-               uport->line     = line;
-               uport->mapbase  = base;
-       }
-}
-
-#ifdef CONFIG_SERIAL_DZ_CONSOLE
-/*
- * -------------------------------------------------------------------
- * dz_console_putchar() -- transmit a character
- *
- * Polled transmission.  This is tricky.  We need to mask transmit
- * interrupts so that they do not interfere, enable the transmitter
- * for the line requested and then wait till the transmit scanner
- * requests data for this line.  But it may request data for another
- * line first, in which case we have to disable its transmitter and
- * repeat waiting till our line pops up.  Only then the character may
- * be transmitted.  Finally, the state of the transmitter mask is
- * restored.  Welcome to the world of PDP-11!
- * -------------------------------------------------------------------
- */
-static void dz_console_putchar(struct uart_port *uport, int ch)
-{
-       struct dz_port *dport = to_dport(uport);
-       unsigned long flags;
-       unsigned short csr, tcr, trdy, mask;
-       int loops = 10000;
-
-       spin_lock_irqsave(&dport->port.lock, flags);
-       csr = dz_in(dport, DZ_CSR);
-       dz_out(dport, DZ_CSR, csr & ~DZ_TIE);
-       tcr = dz_in(dport, DZ_TCR);
-       tcr |= 1 << dport->port.line;
-       mask = tcr;
-       dz_out(dport, DZ_TCR, mask);
-       iob();
-       spin_unlock_irqrestore(&dport->port.lock, flags);
-
-       do {
-               trdy = dz_in(dport, DZ_CSR);
-               if (!(trdy & DZ_TRDY))
-                       continue;
-               trdy = (trdy & DZ_TLINE) >> 8;
-               if (trdy == dport->port.line)
-                       break;
-               mask &= ~(1 << trdy);
-               dz_out(dport, DZ_TCR, mask);
-               iob();
-               udelay(2);
-       } while (--loops);
-
-       if (loops)                              /* Cannot send otherwise. */
-               dz_out(dport, DZ_TDR, ch);
-
-       dz_out(dport, DZ_TCR, tcr);
-       dz_out(dport, DZ_CSR, csr);
-}
-
-/*
- * -------------------------------------------------------------------
- * dz_console_print ()
- *
- * dz_console_print is registered for printk.
- * The console must be locked when we get here.
- * -------------------------------------------------------------------
- */
-static void dz_console_print(struct console *co,
-                            const char *str,
-                            unsigned int count)
-{
-       struct dz_port *dport = &dz_mux.dport[co->index];
-#ifdef DEBUG_DZ
-       prom_printf((char *) str);
-#endif
-       uart_console_write(&dport->port, str, count, dz_console_putchar);
-}
-
-static int __init dz_console_setup(struct console *co, char *options)
-{
-       struct dz_port *dport = &dz_mux.dport[co->index];
-       struct uart_port *uport = &dport->port;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-       int ret;
-
-       ret = dz_map_port(uport);
-       if (ret)
-               return ret;
-
-       spin_lock_init(&dport->port.lock);      /* For dz_pm().  */
-
-       dz_reset(dport);
-       dz_pm(uport, 0, -1);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(&dport->port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver dz_reg;
-static struct console dz_console = {
-       .name   = "ttyS",
-       .write  = dz_console_print,
-       .device = uart_console_device,
-       .setup  = dz_console_setup,
-       .flags  = CON_PRINTBUFFER,
-       .index  = -1,
-       .data   = &dz_reg,
-};
-
-static int __init dz_serial_console_init(void)
-{
-       if (!IOASIC) {
-               dz_init_ports();
-               register_console(&dz_console);
-               return 0;
-       } else
-               return -ENXIO;
-}
-
-console_initcall(dz_serial_console_init);
-
-#define SERIAL_DZ_CONSOLE      &dz_console
-#else
-#define SERIAL_DZ_CONSOLE      NULL
-#endif /* CONFIG_SERIAL_DZ_CONSOLE */
-
-static struct uart_driver dz_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "serial",
-       .dev_name               = "ttyS",
-       .major                  = TTY_MAJOR,
-       .minor                  = 64,
-       .nr                     = DZ_NB_PORT,
-       .cons                   = SERIAL_DZ_CONSOLE,
-};
-
-static int __init dz_init(void)
-{
-       int ret, i;
-
-       if (IOASIC)
-               return -ENXIO;
-
-       printk("%s%s\n", dz_name, dz_version);
-
-       dz_init_ports();
-
-       ret = uart_register_driver(&dz_reg);
-       if (ret)
-               return ret;
-
-       for (i = 0; i < DZ_NB_PORT; i++)
-               uart_add_one_port(&dz_reg, &dz_mux.dport[i].port);
-
-       return 0;
-}
-
-module_init(dz_init);
diff --git a/drivers/serial/dz.h b/drivers/serial/dz.h
deleted file mode 100644 (file)
index faf169e..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * dz.h: Serial port driver for DECstations equipped
- *       with the DZ chipset.
- *
- * Copyright (C) 1998 Olivier A. D. Lebaillif 
- *             
- * Email: olivier.lebaillif@ifrsys.com
- *
- * Copyright (C) 2004, 2006  Maciej W. Rozycki
- */
-#ifndef DZ_SERIAL_H
-#define DZ_SERIAL_H
-
-/*
- * Definitions for the Control and Status Register.
- */
-#define DZ_TRDY        0x8000                 /* Transmitter empty */
-#define DZ_TIE         0x4000                 /* Transmitter Interrupt Enbl */
-#define DZ_TLINE       0x0300                 /* Transmitter Line Number */
-#define DZ_RDONE       0x0080                 /* Receiver data ready */
-#define DZ_RIE         0x0040                 /* Receive Interrupt Enable */
-#define DZ_MSE         0x0020                 /* Master Scan Enable */
-#define DZ_CLR         0x0010                 /* Master reset */
-#define DZ_MAINT       0x0008                 /* Loop Back Mode */
-
-/*
- * Definitions for the Receiver Buffer Register.
- */
-#define DZ_RBUF_MASK   0x00FF                 /* Data Mask */
-#define DZ_LINE_MASK   0x0300                 /* Line Mask */
-#define DZ_DVAL        0x8000                 /* Valid Data indicator */
-#define DZ_OERR        0x4000                 /* Overrun error indicator */
-#define DZ_FERR        0x2000                 /* Frame error indicator */
-#define DZ_PERR        0x1000                 /* Parity error indicator */
-
-#define DZ_BREAK       0x0800                 /* BREAK event software flag */
-
-#define LINE(x) ((x & DZ_LINE_MASK) >> 8)     /* Get the line number
-                                                 from the input buffer */
-#define UCHAR(x) ((unsigned char)(x & DZ_RBUF_MASK))
-
-/*
- * Definitions for the Transmit Control Register.
- */
-#define DZ_LINE_KEYBOARD 0x0001
-#define DZ_LINE_MOUSE    0x0002
-#define DZ_LINE_MODEM    0x0004
-#define DZ_LINE_PRINTER  0x0008
-
-#define DZ_MODEM_RTS     0x0800               /* RTS for the modem line (2) */
-#define DZ_MODEM_DTR     0x0400               /* DTR for the modem line (2) */
-#define DZ_PRINT_RTS     0x0200               /* RTS for the prntr line (3) */
-#define DZ_PRINT_DTR     0x0100               /* DTR for the prntr line (3) */
-#define DZ_LNENB         0x000f               /* Transmitter Line Enable */
-
-/*
- * Definitions for the Modem Status Register.
- */
-#define DZ_MODEM_RI      0x0800               /* RI for the modem line (2) */
-#define DZ_MODEM_CD      0x0400               /* CD for the modem line (2) */
-#define DZ_MODEM_DSR     0x0200               /* DSR for the modem line (2) */
-#define DZ_MODEM_CTS     0x0100               /* CTS for the modem line (2) */
-#define DZ_PRINT_RI      0x0008               /* RI for the printer line (3) */
-#define DZ_PRINT_CD      0x0004               /* CD for the printer line (3) */
-#define DZ_PRINT_DSR     0x0002               /* DSR for the prntr line (3) */
-#define DZ_PRINT_CTS     0x0001               /* CTS for the prntr line (3) */
-
-/*
- * Definitions for the Transmit Data Register.
- */
-#define DZ_BRK0          0x0100               /* Break assertion for line 0 */
-#define DZ_BRK1          0x0200               /* Break assertion for line 1 */
-#define DZ_BRK2          0x0400               /* Break assertion for line 2 */
-#define DZ_BRK3          0x0800               /* Break assertion for line 3 */
-
-/*
- * Definitions for the Line Parameter Register.
- */
-#define DZ_KEYBOARD      0x0000               /* line 0 = keyboard */
-#define DZ_MOUSE         0x0001               /* line 1 = mouse */
-#define DZ_MODEM         0x0002               /* line 2 = modem */
-#define DZ_PRINTER       0x0003               /* line 3 = printer */
-
-#define DZ_CSIZE         0x0018               /* Number of bits per byte (mask) */
-#define DZ_CS5           0x0000               /* 5 bits per byte */
-#define DZ_CS6           0x0008               /* 6 bits per byte */
-#define DZ_CS7           0x0010               /* 7 bits per byte */
-#define DZ_CS8           0x0018               /* 8 bits per byte */
-
-#define DZ_CSTOPB        0x0020               /* 2 stop bits instead of one */ 
-
-#define DZ_PARENB        0x0040               /* Parity enable */
-#define DZ_PARODD        0x0080               /* Odd parity instead of even */
-
-#define DZ_CBAUD         0x0E00               /* Baud Rate (mask) */
-#define DZ_B50           0x0000
-#define DZ_B75           0x0100
-#define DZ_B110          0x0200
-#define DZ_B134          0x0300
-#define DZ_B150          0x0400
-#define DZ_B300          0x0500
-#define DZ_B600          0x0600
-#define DZ_B1200         0x0700 
-#define DZ_B1800         0x0800
-#define DZ_B2000         0x0900
-#define DZ_B2400         0x0A00
-#define DZ_B3600         0x0B00
-#define DZ_B4800         0x0C00
-#define DZ_B7200         0x0D00
-#define DZ_B9600         0x0E00
-
-#define DZ_RXENAB        0x1000               /* Receiver Enable */
-
-/*
- * Addresses for the DZ registers
- */
-#define DZ_CSR       0x00            /* Control and Status Register */
-#define DZ_RBUF      0x08            /* Receive Buffer */
-#define DZ_LPR       0x08            /* Line Parameters Register */
-#define DZ_TCR       0x10            /* Transmitter Control Register */
-#define DZ_MSR       0x18            /* Modem Status Register */
-#define DZ_TDR       0x18            /* Transmit Data Register */
-
-#define DZ_NB_PORT 4
-
-#define DZ_XMIT_SIZE   4096                 /* buffer size */
-#define DZ_WAKEUP_CHARS   DZ_XMIT_SIZE/4
-
-#endif /* DZ_SERIAL_H */
diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c
deleted file mode 100644 (file)
index 53a4682..0000000
+++ /dev/null
@@ -1,1658 +0,0 @@
-/*
-  * icom.c
-  *
-  * Copyright (C) 2001 IBM Corporation. All rights reserved.
-  *
-  * Serial device driver.
-  *
-  * Based on code from serial.c
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-  * the Free Software Foundation; either version 2 of the License, or
-  * (at your option) any later version.
-  *
-  * This program is distributed in the hope that it will be useful,
-  * but WITHOUT ANY WARRANTY; without even the implied warranty of
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  * GNU General Public License for more details.
-  *
-  * You should have received a copy of the GNU General Public License
-  * along with this program; if not, write to the Free Software
-  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-  *
-  */
-#define SERIAL_DO_RESTART
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/termios.h>
-#include <linux/fs.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/serial_reg.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/delay.h>
-#include <linux/pci.h>
-#include <linux/vmalloc.h>
-#include <linux/smp.h>
-#include <linux/spinlock.h>
-#include <linux/kref.h>
-#include <linux/firmware.h>
-#include <linux/bitops.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-
-#include "icom.h"
-
-/*#define ICOM_TRACE            enable port trace capabilities */
-
-#define ICOM_DRIVER_NAME "icom"
-#define ICOM_VERSION_STR "1.3.1"
-#define NR_PORTS              128
-#define ICOM_PORT ((struct icom_port *)port)
-#define to_icom_adapter(d) container_of(d, struct icom_adapter, kref)
-
-static const struct pci_device_id icom_pci_table[] = {
-       {
-               .vendor = PCI_VENDOR_ID_IBM,
-               .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_1,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = ADAPTER_V1,
-       },
-       {
-               .vendor = PCI_VENDOR_ID_IBM,
-               .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
-               .subvendor = PCI_VENDOR_ID_IBM,
-               .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_TWO_PORTS_RVX,
-               .driver_data = ADAPTER_V2,
-       },
-       {
-               .vendor = PCI_VENDOR_ID_IBM,
-               .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
-               .subvendor = PCI_VENDOR_ID_IBM,
-               .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM,
-               .driver_data = ADAPTER_V2,
-       },
-       {
-               .vendor = PCI_VENDOR_ID_IBM,
-               .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
-               .subvendor = PCI_VENDOR_ID_IBM,
-               .subdevice = PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL,
-               .driver_data = ADAPTER_V2,
-       },
-       {
-               .vendor = PCI_VENDOR_ID_IBM,
-               .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
-               .subvendor = PCI_VENDOR_ID_IBM,
-               .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM_PCIE,
-               .driver_data = ADAPTER_V2,
-       },
-       {}
-};
-
-struct lookup_proc_table start_proc[4] = {
-       {NULL, ICOM_CONTROL_START_A},
-       {NULL, ICOM_CONTROL_START_B},
-       {NULL, ICOM_CONTROL_START_C},
-       {NULL, ICOM_CONTROL_START_D}
-};
-
-
-struct lookup_proc_table stop_proc[4] = {
-       {NULL, ICOM_CONTROL_STOP_A},
-       {NULL, ICOM_CONTROL_STOP_B},
-       {NULL, ICOM_CONTROL_STOP_C},
-       {NULL, ICOM_CONTROL_STOP_D}
-};
-
-struct lookup_int_table int_mask_tbl[4] = {
-       {NULL, ICOM_INT_MASK_PRC_A},
-       {NULL, ICOM_INT_MASK_PRC_B},
-       {NULL, ICOM_INT_MASK_PRC_C},
-       {NULL, ICOM_INT_MASK_PRC_D},
-};
-
-
-MODULE_DEVICE_TABLE(pci, icom_pci_table);
-
-static LIST_HEAD(icom_adapter_head);
-
-/* spinlock for adapter initialization and changing adapter operations */
-static spinlock_t icom_lock;
-
-#ifdef ICOM_TRACE
-static inline void trace(struct icom_port *icom_port, char *trace_pt,
-                       unsigned long trace_data)
-{
-       dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n",
-       icom_port->port, trace_pt, trace_data);
-}
-#else
-static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {};
-#endif
-static void icom_kref_release(struct kref *kref);
-
-static void free_port_memory(struct icom_port *icom_port)
-{
-       struct pci_dev *dev = icom_port->adapter->pci_dev;
-
-       trace(icom_port, "RET_PORT_MEM", 0);
-       if (icom_port->recv_buf) {
-               pci_free_consistent(dev, 4096, icom_port->recv_buf,
-                                   icom_port->recv_buf_pci);
-               icom_port->recv_buf = NULL;
-       }
-       if (icom_port->xmit_buf) {
-               pci_free_consistent(dev, 4096, icom_port->xmit_buf,
-                                   icom_port->xmit_buf_pci);
-               icom_port->xmit_buf = NULL;
-       }
-       if (icom_port->statStg) {
-               pci_free_consistent(dev, 4096, icom_port->statStg,
-                                   icom_port->statStg_pci);
-               icom_port->statStg = NULL;
-       }
-
-       if (icom_port->xmitRestart) {
-               pci_free_consistent(dev, 4096, icom_port->xmitRestart,
-                                   icom_port->xmitRestart_pci);
-               icom_port->xmitRestart = NULL;
-       }
-}
-
-static int __devinit get_port_memory(struct icom_port *icom_port)
-{
-       int index;
-       unsigned long stgAddr;
-       unsigned long startStgAddr;
-       unsigned long offset;
-       struct pci_dev *dev = icom_port->adapter->pci_dev;
-
-       icom_port->xmit_buf =
-           pci_alloc_consistent(dev, 4096, &icom_port->xmit_buf_pci);
-       if (!icom_port->xmit_buf) {
-               dev_err(&dev->dev, "Can not allocate Transmit buffer\n");
-               return -ENOMEM;
-       }
-
-       trace(icom_port, "GET_PORT_MEM",
-             (unsigned long) icom_port->xmit_buf);
-
-       icom_port->recv_buf =
-           pci_alloc_consistent(dev, 4096, &icom_port->recv_buf_pci);
-       if (!icom_port->recv_buf) {
-               dev_err(&dev->dev, "Can not allocate Receive buffer\n");
-               free_port_memory(icom_port);
-               return -ENOMEM;
-       }
-       trace(icom_port, "GET_PORT_MEM",
-             (unsigned long) icom_port->recv_buf);
-
-       icom_port->statStg =
-           pci_alloc_consistent(dev, 4096, &icom_port->statStg_pci);
-       if (!icom_port->statStg) {
-               dev_err(&dev->dev, "Can not allocate Status buffer\n");
-               free_port_memory(icom_port);
-               return -ENOMEM;
-       }
-       trace(icom_port, "GET_PORT_MEM",
-             (unsigned long) icom_port->statStg);
-
-       icom_port->xmitRestart =
-           pci_alloc_consistent(dev, 4096, &icom_port->xmitRestart_pci);
-       if (!icom_port->xmitRestart) {
-               dev_err(&dev->dev,
-                       "Can not allocate xmit Restart buffer\n");
-               free_port_memory(icom_port);
-               return -ENOMEM;
-       }
-
-       memset(icom_port->statStg, 0, 4096);
-
-       /* FODs: Frame Out Descriptor Queue, this is a FIFO queue that
-           indicates that frames are to be transmitted
-       */
-
-       stgAddr = (unsigned long) icom_port->statStg;
-       for (index = 0; index < NUM_XBUFFS; index++) {
-               trace(icom_port, "FOD_ADDR", stgAddr);
-               stgAddr = stgAddr + sizeof(icom_port->statStg->xmit[0]);
-               if (index < (NUM_XBUFFS - 1)) {
-                       memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area));
-                       icom_port->statStg->xmit[index].leLengthASD =
-                           (unsigned short int) cpu_to_le16(XMIT_BUFF_SZ);
-                       trace(icom_port, "FOD_ADDR", stgAddr);
-                       trace(icom_port, "FOD_XBUFF",
-                             (unsigned long) icom_port->xmit_buf);
-                       icom_port->statStg->xmit[index].leBuffer =
-                           cpu_to_le32(icom_port->xmit_buf_pci);
-               } else if (index == (NUM_XBUFFS - 1)) {
-                       memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area));
-                       icom_port->statStg->xmit[index].leLengthASD =
-                           (unsigned short int) cpu_to_le16(XMIT_BUFF_SZ);
-                       trace(icom_port, "FOD_XBUFF",
-                             (unsigned long) icom_port->xmit_buf);
-                       icom_port->statStg->xmit[index].leBuffer =
-                           cpu_to_le32(icom_port->xmit_buf_pci);
-               } else {
-                       memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area));
-               }
-       }
-       /* FIDs */
-       startStgAddr = stgAddr;
-
-       /* fill in every entry, even if no buffer */
-       for (index = 0; index <  NUM_RBUFFS; index++) {
-               trace(icom_port, "FID_ADDR", stgAddr);
-               stgAddr = stgAddr + sizeof(icom_port->statStg->rcv[0]);
-               icom_port->statStg->rcv[index].leLength = 0;
-               icom_port->statStg->rcv[index].WorkingLength =
-                   (unsigned short int) cpu_to_le16(RCV_BUFF_SZ);
-               if (index < (NUM_RBUFFS - 1) ) {
-                       offset = stgAddr - (unsigned long) icom_port->statStg;
-                       icom_port->statStg->rcv[index].leNext =
-                             cpu_to_le32(icom_port-> statStg_pci + offset);
-                       trace(icom_port, "FID_RBUFF",
-                             (unsigned long) icom_port->recv_buf);
-                       icom_port->statStg->rcv[index].leBuffer =
-                           cpu_to_le32(icom_port->recv_buf_pci);
-               } else if (index == (NUM_RBUFFS -1) ) {
-                       offset = startStgAddr - (unsigned long) icom_port->statStg;
-                       icom_port->statStg->rcv[index].leNext =
-                           cpu_to_le32(icom_port-> statStg_pci + offset);
-                       trace(icom_port, "FID_RBUFF",
-                             (unsigned long) icom_port->recv_buf + 2048);
-                       icom_port->statStg->rcv[index].leBuffer =
-                           cpu_to_le32(icom_port->recv_buf_pci + 2048);
-               } else {
-                       icom_port->statStg->rcv[index].leNext = 0;
-                       icom_port->statStg->rcv[index].leBuffer = 0;
-               }
-       }
-
-       return 0;
-}
-
-static void stop_processor(struct icom_port *icom_port)
-{
-       unsigned long temp;
-       unsigned long flags;
-       int port;
-
-       spin_lock_irqsave(&icom_lock, flags);
-
-       port = icom_port->port;
-       if (port == 0 || port == 1)
-               stop_proc[port].global_control_reg = &icom_port->global_reg->control;
-       else
-               stop_proc[port].global_control_reg = &icom_port->global_reg->control_2;
-
-
-       if (port < 4) {
-               temp = readl(stop_proc[port].global_control_reg);
-               temp =
-                       (temp & ~start_proc[port].processor_id) | stop_proc[port].processor_id;
-               writel(temp, stop_proc[port].global_control_reg);
-
-               /* write flush */
-               readl(stop_proc[port].global_control_reg);
-       } else {
-               dev_err(&icom_port->adapter->pci_dev->dev,
-                        "Invalid port assignment\n");
-       }
-
-       spin_unlock_irqrestore(&icom_lock, flags);
-}
-
-static void start_processor(struct icom_port *icom_port)
-{
-       unsigned long temp;
-       unsigned long flags;
-       int port;
-
-       spin_lock_irqsave(&icom_lock, flags);
-
-       port = icom_port->port;
-       if (port == 0 || port == 1)
-               start_proc[port].global_control_reg = &icom_port->global_reg->control;
-       else
-               start_proc[port].global_control_reg = &icom_port->global_reg->control_2;
-       if (port < 4) {
-               temp = readl(start_proc[port].global_control_reg);
-               temp =
-                       (temp & ~stop_proc[port].processor_id) | start_proc[port].processor_id;
-               writel(temp, start_proc[port].global_control_reg);
-
-               /* write flush */
-               readl(start_proc[port].global_control_reg);
-       } else {
-               dev_err(&icom_port->adapter->pci_dev->dev,
-                        "Invalid port assignment\n");
-       }
-
-       spin_unlock_irqrestore(&icom_lock, flags);
-}
-
-static void load_code(struct icom_port *icom_port)
-{
-       const struct firmware *fw;
-       char __iomem *iram_ptr;
-       int index;
-       int status = 0;
-       void __iomem *dram_ptr = icom_port->dram;
-       dma_addr_t temp_pci;
-       unsigned char *new_page = NULL;
-       unsigned char cable_id = NO_CABLE;
-       struct pci_dev *dev = icom_port->adapter->pci_dev;
-
-       /* Clear out any pending interrupts */
-       writew(0x3FFF, icom_port->int_reg);
-
-       trace(icom_port, "CLEAR_INTERRUPTS", 0);
-
-       /* Stop processor */
-       stop_processor(icom_port);
-
-       /* Zero out DRAM */
-       memset_io(dram_ptr, 0, 512);
-
-       /* Load Call Setup into Adapter */
-       if (request_firmware(&fw, "icom_call_setup.bin", &dev->dev) < 0) {
-               dev_err(&dev->dev,"Unable to load icom_call_setup.bin firmware image\n");
-               status = -1;
-               goto load_code_exit;
-       }
-
-       if (fw->size > ICOM_DCE_IRAM_OFFSET) {
-               dev_err(&dev->dev, "Invalid firmware image for icom_call_setup.bin found.\n");
-               release_firmware(fw);
-               status = -1;
-               goto load_code_exit;
-       }
-
-       iram_ptr = (char __iomem *)icom_port->dram + ICOM_IRAM_OFFSET;
-       for (index = 0; index < fw->size; index++)
-               writeb(fw->data[index], &iram_ptr[index]);
-
-       release_firmware(fw);
-
-       /* Load Resident DCE portion of Adapter */
-       if (request_firmware(&fw, "icom_res_dce.bin", &dev->dev) < 0) {
-               dev_err(&dev->dev,"Unable to load icom_res_dce.bin firmware image\n");
-               status = -1;
-               goto load_code_exit;
-       }
-
-       if (fw->size > ICOM_IRAM_SIZE) {
-               dev_err(&dev->dev, "Invalid firmware image for icom_res_dce.bin found.\n");
-               release_firmware(fw);
-               status = -1;
-               goto load_code_exit;
-       }
-
-       iram_ptr = (char __iomem *) icom_port->dram + ICOM_IRAM_OFFSET;
-       for (index = ICOM_DCE_IRAM_OFFSET; index < fw->size; index++)
-               writeb(fw->data[index], &iram_ptr[index]);
-
-       release_firmware(fw);
-
-       /* Set Hardware level */
-       if (icom_port->adapter->version == ADAPTER_V2)
-               writeb(V2_HARDWARE, &(icom_port->dram->misc_flags));
-
-       /* Start the processor in Adapter */
-       start_processor(icom_port);
-
-       writeb((HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL),
-              &(icom_port->dram->HDLCConfigReg));
-       writeb(0x04, &(icom_port->dram->FlagFillIdleTimer));    /* 0.5 seconds */
-       writeb(0x00, &(icom_port->dram->CmdReg));
-       writeb(0x10, &(icom_port->dram->async_config3));
-       writeb((ICOM_ACFG_DRIVE1 | ICOM_ACFG_NO_PARITY | ICOM_ACFG_8BPC |
-               ICOM_ACFG_1STOP_BIT), &(icom_port->dram->async_config2));
-
-       /*Set up data in icom DRAM to indicate where personality
-        *code is located and its length.
-        */
-       new_page = pci_alloc_consistent(dev, 4096, &temp_pci);
-
-       if (!new_page) {
-               dev_err(&dev->dev, "Can not allocate DMA buffer\n");
-               status = -1;
-               goto load_code_exit;
-       }
-
-       if (request_firmware(&fw, "icom_asc.bin", &dev->dev) < 0) {
-               dev_err(&dev->dev,"Unable to load icom_asc.bin firmware image\n");
-               status = -1;
-               goto load_code_exit;
-       }
-
-       if (fw->size > ICOM_DCE_IRAM_OFFSET) {
-               dev_err(&dev->dev, "Invalid firmware image for icom_asc.bin found.\n");
-               release_firmware(fw);
-               status = -1;
-               goto load_code_exit;
-       }
-
-       for (index = 0; index < fw->size; index++)
-               new_page[index] = fw->data[index];
-
-       release_firmware(fw);
-
-       writeb((char) ((fw->size + 16)/16), &icom_port->dram->mac_length);
-       writel(temp_pci, &icom_port->dram->mac_load_addr);
-
-       /*Setting the syncReg to 0x80 causes adapter to start downloading
-          the personality code into adapter instruction RAM.
-          Once code is loaded, it will begin executing and, based on
-          information provided above, will start DMAing data from
-          shared memory to adapter DRAM.
-        */
-       /* the wait loop below verifies this write operation has been done
-          and processed
-       */
-       writeb(START_DOWNLOAD, &icom_port->dram->sync);
-
-       /* Wait max 1 Sec for data download and processor to start */
-       for (index = 0; index < 10; index++) {
-               msleep(100);
-               if (readb(&icom_port->dram->misc_flags) & ICOM_HDW_ACTIVE)
-                       break;
-       }
-
-       if (index == 10)
-               status = -1;
-
-       /*
-        * check Cable ID
-        */
-       cable_id = readb(&icom_port->dram->cable_id);
-
-       if (cable_id & ICOM_CABLE_ID_VALID) {
-               /* Get cable ID into the lower 4 bits (standard form) */
-               cable_id = (cable_id & ICOM_CABLE_ID_MASK) >> 4;
-               icom_port->cable_id = cable_id;
-       } else {
-               dev_err(&dev->dev,"Invalid or no cable attached\n");
-               icom_port->cable_id = NO_CABLE;
-       }
-
-      load_code_exit:
-
-       if (status != 0) {
-               /* Clear out any pending interrupts */
-               writew(0x3FFF, icom_port->int_reg);
-
-               /* Turn off port */
-               writeb(ICOM_DISABLE, &(icom_port->dram->disable));
-
-               /* Stop processor */
-               stop_processor(icom_port);
-
-               dev_err(&icom_port->adapter->pci_dev->dev,"Port not opertional\n");
-       }
-
-       if (new_page != NULL)
-               pci_free_consistent(dev, 4096, new_page, temp_pci);
-}
-
-static int startup(struct icom_port *icom_port)
-{
-       unsigned long temp;
-       unsigned char cable_id, raw_cable_id;
-       unsigned long flags;
-       int port;
-
-       trace(icom_port, "STARTUP", 0);
-
-       if (!icom_port->dram) {
-               /* should NEVER be NULL */
-               dev_err(&icom_port->adapter->pci_dev->dev,
-                       "Unusable Port, port configuration missing\n");
-               return -ENODEV;
-       }
-
-       /*
-        * check Cable ID
-        */
-       raw_cable_id = readb(&icom_port->dram->cable_id);
-       trace(icom_port, "CABLE_ID", raw_cable_id);
-
-       /* Get cable ID into the lower 4 bits (standard form) */
-       cable_id = (raw_cable_id & ICOM_CABLE_ID_MASK) >> 4;
-
-       /* Check for valid Cable ID */
-       if (!(raw_cable_id & ICOM_CABLE_ID_VALID) ||
-           (cable_id != icom_port->cable_id)) {
-
-               /* reload adapter code, pick up any potential changes in cable id */
-               load_code(icom_port);
-
-               /* still no sign of cable, error out */
-               raw_cable_id = readb(&icom_port->dram->cable_id);
-               cable_id = (raw_cable_id & ICOM_CABLE_ID_MASK) >> 4;
-               if (!(raw_cable_id & ICOM_CABLE_ID_VALID) ||
-                   (icom_port->cable_id == NO_CABLE))
-                       return -EIO;
-       }
-
-       /*
-        * Finally, clear and  enable interrupts
-        */
-       spin_lock_irqsave(&icom_lock, flags);
-       port = icom_port->port;
-       if (port == 0 || port == 1)
-               int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask;
-       else
-               int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2;
-
-       if (port == 0 || port == 2)
-               writew(0x00FF, icom_port->int_reg);
-       else
-               writew(0x3F00, icom_port->int_reg);
-       if (port < 4) {
-               temp = readl(int_mask_tbl[port].global_int_mask);
-               writel(temp & ~int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask);
-
-               /* write flush */
-               readl(int_mask_tbl[port].global_int_mask);
-       } else {
-               dev_err(&icom_port->adapter->pci_dev->dev,
-                        "Invalid port assignment\n");
-       }
-
-       spin_unlock_irqrestore(&icom_lock, flags);
-       return 0;
-}
-
-static void shutdown(struct icom_port *icom_port)
-{
-       unsigned long temp;
-       unsigned char cmdReg;
-       unsigned long flags;
-       int port;
-
-       spin_lock_irqsave(&icom_lock, flags);
-       trace(icom_port, "SHUTDOWN", 0);
-
-       /*
-        * disable all interrupts
-        */
-       port = icom_port->port;
-       if (port == 0 || port == 1)
-               int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask;
-       else
-               int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2;
-
-       if (port < 4) {
-               temp = readl(int_mask_tbl[port].global_int_mask);
-               writel(temp | int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask);
-
-               /* write flush */
-               readl(int_mask_tbl[port].global_int_mask);
-       } else {
-               dev_err(&icom_port->adapter->pci_dev->dev,
-                        "Invalid port assignment\n");
-       }
-       spin_unlock_irqrestore(&icom_lock, flags);
-
-       /*
-        * disable break condition
-        */
-       cmdReg = readb(&icom_port->dram->CmdReg);
-       if (cmdReg & CMD_SND_BREAK) {
-               writeb(cmdReg & ~CMD_SND_BREAK, &icom_port->dram->CmdReg);
-       }
-}
-
-static int icom_write(struct uart_port *port)
-{
-       unsigned long data_count;
-       unsigned char cmdReg;
-       unsigned long offset;
-       int temp_tail = port->state->xmit.tail;
-
-       trace(ICOM_PORT, "WRITE", 0);
-
-       if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) &
-           SA_FLAGS_READY_TO_XMIT) {
-               trace(ICOM_PORT, "WRITE_FULL", 0);
-               return 0;
-       }
-
-       data_count = 0;
-       while ((port->state->xmit.head != temp_tail) &&
-              (data_count <= XMIT_BUFF_SZ)) {
-
-               ICOM_PORT->xmit_buf[data_count++] =
-                   port->state->xmit.buf[temp_tail];
-
-               temp_tail++;
-               temp_tail &= (UART_XMIT_SIZE - 1);
-       }
-
-       if (data_count) {
-               ICOM_PORT->statStg->xmit[0].flags =
-                   cpu_to_le16(SA_FLAGS_READY_TO_XMIT);
-               ICOM_PORT->statStg->xmit[0].leLength =
-                   cpu_to_le16(data_count);
-               offset =
-                   (unsigned long) &ICOM_PORT->statStg->xmit[0] -
-                   (unsigned long) ICOM_PORT->statStg;
-               *ICOM_PORT->xmitRestart =
-                   cpu_to_le32(ICOM_PORT->statStg_pci + offset);
-               cmdReg = readb(&ICOM_PORT->dram->CmdReg);
-               writeb(cmdReg | CMD_XMIT_RCV_ENABLE,
-                      &ICOM_PORT->dram->CmdReg);
-               writeb(START_XMIT, &ICOM_PORT->dram->StartXmitCmd);
-               trace(ICOM_PORT, "WRITE_START", data_count);
-               /* write flush */
-               readb(&ICOM_PORT->dram->StartXmitCmd);
-       }
-
-       return data_count;
-}
-
-static inline void check_modem_status(struct icom_port *icom_port)
-{
-       static char old_status = 0;
-       char delta_status;
-       unsigned char status;
-
-       spin_lock(&icom_port->uart_port.lock);
-
-       /*modem input register */
-       status = readb(&icom_port->dram->isr);
-       trace(icom_port, "CHECK_MODEM", status);
-       delta_status = status ^ old_status;
-       if (delta_status) {
-               if (delta_status & ICOM_RI)
-                       icom_port->uart_port.icount.rng++;
-               if (delta_status & ICOM_DSR)
-                       icom_port->uart_port.icount.dsr++;
-               if (delta_status & ICOM_DCD)
-                       uart_handle_dcd_change(&icom_port->uart_port,
-                                              delta_status & ICOM_DCD);
-               if (delta_status & ICOM_CTS)
-                       uart_handle_cts_change(&icom_port->uart_port,
-                                              delta_status & ICOM_CTS);
-
-               wake_up_interruptible(&icom_port->uart_port.state->
-                                     port.delta_msr_wait);
-               old_status = status;
-       }
-       spin_unlock(&icom_port->uart_port.lock);
-}
-
-static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port)
-{
-       unsigned short int count;
-       int i;
-
-       if (port_int_reg & (INT_XMIT_COMPLETED)) {
-               trace(icom_port, "XMIT_COMPLETE", 0);
-
-               /* clear buffer in use bit */
-               icom_port->statStg->xmit[0].flags &=
-                       cpu_to_le16(~SA_FLAGS_READY_TO_XMIT);
-
-               count = (unsigned short int)
-                       cpu_to_le16(icom_port->statStg->xmit[0].leLength);
-               icom_port->uart_port.icount.tx += count;
-
-               for (i=0; i<count &&
-                       !uart_circ_empty(&icom_port->uart_port.state->xmit); i++) {
-
-                       icom_port->uart_port.state->xmit.tail++;
-                       icom_port->uart_port.state->xmit.tail &=
-                               (UART_XMIT_SIZE - 1);
-               }
-
-               if (!icom_write(&icom_port->uart_port))
-                       /* activate write queue */
-                       uart_write_wakeup(&icom_port->uart_port);
-       } else
-               trace(icom_port, "XMIT_DISABLED", 0);
-}
-
-static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port)
-{
-       short int count, rcv_buff;
-       struct tty_struct *tty = icom_port->uart_port.state->port.tty;
-       unsigned short int status;
-       struct uart_icount *icount;
-       unsigned long offset;
-       unsigned char flag;
-
-       trace(icom_port, "RCV_COMPLETE", 0);
-       rcv_buff = icom_port->next_rcv;
-
-       status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags);
-       while (status & SA_FL_RCV_DONE) {
-               int first = -1;
-
-               trace(icom_port, "FID_STATUS", status);
-               count = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].leLength);
-
-               trace(icom_port, "RCV_COUNT", count);
-
-               trace(icom_port, "REAL_COUNT", count);
-
-               offset =
-                       cpu_to_le32(icom_port->statStg->rcv[rcv_buff].leBuffer) -
-                       icom_port->recv_buf_pci;
-
-               /* Block copy all but the last byte as this may have status */
-               if (count > 0) {
-                       first = icom_port->recv_buf[offset];
-                       tty_insert_flip_string(tty, icom_port->recv_buf + offset, count - 1);
-               }
-
-               icount = &icom_port->uart_port.icount;
-               icount->rx += count;
-
-               /* Break detect logic */
-               if ((status & SA_FLAGS_FRAME_ERROR)
-                   && first == 0) {
-                       status &= ~SA_FLAGS_FRAME_ERROR;
-                       status |= SA_FLAGS_BREAK_DET;
-                       trace(icom_port, "BREAK_DET", 0);
-               }
-
-               flag = TTY_NORMAL;
-
-               if (status &
-                   (SA_FLAGS_BREAK_DET | SA_FLAGS_PARITY_ERROR |
-                    SA_FLAGS_FRAME_ERROR | SA_FLAGS_OVERRUN)) {
-
-                       if (status & SA_FLAGS_BREAK_DET)
-                               icount->brk++;
-                       if (status & SA_FLAGS_PARITY_ERROR)
-                               icount->parity++;
-                       if (status & SA_FLAGS_FRAME_ERROR)
-                               icount->frame++;
-                       if (status & SA_FLAGS_OVERRUN)
-                               icount->overrun++;
-
-                       /*
-                        * Now check to see if character should be
-                        * ignored, and mask off conditions which
-                        * should be ignored.
-                        */
-                       if (status & icom_port->ignore_status_mask) {
-                               trace(icom_port, "IGNORE_CHAR", 0);
-                               goto ignore_char;
-                       }
-
-                       status &= icom_port->read_status_mask;
-
-                       if (status & SA_FLAGS_BREAK_DET) {
-                               flag = TTY_BREAK;
-                       } else if (status & SA_FLAGS_PARITY_ERROR) {
-                               trace(icom_port, "PARITY_ERROR", 0);
-                               flag = TTY_PARITY;
-                       } else if (status & SA_FLAGS_FRAME_ERROR)
-                               flag = TTY_FRAME;
-
-               }
-
-               tty_insert_flip_char(tty, *(icom_port->recv_buf + offset + count - 1), flag);
-
-               if (status & SA_FLAGS_OVERRUN)
-                       /*
-                        * Overrun is special, since it's
-                        * reported immediately, and doesn't
-                        * affect the current character
-                        */
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-ignore_char:
-               icom_port->statStg->rcv[rcv_buff].flags = 0;
-               icom_port->statStg->rcv[rcv_buff].leLength = 0;
-               icom_port->statStg->rcv[rcv_buff].WorkingLength =
-                       (unsigned short int) cpu_to_le16(RCV_BUFF_SZ);
-
-               rcv_buff++;
-               if (rcv_buff == NUM_RBUFFS)
-                       rcv_buff = 0;
-
-               status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags);
-       }
-       icom_port->next_rcv = rcv_buff;
-       tty_flip_buffer_push(tty);
-}
-
-static void process_interrupt(u16 port_int_reg,
-                             struct icom_port *icom_port)
-{
-
-       spin_lock(&icom_port->uart_port.lock);
-       trace(icom_port, "INTERRUPT", port_int_reg);
-
-       if (port_int_reg & (INT_XMIT_COMPLETED | INT_XMIT_DISABLED))
-               xmit_interrupt(port_int_reg, icom_port);
-
-       if (port_int_reg & INT_RCV_COMPLETED)
-               recv_interrupt(port_int_reg, icom_port);
-
-       spin_unlock(&icom_port->uart_port.lock);
-}
-
-static irqreturn_t icom_interrupt(int irq, void *dev_id)
-{
-       void __iomem * int_reg;
-       u32 adapter_interrupts;
-       u16 port_int_reg;
-       struct icom_adapter *icom_adapter;
-       struct icom_port *icom_port;
-
-       /* find icom_port for this interrupt */
-       icom_adapter = (struct icom_adapter *) dev_id;
-
-       if (icom_adapter->version == ADAPTER_V2) {
-               int_reg = icom_adapter->base_addr + 0x8024;
-
-               adapter_interrupts = readl(int_reg);
-
-               if (adapter_interrupts & 0x00003FFF) {
-                       /* port 2 interrupt,  NOTE:  for all ADAPTER_V2, port 2 will be active */
-                       icom_port = &icom_adapter->port_info[2];
-                       port_int_reg = (u16) adapter_interrupts;
-                       process_interrupt(port_int_reg, icom_port);
-                       check_modem_status(icom_port);
-               }
-               if (adapter_interrupts & 0x3FFF0000) {
-                       /* port 3 interrupt */
-                       icom_port = &icom_adapter->port_info[3];
-                       if (icom_port->status == ICOM_PORT_ACTIVE) {
-                               port_int_reg =
-                                   (u16) (adapter_interrupts >> 16);
-                               process_interrupt(port_int_reg, icom_port);
-                               check_modem_status(icom_port);
-                       }
-               }
-
-               /* Clear out any pending interrupts */
-               writel(adapter_interrupts, int_reg);
-
-               int_reg = icom_adapter->base_addr + 0x8004;
-       } else {
-               int_reg = icom_adapter->base_addr + 0x4004;
-       }
-
-       adapter_interrupts = readl(int_reg);
-
-       if (adapter_interrupts & 0x00003FFF) {
-               /* port 0 interrupt, NOTE:  for all adapters, port 0 will be active */
-               icom_port = &icom_adapter->port_info[0];
-               port_int_reg = (u16) adapter_interrupts;
-               process_interrupt(port_int_reg, icom_port);
-               check_modem_status(icom_port);
-       }
-       if (adapter_interrupts & 0x3FFF0000) {
-               /* port 1 interrupt */
-               icom_port = &icom_adapter->port_info[1];
-               if (icom_port->status == ICOM_PORT_ACTIVE) {
-                       port_int_reg = (u16) (adapter_interrupts >> 16);
-                       process_interrupt(port_int_reg, icom_port);
-                       check_modem_status(icom_port);
-               }
-       }
-
-       /* Clear out any pending interrupts */
-       writel(adapter_interrupts, int_reg);
-
-       /* flush the write */
-       adapter_interrupts = readl(int_reg);
-
-       return IRQ_HANDLED;
-}
-
-/*
- * ------------------------------------------------------------------
- * Begin serial-core API
- * ------------------------------------------------------------------
- */
-static unsigned int icom_tx_empty(struct uart_port *port)
-{
-       int ret;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) &
-           SA_FLAGS_READY_TO_XMIT)
-               ret = TIOCSER_TEMT;
-       else
-               ret = 0;
-
-       spin_unlock_irqrestore(&port->lock, flags);
-       return ret;
-}
-
-static void icom_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       unsigned char local_osr;
-
-       trace(ICOM_PORT, "SET_MODEM", 0);
-       local_osr = readb(&ICOM_PORT->dram->osr);
-
-       if (mctrl & TIOCM_RTS) {
-               trace(ICOM_PORT, "RAISE_RTS", 0);
-               local_osr |= ICOM_RTS;
-       } else {
-               trace(ICOM_PORT, "LOWER_RTS", 0);
-               local_osr &= ~ICOM_RTS;
-       }
-
-       if (mctrl & TIOCM_DTR) {
-               trace(ICOM_PORT, "RAISE_DTR", 0);
-               local_osr |= ICOM_DTR;
-       } else {
-               trace(ICOM_PORT, "LOWER_DTR", 0);
-               local_osr &= ~ICOM_DTR;
-       }
-
-       writeb(local_osr, &ICOM_PORT->dram->osr);
-}
-
-static unsigned int icom_get_mctrl(struct uart_port *port)
-{
-       unsigned char status;
-       unsigned int result;
-
-       trace(ICOM_PORT, "GET_MODEM", 0);
-
-       status = readb(&ICOM_PORT->dram->isr);
-
-       result = ((status & ICOM_DCD) ? TIOCM_CAR : 0)
-           | ((status & ICOM_RI) ? TIOCM_RNG : 0)
-           | ((status & ICOM_DSR) ? TIOCM_DSR : 0)
-           | ((status & ICOM_CTS) ? TIOCM_CTS : 0);
-       return result;
-}
-
-static void icom_stop_tx(struct uart_port *port)
-{
-       unsigned char cmdReg;
-
-       trace(ICOM_PORT, "STOP", 0);
-       cmdReg = readb(&ICOM_PORT->dram->CmdReg);
-       writeb(cmdReg | CMD_HOLD_XMIT, &ICOM_PORT->dram->CmdReg);
-}
-
-static void icom_start_tx(struct uart_port *port)
-{
-       unsigned char cmdReg;
-
-       trace(ICOM_PORT, "START", 0);
-       cmdReg = readb(&ICOM_PORT->dram->CmdReg);
-       if ((cmdReg & CMD_HOLD_XMIT) == CMD_HOLD_XMIT)
-               writeb(cmdReg & ~CMD_HOLD_XMIT,
-                      &ICOM_PORT->dram->CmdReg);
-
-       icom_write(port);
-}
-
-static void icom_send_xchar(struct uart_port *port, char ch)
-{
-       unsigned char xdata;
-       int index;
-       unsigned long flags;
-
-       trace(ICOM_PORT, "SEND_XCHAR", ch);
-
-       /* wait .1 sec to send char */
-       for (index = 0; index < 10; index++) {
-               spin_lock_irqsave(&port->lock, flags);
-               xdata = readb(&ICOM_PORT->dram->xchar);
-               if (xdata == 0x00) {
-                       trace(ICOM_PORT, "QUICK_WRITE", 0);
-                       writeb(ch, &ICOM_PORT->dram->xchar);
-
-                       /* flush write operation */
-                       xdata = readb(&ICOM_PORT->dram->xchar);
-                       spin_unlock_irqrestore(&port->lock, flags);
-                       break;
-               }
-               spin_unlock_irqrestore(&port->lock, flags);
-               msleep(10);
-       }
-}
-
-static void icom_stop_rx(struct uart_port *port)
-{
-       unsigned char cmdReg;
-
-       cmdReg = readb(&ICOM_PORT->dram->CmdReg);
-       writeb(cmdReg & ~CMD_RCV_ENABLE, &ICOM_PORT->dram->CmdReg);
-}
-
-static void icom_enable_ms(struct uart_port *port)
-{
-       /* no-op */
-}
-
-static void icom_break(struct uart_port *port, int break_state)
-{
-       unsigned char cmdReg;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       trace(ICOM_PORT, "BREAK", 0);
-       cmdReg = readb(&ICOM_PORT->dram->CmdReg);
-       if (break_state == -1) {
-               writeb(cmdReg | CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg);
-       } else {
-               writeb(cmdReg & ~CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg);
-       }
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static int icom_open(struct uart_port *port)
-{
-       int retval;
-
-       kref_get(&ICOM_PORT->adapter->kref);
-       retval = startup(ICOM_PORT);
-
-       if (retval) {
-               kref_put(&ICOM_PORT->adapter->kref, icom_kref_release);
-               trace(ICOM_PORT, "STARTUP_ERROR", 0);
-               return retval;
-       }
-
-       return 0;
-}
-
-static void icom_close(struct uart_port *port)
-{
-       unsigned char cmdReg;
-
-       trace(ICOM_PORT, "CLOSE", 0);
-
-       /* stop receiver */
-       cmdReg = readb(&ICOM_PORT->dram->CmdReg);
-       writeb(cmdReg & (unsigned char) ~CMD_RCV_ENABLE,
-              &ICOM_PORT->dram->CmdReg);
-
-       shutdown(ICOM_PORT);
-
-       kref_put(&ICOM_PORT->adapter->kref, icom_kref_release);
-}
-
-static void icom_set_termios(struct uart_port *port,
-                            struct ktermios *termios,
-                            struct ktermios *old_termios)
-{
-       int baud;
-       unsigned cflag, iflag;
-       char new_config2;
-       char new_config3 = 0;
-       char tmp_byte;
-       int index;
-       int rcv_buff, xmit_buff;
-       unsigned long offset;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       trace(ICOM_PORT, "CHANGE_SPEED", 0);
-
-       cflag = termios->c_cflag;
-       iflag = termios->c_iflag;
-
-       new_config2 = ICOM_ACFG_DRIVE1;
-
-       /* byte size and parity */
-       switch (cflag & CSIZE) {
-       case CS5:               /* 5 bits/char */
-               new_config2 |= ICOM_ACFG_5BPC;
-               break;
-       case CS6:               /* 6 bits/char */
-               new_config2 |= ICOM_ACFG_6BPC;
-               break;
-       case CS7:               /* 7 bits/char */
-               new_config2 |= ICOM_ACFG_7BPC;
-               break;
-       case CS8:               /* 8 bits/char */
-               new_config2 |= ICOM_ACFG_8BPC;
-               break;
-       default:
-               break;
-       }
-       if (cflag & CSTOPB) {
-               /* 2 stop bits */
-               new_config2 |= ICOM_ACFG_2STOP_BIT;
-       }
-       if (cflag & PARENB) {
-               /* parity bit enabled */
-               new_config2 |= ICOM_ACFG_PARITY_ENAB;
-               trace(ICOM_PORT, "PARENB", 0);
-       }
-       if (cflag & PARODD) {
-               /* odd parity */
-               new_config2 |= ICOM_ACFG_PARITY_ODD;
-               trace(ICOM_PORT, "PARODD", 0);
-       }
-
-       /* Determine divisor based on baud rate */
-       baud = uart_get_baud_rate(port, termios, old_termios,
-                                 icom_acfg_baud[0],
-                                 icom_acfg_baud[BAUD_TABLE_LIMIT]);
-       if (!baud)
-               baud = 9600;    /* B0 transition handled in rs_set_termios */
-
-       for (index = 0; index < BAUD_TABLE_LIMIT; index++) {
-               if (icom_acfg_baud[index] == baud) {
-                       new_config3 = index;
-                       break;
-               }
-       }
-
-       uart_update_timeout(port, cflag, baud);
-
-       /* CTS flow control flag and modem status interrupts */
-       tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg));
-       if (cflag & CRTSCTS)
-               tmp_byte |= HDLC_HDW_FLOW;
-       else
-               tmp_byte &= ~HDLC_HDW_FLOW;
-       writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg));
-
-       /*
-        * Set up parity check flag
-        */
-       ICOM_PORT->read_status_mask = SA_FLAGS_OVERRUN | SA_FL_RCV_DONE;
-       if (iflag & INPCK)
-               ICOM_PORT->read_status_mask |=
-                   SA_FLAGS_FRAME_ERROR | SA_FLAGS_PARITY_ERROR;
-
-       if ((iflag & BRKINT) || (iflag & PARMRK))
-               ICOM_PORT->read_status_mask |= SA_FLAGS_BREAK_DET;
-
-       /*
-        * Characters to ignore
-        */
-       ICOM_PORT->ignore_status_mask = 0;
-       if (iflag & IGNPAR)
-               ICOM_PORT->ignore_status_mask |=
-                   SA_FLAGS_PARITY_ERROR | SA_FLAGS_FRAME_ERROR;
-       if (iflag & IGNBRK) {
-               ICOM_PORT->ignore_status_mask |= SA_FLAGS_BREAK_DET;
-               /*
-                * If we're ignore parity and break indicators, ignore
-                * overruns too.  (For real raw support).
-                */
-               if (iflag & IGNPAR)
-                       ICOM_PORT->ignore_status_mask |= SA_FLAGS_OVERRUN;
-       }
-
-       /*
-        * !!! ignore all characters if CREAD is not set
-        */
-       if ((cflag & CREAD) == 0)
-               ICOM_PORT->ignore_status_mask |= SA_FL_RCV_DONE;
-
-       /* Turn off Receiver to prepare for reset */
-       writeb(CMD_RCV_DISABLE, &ICOM_PORT->dram->CmdReg);
-
-       for (index = 0; index < 10; index++) {
-               if (readb(&ICOM_PORT->dram->PrevCmdReg) == 0x00) {
-                       break;
-               }
-       }
-
-       /* clear all current buffers of data */
-       for (rcv_buff = 0; rcv_buff < NUM_RBUFFS; rcv_buff++) {
-               ICOM_PORT->statStg->rcv[rcv_buff].flags = 0;
-               ICOM_PORT->statStg->rcv[rcv_buff].leLength = 0;
-               ICOM_PORT->statStg->rcv[rcv_buff].WorkingLength =
-                   (unsigned short int) cpu_to_le16(RCV_BUFF_SZ);
-       }
-
-       for (xmit_buff = 0; xmit_buff < NUM_XBUFFS; xmit_buff++) {
-               ICOM_PORT->statStg->xmit[xmit_buff].flags = 0;
-       }
-
-       /* activate changes and start xmit and receiver here */
-       /* Enable the receiver */
-       writeb(new_config3, &(ICOM_PORT->dram->async_config3));
-       writeb(new_config2, &(ICOM_PORT->dram->async_config2));
-       tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg));
-       tmp_byte |= HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL;
-       writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg));
-       writeb(0x04, &(ICOM_PORT->dram->FlagFillIdleTimer));    /* 0.5 seconds */
-       writeb(0xFF, &(ICOM_PORT->dram->ier));  /* enable modem signal interrupts */
-
-       /* reset processor */
-       writeb(CMD_RESTART, &ICOM_PORT->dram->CmdReg);
-
-       for (index = 0; index < 10; index++) {
-               if (readb(&ICOM_PORT->dram->CmdReg) == 0x00) {
-                       break;
-               }
-       }
-
-       /* Enable Transmitter and Reciever */
-       offset =
-           (unsigned long) &ICOM_PORT->statStg->rcv[0] -
-           (unsigned long) ICOM_PORT->statStg;
-       writel(ICOM_PORT->statStg_pci + offset,
-              &ICOM_PORT->dram->RcvStatusAddr);
-       ICOM_PORT->next_rcv = 0;
-       ICOM_PORT->put_length = 0;
-       *ICOM_PORT->xmitRestart = 0;
-       writel(ICOM_PORT->xmitRestart_pci,
-              &ICOM_PORT->dram->XmitStatusAddr);
-       trace(ICOM_PORT, "XR_ENAB", 0);
-       writeb(CMD_XMIT_RCV_ENABLE, &ICOM_PORT->dram->CmdReg);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *icom_type(struct uart_port *port)
-{
-       return "icom";
-}
-
-static void icom_release_port(struct uart_port *port)
-{
-}
-
-static int icom_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-static void icom_config_port(struct uart_port *port, int flags)
-{
-       port->type = PORT_ICOM;
-}
-
-static struct uart_ops icom_ops = {
-       .tx_empty = icom_tx_empty,
-       .set_mctrl = icom_set_mctrl,
-       .get_mctrl = icom_get_mctrl,
-       .stop_tx = icom_stop_tx,
-       .start_tx = icom_start_tx,
-       .send_xchar = icom_send_xchar,
-       .stop_rx = icom_stop_rx,
-       .enable_ms = icom_enable_ms,
-       .break_ctl = icom_break,
-       .startup = icom_open,
-       .shutdown = icom_close,
-       .set_termios = icom_set_termios,
-       .type = icom_type,
-       .release_port = icom_release_port,
-       .request_port = icom_request_port,
-       .config_port = icom_config_port,
-};
-
-#define ICOM_CONSOLE NULL
-
-static struct uart_driver icom_uart_driver = {
-       .owner = THIS_MODULE,
-       .driver_name = ICOM_DRIVER_NAME,
-       .dev_name = "ttyA",
-       .major = ICOM_MAJOR,
-       .minor = ICOM_MINOR_START,
-       .nr = NR_PORTS,
-       .cons = ICOM_CONSOLE,
-};
-
-static int __devinit icom_init_ports(struct icom_adapter *icom_adapter)
-{
-       u32 subsystem_id = icom_adapter->subsystem_id;
-       int i;
-       struct icom_port *icom_port;
-
-       if (icom_adapter->version == ADAPTER_V1) {
-               icom_adapter->numb_ports = 2;
-
-               for (i = 0; i < 2; i++) {
-                       icom_port = &icom_adapter->port_info[i];
-                       icom_port->port = i;
-                       icom_port->status = ICOM_PORT_ACTIVE;
-                       icom_port->imbed_modem = ICOM_UNKNOWN;
-               }
-       } else {
-               if (subsystem_id == PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL) {
-                       icom_adapter->numb_ports = 4;
-
-                       for (i = 0; i < 4; i++) {
-                               icom_port = &icom_adapter->port_info[i];
-
-                               icom_port->port = i;
-                               icom_port->status = ICOM_PORT_ACTIVE;
-                               icom_port->imbed_modem = ICOM_IMBED_MODEM;
-                       }
-               } else {
-                       icom_adapter->numb_ports = 4;
-
-                       icom_adapter->port_info[0].port = 0;
-                       icom_adapter->port_info[0].status = ICOM_PORT_ACTIVE;
-
-                       if (subsystem_id ==
-                           PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM) {
-                               icom_adapter->port_info[0].imbed_modem = ICOM_IMBED_MODEM;
-                       } else {
-                               icom_adapter->port_info[0].imbed_modem = ICOM_RVX;
-                       }
-
-                       icom_adapter->port_info[1].status = ICOM_PORT_OFF;
-
-                       icom_adapter->port_info[2].port = 2;
-                       icom_adapter->port_info[2].status = ICOM_PORT_ACTIVE;
-                       icom_adapter->port_info[2].imbed_modem = ICOM_RVX;
-                       icom_adapter->port_info[3].status = ICOM_PORT_OFF;
-               }
-       }
-
-       return 0;
-}
-
-static void icom_port_active(struct icom_port *icom_port, struct icom_adapter *icom_adapter, int port_num)
-{
-       if (icom_adapter->version == ADAPTER_V1) {
-               icom_port->global_reg = icom_adapter->base_addr + 0x4000;
-               icom_port->int_reg = icom_adapter->base_addr +
-                   0x4004 + 2 - 2 * port_num;
-       } else {
-               icom_port->global_reg = icom_adapter->base_addr + 0x8000;
-               if (icom_port->port < 2)
-                       icom_port->int_reg = icom_adapter->base_addr +
-                           0x8004 + 2 - 2 * icom_port->port;
-               else
-                       icom_port->int_reg = icom_adapter->base_addr +
-                           0x8024 + 2 - 2 * (icom_port->port - 2);
-       }
-}
-static int __devinit icom_load_ports(struct icom_adapter *icom_adapter)
-{
-       struct icom_port *icom_port;
-       int port_num;
-
-       for (port_num = 0; port_num < icom_adapter->numb_ports; port_num++) {
-
-               icom_port = &icom_adapter->port_info[port_num];
-
-               if (icom_port->status == ICOM_PORT_ACTIVE) {
-                       icom_port_active(icom_port, icom_adapter, port_num);
-                       icom_port->dram = icom_adapter->base_addr +
-                                       0x2000 * icom_port->port;
-
-                       icom_port->adapter = icom_adapter;
-
-                       /* get port memory */
-                       if (get_port_memory(icom_port) != 0) {
-                               dev_err(&icom_port->adapter->pci_dev->dev,
-                                       "Memory allocation for port FAILED\n");
-                       }
-               }
-       }
-       return 0;
-}
-
-static int __devinit icom_alloc_adapter(struct icom_adapter
-                                       **icom_adapter_ref)
-{
-       int adapter_count = 0;
-       struct icom_adapter *icom_adapter;
-       struct icom_adapter *cur_adapter_entry;
-       struct list_head *tmp;
-
-       icom_adapter = (struct icom_adapter *)
-           kzalloc(sizeof(struct icom_adapter), GFP_KERNEL);
-
-       if (!icom_adapter) {
-               return -ENOMEM;
-       }
-
-       list_for_each(tmp, &icom_adapter_head) {
-               cur_adapter_entry =
-                   list_entry(tmp, struct icom_adapter,
-                              icom_adapter_entry);
-               if (cur_adapter_entry->index != adapter_count) {
-                       break;
-               }
-               adapter_count++;
-       }
-
-       icom_adapter->index = adapter_count;
-       list_add_tail(&icom_adapter->icom_adapter_entry, tmp);
-
-       *icom_adapter_ref = icom_adapter;
-       return 0;
-}
-
-static void icom_free_adapter(struct icom_adapter *icom_adapter)
-{
-       list_del(&icom_adapter->icom_adapter_entry);
-       kfree(icom_adapter);
-}
-
-static void icom_remove_adapter(struct icom_adapter *icom_adapter)
-{
-       struct icom_port *icom_port;
-       int index;
-
-       for (index = 0; index < icom_adapter->numb_ports; index++) {
-               icom_port = &icom_adapter->port_info[index];
-
-               if (icom_port->status == ICOM_PORT_ACTIVE) {
-                       dev_info(&icom_adapter->pci_dev->dev,
-                                "Device removed\n");
-
-                       uart_remove_one_port(&icom_uart_driver,
-                                            &icom_port->uart_port);
-
-                       /* be sure that DTR and RTS are dropped */
-                       writeb(0x00, &icom_port->dram->osr);
-
-                       /* Wait 0.1 Sec for simple Init to complete */
-                       msleep(100);
-
-                       /* Stop proccessor */
-                       stop_processor(icom_port);
-
-                       free_port_memory(icom_port);
-               }
-       }
-
-       free_irq(icom_adapter->pci_dev->irq, (void *) icom_adapter);
-       iounmap(icom_adapter->base_addr);
-       pci_release_regions(icom_adapter->pci_dev);
-       icom_free_adapter(icom_adapter);
-}
-
-static void icom_kref_release(struct kref *kref)
-{
-       struct icom_adapter *icom_adapter;
-
-       icom_adapter = to_icom_adapter(kref);
-       icom_remove_adapter(icom_adapter);
-}
-
-static int __devinit icom_probe(struct pci_dev *dev,
-                               const struct pci_device_id *ent)
-{
-       int index;
-       unsigned int command_reg;
-       int retval;
-       struct icom_adapter *icom_adapter;
-       struct icom_port *icom_port;
-
-       retval = pci_enable_device(dev);
-       if (retval) {
-               dev_err(&dev->dev, "Device enable FAILED\n");
-               return retval;
-       }
-
-       if ( (retval = pci_request_regions(dev, "icom"))) {
-                dev_err(&dev->dev, "pci_request_regions FAILED\n");
-                pci_disable_device(dev);
-                return retval;
-        }
-
-       pci_set_master(dev);
-
-       if ( (retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg))) {
-               dev_err(&dev->dev, "PCI Config read FAILED\n");
-               return retval;
-       }
-
-       pci_write_config_dword(dev, PCI_COMMAND,
-               command_reg | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER
-               | PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
-
-       if (ent->driver_data == ADAPTER_V1) {
-               pci_write_config_dword(dev, 0x44, 0x8300830A);
-       } else {
-               pci_write_config_dword(dev, 0x44, 0x42004200);
-               pci_write_config_dword(dev, 0x48, 0x42004200);
-       }
-
-
-       retval = icom_alloc_adapter(&icom_adapter);
-       if (retval) {
-                dev_err(&dev->dev, "icom_alloc_adapter FAILED\n");
-                retval = -EIO;
-                goto probe_exit0;
-       }
-
-       icom_adapter->base_addr_pci = pci_resource_start(dev, 0);
-       icom_adapter->pci_dev = dev;
-       icom_adapter->version = ent->driver_data;
-       icom_adapter->subsystem_id = ent->subdevice;
-
-
-       retval = icom_init_ports(icom_adapter);
-       if (retval) {
-               dev_err(&dev->dev, "Port configuration failed\n");
-               goto probe_exit1;
-       }
-
-       icom_adapter->base_addr = pci_ioremap_bar(dev, 0);
-
-       if (!icom_adapter->base_addr)
-               goto probe_exit1;
-
-        /* save off irq and request irq line */
-        if ( (retval = request_irq(dev->irq, icom_interrupt,
-                                  IRQF_DISABLED | IRQF_SHARED, ICOM_DRIVER_NAME,
-                                  (void *) icom_adapter))) {
-                 goto probe_exit2;
-        }
-
-       retval = icom_load_ports(icom_adapter);
-
-       for (index = 0; index < icom_adapter->numb_ports; index++) {
-               icom_port = &icom_adapter->port_info[index];
-
-               if (icom_port->status == ICOM_PORT_ACTIVE) {
-                       icom_port->uart_port.irq = icom_port->adapter->pci_dev->irq;
-                       icom_port->uart_port.type = PORT_ICOM;
-                       icom_port->uart_port.iotype = UPIO_MEM;
-                       icom_port->uart_port.membase =
-                                              (char *) icom_adapter->base_addr_pci;
-                       icom_port->uart_port.fifosize = 16;
-                       icom_port->uart_port.ops = &icom_ops;
-                       icom_port->uart_port.line =
-                       icom_port->port + icom_adapter->index * 4;
-                       if (uart_add_one_port (&icom_uart_driver, &icom_port->uart_port)) {
-                               icom_port->status = ICOM_PORT_OFF;
-                               dev_err(&dev->dev, "Device add failed\n");
-                        } else
-                               dev_info(&dev->dev, "Device added\n");
-               }
-       }
-
-       kref_init(&icom_adapter->kref);
-       return 0;
-
-probe_exit2:
-       iounmap(icom_adapter->base_addr);
-probe_exit1:
-       icom_free_adapter(icom_adapter);
-
-probe_exit0:
-       pci_release_regions(dev);
-       pci_disable_device(dev);
-
-       return retval;
-}
-
-static void __devexit icom_remove(struct pci_dev *dev)
-{
-       struct icom_adapter *icom_adapter;
-       struct list_head *tmp;
-
-       list_for_each(tmp, &icom_adapter_head) {
-               icom_adapter = list_entry(tmp, struct icom_adapter,
-                                         icom_adapter_entry);
-               if (icom_adapter->pci_dev == dev) {
-                       kref_put(&icom_adapter->kref, icom_kref_release);
-                       return;
-               }
-       }
-
-       dev_err(&dev->dev, "Unable to find device to remove\n");
-}
-
-static struct pci_driver icom_pci_driver = {
-       .name = ICOM_DRIVER_NAME,
-       .id_table = icom_pci_table,
-       .probe = icom_probe,
-       .remove = __devexit_p(icom_remove),
-};
-
-static int __init icom_init(void)
-{
-       int ret;
-
-       spin_lock_init(&icom_lock);
-
-       ret = uart_register_driver(&icom_uart_driver);
-       if (ret)
-               return ret;
-
-       ret = pci_register_driver(&icom_pci_driver);
-
-       if (ret < 0)
-               uart_unregister_driver(&icom_uart_driver);
-
-       return ret;
-}
-
-static void __exit icom_exit(void)
-{
-       pci_unregister_driver(&icom_pci_driver);
-       uart_unregister_driver(&icom_uart_driver);
-}
-
-module_init(icom_init);
-module_exit(icom_exit);
-
-MODULE_AUTHOR("Michael Anderson <mjanders@us.ibm.com>");
-MODULE_DESCRIPTION("IBM iSeries Serial IOA driver");
-MODULE_SUPPORTED_DEVICE
-    ("IBM iSeries 2745, 2771, 2772, 2742, 2793 and 2805 Communications adapters");
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE("icom_call_setup.bin");
-MODULE_FIRMWARE("icom_res_dce.bin");
-MODULE_FIRMWARE("icom_asc.bin");
diff --git a/drivers/serial/icom.h b/drivers/serial/icom.h
deleted file mode 100644 (file)
index c8029e0..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * icom.h
- *
- * Copyright (C) 2001 Michael Anderson, IBM Corporation
- *
- * Serial device driver include file.
- *
- * 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/serial_core.h>
-
-#define BAUD_TABLE_LIMIT       ((sizeof(icom_acfg_baud)/sizeof(int)) - 1)
-static int icom_acfg_baud[] = {
-       300,
-       600,
-       900,
-       1200,
-       1800,
-       2400,
-       3600,
-       4800,
-       7200,
-       9600,
-       14400,
-       19200,
-       28800,
-       38400,
-       57600,
-       76800,
-       115200,
-       153600,
-       230400,
-       307200,
-       460800,
-};
-
-struct icom_regs {
-       u32 control;            /* Adapter Control Register     */
-       u32 interrupt;          /* Adapter Interrupt Register   */
-       u32 int_mask;           /* Adapter Interrupt Mask Reg   */
-       u32 int_pri;            /* Adapter Interrupt Priority r */
-       u32 int_reg_b;          /* Adapter non-masked Interrupt */
-       u32 resvd01;
-       u32 resvd02;
-       u32 resvd03;
-       u32 control_2;          /* Adapter Control Register 2   */
-       u32 interrupt_2;        /* Adapter Interrupt Register 2 */
-       u32 int_mask_2;         /* Adapter Interrupt Mask 2     */
-       u32 int_pri_2;          /* Adapter Interrupt Prior 2    */
-       u32 int_reg_2b;         /* Adapter non-masked 2         */
-};
-
-struct func_dram {
-       u32 reserved[108];      /* 0-1B0   reserved by personality code */
-       u32 RcvStatusAddr;      /* 1B0-1B3 Status Address for Next rcv */
-       u8 RcvStnAddr;          /* 1B4     Receive Station Addr */
-       u8 IdleState;           /* 1B5     Idle State */
-       u8 IdleMonitor;         /* 1B6     Idle Monitor */
-       u8 FlagFillIdleTimer;   /* 1B7     Flag Fill Idle Timer */
-       u32 XmitStatusAddr;     /* 1B8-1BB Transmit Status Address */
-       u8 StartXmitCmd;        /* 1BC     Start Xmit Command */
-       u8 HDLCConfigReg;       /* 1BD     Reserved */
-       u8 CauseCode;           /* 1BE     Cause code for fatal error */
-       u8 xchar;               /* 1BF     High priority send */
-       u32 reserved3;          /* 1C0-1C3 Reserved */
-       u8 PrevCmdReg;          /* 1C4     Reserved */
-       u8 CmdReg;              /* 1C5     Command Register */
-       u8 async_config2;       /* 1C6     Async Config Byte 2 */
-       u8 async_config3;       /* 1C7     Async Config Byte 3 */
-       u8 dce_resvd[20];       /* 1C8-1DB DCE Rsvd           */
-       u8 dce_resvd21;         /* 1DC     DCE Rsvd (21st byte */
-       u8 misc_flags;          /* 1DD     misc flags         */
-#define V2_HARDWARE     0x40
-#define ICOM_HDW_ACTIVE 0x01
-       u8 call_length;         /* 1DE     Phone #/CFI buff ln */
-       u8 call_length2;        /* 1DF     Upper byte (unused) */
-       u32 call_addr;          /* 1E0-1E3 Phn #/CFI buff addr */
-       u16 timer_value;        /* 1E4-1E5 general timer value */
-       u8 timer_command;       /* 1E6     general timer cmd  */
-       u8 dce_command;         /* 1E7     dce command reg    */
-       u8 dce_cmd_status;      /* 1E8     dce command stat   */
-       u8 x21_r1_ioff;         /* 1E9     dce ready counter  */
-       u8 x21_r0_ioff;         /* 1EA     dce not ready ctr  */
-       u8 x21_ralt_ioff;       /* 1EB     dce CNR counter    */
-       u8 x21_r1_ion;          /* 1EC     dce ready I on ctr */
-       u8 rsvd_ier;            /* 1ED     Rsvd for IER (if ne */
-       u8 ier;                 /* 1EE     Interrupt Enable   */
-       u8 isr;                 /* 1EF     Input Signal Reg   */
-       u8 osr;                 /* 1F0     Output Signal Reg  */
-       u8 reset;               /* 1F1     Reset/Reload Reg   */
-       u8 disable;             /* 1F2     Disable Reg        */
-       u8 sync;                /* 1F3     Sync Reg           */
-       u8 error_stat;          /* 1F4     Error Status       */
-       u8 cable_id;            /* 1F5     Cable ID           */
-       u8 cs_length;           /* 1F6     CS Load Length     */
-       u8 mac_length;          /* 1F7     Mac Load Length    */
-       u32 cs_load_addr;       /* 1F8-1FB Call Load PCI Addr */
-       u32 mac_load_addr;      /* 1FC-1FF Mac Load PCI Addr  */
-};
-
-/*
- * adapter defines and structures
- */
-#define ICOM_CONTROL_START_A         0x00000008
-#define ICOM_CONTROL_STOP_A          0x00000004
-#define ICOM_CONTROL_START_B         0x00000002
-#define ICOM_CONTROL_STOP_B          0x00000001
-#define ICOM_CONTROL_START_C         0x00000008
-#define ICOM_CONTROL_STOP_C          0x00000004
-#define ICOM_CONTROL_START_D         0x00000002
-#define ICOM_CONTROL_STOP_D          0x00000001
-#define ICOM_IRAM_OFFSET             0x1000
-#define ICOM_IRAM_SIZE               0x0C00
-#define ICOM_DCE_IRAM_OFFSET         0x0A00
-#define ICOM_CABLE_ID_VALID          0x01
-#define ICOM_CABLE_ID_MASK           0xF0
-#define ICOM_DISABLE                 0x80
-#define CMD_XMIT_RCV_ENABLE          0xC0
-#define CMD_XMIT_ENABLE              0x40
-#define CMD_RCV_DISABLE              0x00
-#define CMD_RCV_ENABLE               0x80
-#define CMD_RESTART                  0x01
-#define CMD_HOLD_XMIT                0x02
-#define CMD_SND_BREAK                0x04
-#define RS232_CABLE                  0x06
-#define V24_CABLE                    0x0E
-#define V35_CABLE                    0x0C
-#define V36_CABLE                    0x02
-#define NO_CABLE                     0x00
-#define START_DOWNLOAD               0x80
-#define ICOM_INT_MASK_PRC_A          0x00003FFF
-#define ICOM_INT_MASK_PRC_B          0x3FFF0000
-#define ICOM_INT_MASK_PRC_C          0x00003FFF
-#define ICOM_INT_MASK_PRC_D          0x3FFF0000
-#define INT_RCV_COMPLETED            0x1000
-#define INT_XMIT_COMPLETED           0x2000
-#define INT_IDLE_DETECT              0x0800
-#define INT_RCV_DISABLED             0x0400
-#define INT_XMIT_DISABLED            0x0200
-#define INT_RCV_XMIT_SHUTDOWN        0x0100
-#define INT_FATAL_ERROR              0x0080
-#define INT_CABLE_PULL               0x0020
-#define INT_SIGNAL_CHANGE            0x0010
-#define HDLC_PPP_PURE_ASYNC          0x02
-#define HDLC_FF_FILL                 0x00
-#define HDLC_HDW_FLOW                0x01
-#define START_XMIT                   0x80
-#define ICOM_ACFG_DRIVE1             0x20
-#define ICOM_ACFG_NO_PARITY          0x00
-#define ICOM_ACFG_PARITY_ENAB        0x02
-#define ICOM_ACFG_PARITY_ODD         0x01
-#define ICOM_ACFG_8BPC               0x00
-#define ICOM_ACFG_7BPC               0x04
-#define ICOM_ACFG_6BPC               0x08
-#define ICOM_ACFG_5BPC               0x0C
-#define ICOM_ACFG_1STOP_BIT          0x00
-#define ICOM_ACFG_2STOP_BIT          0x10
-#define ICOM_DTR                     0x80
-#define ICOM_RTS                     0x40
-#define ICOM_RI                      0x08
-#define ICOM_DSR                     0x80
-#define ICOM_DCD                     0x20
-#define ICOM_CTS                     0x40
-
-#define NUM_XBUFFS 1
-#define NUM_RBUFFS 2
-#define RCV_BUFF_SZ 0x0200
-#define XMIT_BUFF_SZ 0x1000
-struct statusArea {
-    /**********************************************/
-       /* Transmit Status Area                       */
-    /**********************************************/
-       struct xmit_status_area{
-               u32 leNext;     /* Next entry in Little Endian on Adapter */
-               u32 leNextASD;
-               u32 leBuffer;   /* Buffer for entry in LE for Adapter */
-               u16 leLengthASD;
-               u16 leOffsetASD;
-               u16 leLength;   /* Length of data in segment */
-               u16 flags;
-#define SA_FLAGS_DONE           0x0080 /* Done with Segment */
-#define SA_FLAGS_CONTINUED      0x8000 /* More Segments */
-#define SA_FLAGS_IDLE           0x4000 /* Mark IDLE after frm */
-#define SA_FLAGS_READY_TO_XMIT  0x0800
-#define SA_FLAGS_STAT_MASK      0x007F
-       } xmit[NUM_XBUFFS];
-
-    /**********************************************/
-       /* Receive Status Area                        */
-    /**********************************************/
-       struct {
-               u32 leNext;     /* Next entry in Little Endian on Adapter */
-               u32 leNextASD;
-               u32 leBuffer;   /* Buffer for entry in LE for Adapter */
-               u16 WorkingLength;      /* size of segment */
-               u16 reserv01;
-               u16 leLength;   /* Length of data in segment */
-               u16 flags;
-#define SA_FL_RCV_DONE           0x0010        /* Data ready */
-#define SA_FLAGS_OVERRUN         0x0040
-#define SA_FLAGS_PARITY_ERROR    0x0080
-#define SA_FLAGS_FRAME_ERROR     0x0001
-#define SA_FLAGS_FRAME_TRUNC     0x0002
-#define SA_FLAGS_BREAK_DET       0x0004        /* set conditionally by device driver, not hardware */
-#define SA_FLAGS_RCV_MASK        0xFFE6
-       } rcv[NUM_RBUFFS];
-};
-
-struct icom_adapter;
-
-
-#define ICOM_MAJOR       243
-#define ICOM_MINOR_START 0
-
-struct icom_port {
-       struct uart_port uart_port;
-       u8 imbed_modem;
-#define ICOM_UNKNOWN           1
-#define ICOM_RVX               2
-#define ICOM_IMBED_MODEM       3
-       unsigned char cable_id;
-       unsigned char read_status_mask;
-       unsigned char ignore_status_mask;
-       void __iomem * int_reg;
-       struct icom_regs __iomem *global_reg;
-       struct func_dram __iomem *dram;
-       int port;
-       struct statusArea *statStg;
-       dma_addr_t statStg_pci;
-       u32 *xmitRestart;
-       dma_addr_t xmitRestart_pci;
-       unsigned char *xmit_buf;
-       dma_addr_t xmit_buf_pci;
-       unsigned char *recv_buf;
-       dma_addr_t recv_buf_pci;
-       int next_rcv;
-       int put_length;
-       int status;
-#define ICOM_PORT_ACTIVE       1       /* Port exists. */
-#define ICOM_PORT_OFF          0       /* Port does not exist. */
-       int load_in_progress;
-       struct icom_adapter *adapter;
-};
-
-struct icom_adapter {
-       void __iomem * base_addr;
-       unsigned long base_addr_pci;
-       struct pci_dev *pci_dev;
-       struct icom_port port_info[4];
-       int index;
-       int version;
-#define ADAPTER_V1     0x0001
-#define ADAPTER_V2     0x0002
-       u32 subsystem_id;
-#define FOUR_PORT_MODEL                                0x0252
-#define V2_TWO_PORTS_RVX                       0x021A
-#define V2_ONE_PORT_RVX_ONE_PORT_IMBED_MDM     0x0251
-       int numb_ports;
-       struct list_head icom_adapter_entry;
-       struct kref kref;
-};
-
-/* prototype */
-extern void iCom_sercons_init(void);
-
-struct lookup_proc_table {
-       u32     __iomem *global_control_reg;
-       unsigned long   processor_id;
-};
-
-struct lookup_int_table {
-       u32     __iomem *global_int_mask;
-       unsigned long   processor_id;
-};
diff --git a/drivers/serial/ifx6x60.c b/drivers/serial/ifx6x60.c
deleted file mode 100644 (file)
index ab93763..0000000
+++ /dev/null
@@ -1,1406 +0,0 @@
-/****************************************************************************
- *
- * Driver for the IFX 6x60 spi modem.
- *
- * Copyright (C) 2008 Option International
- * Copyright (C) 2008 Filip Aben <f.aben@option.com>
- *                   Denis Joseph Barrow <d.barow@option.com>
- *                   Jan Dumon <j.dumon@option.com>
- *
- * Copyright (C) 2009, 2010 Intel Corp
- * Russ Gorby <richardx.r.gorby@intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
- * USA
- *
- * Driver modified by Intel from Option gtm501l_spi.c
- *
- * Notes
- * o   The driver currently assumes a single device only. If you need to
- *     change this then look for saved_ifx_dev and add a device lookup
- * o   The driver is intended to be big-endian safe but has never been
- *     tested that way (no suitable hardware). There are a couple of FIXME
- *     notes by areas that may need addressing
- * o   Some of the GPIO naming/setup assumptions may need revisiting if
- *     you need to use this driver for another platform.
- *
- *****************************************************************************/
-#include <linux/module.h>
-#include <linux/termios.h>
-#include <linux/tty.h>
-#include <linux/device.h>
-#include <linux/spi/spi.h>
-#include <linux/tty.h>
-#include <linux/kfifo.h>
-#include <linux/tty_flip.h>
-#include <linux/timer.h>
-#include <linux/serial.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/rfkill.h>
-#include <linux/fs.h>
-#include <linux/ip.h>
-#include <linux/dmapool.h>
-#include <linux/gpio.h>
-#include <linux/sched.h>
-#include <linux/time.h>
-#include <linux/wait.h>
-#include <linux/tty.h>
-#include <linux/pm.h>
-#include <linux/pm_runtime.h>
-#include <linux/spi/ifx_modem.h>
-#include <linux/delay.h>
-
-#include "ifx6x60.h"
-
-#define IFX_SPI_MORE_MASK              0x10
-#define IFX_SPI_MORE_BIT               12      /* bit position in u16 */
-#define IFX_SPI_CTS_BIT                        13      /* bit position in u16 */
-#define IFX_SPI_TTY_ID                 0
-#define IFX_SPI_TIMEOUT_SEC            2
-#define IFX_SPI_HEADER_0               (-1)
-#define IFX_SPI_HEADER_F               (-2)
-
-/* forward reference */
-static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev);
-
-/* local variables */
-static int spi_b16 = 1;                        /* 8 or 16 bit word length */
-static struct tty_driver *tty_drv;
-static struct ifx_spi_device *saved_ifx_dev;
-static struct lock_class_key ifx_spi_key;
-
-/* GPIO/GPE settings */
-
-/**
- *     mrdy_set_high           -       set MRDY GPIO
- *     @ifx: device we are controlling
- *
- */
-static inline void mrdy_set_high(struct ifx_spi_device *ifx)
-{
-       gpio_set_value(ifx->gpio.mrdy, 1);
-}
-
-/**
- *     mrdy_set_low            -       clear MRDY GPIO
- *     @ifx: device we are controlling
- *
- */
-static inline void mrdy_set_low(struct ifx_spi_device *ifx)
-{
-       gpio_set_value(ifx->gpio.mrdy, 0);
-}
-
-/**
- *     ifx_spi_power_state_set
- *     @ifx_dev: our SPI device
- *     @val: bits to set
- *
- *     Set bit in power status and signal power system if status becomes non-0
- */
-static void
-ifx_spi_power_state_set(struct ifx_spi_device *ifx_dev, unsigned char val)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&ifx_dev->power_lock, flags);
-
-       /*
-        * if power status is already non-0, just update, else
-        * tell power system
-        */
-       if (!ifx_dev->power_status)
-               pm_runtime_get(&ifx_dev->spi_dev->dev);
-       ifx_dev->power_status |= val;
-
-       spin_unlock_irqrestore(&ifx_dev->power_lock, flags);
-}
-
-/**
- *     ifx_spi_power_state_clear       -       clear power bit
- *     @ifx_dev: our SPI device
- *     @val: bits to clear
- *
- *     clear bit in power status and signal power system if status becomes 0
- */
-static void
-ifx_spi_power_state_clear(struct ifx_spi_device *ifx_dev, unsigned char val)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&ifx_dev->power_lock, flags);
-
-       if (ifx_dev->power_status) {
-               ifx_dev->power_status &= ~val;
-               if (!ifx_dev->power_status)
-                       pm_runtime_put(&ifx_dev->spi_dev->dev);
-       }
-
-       spin_unlock_irqrestore(&ifx_dev->power_lock, flags);
-}
-
-/**
- *     swap_buf
- *     @buf: our buffer
- *     @len : number of bytes (not words) in the buffer
- *     @end: end of buffer
- *
- *     Swap the contents of a buffer into big endian format
- */
-static inline void swap_buf(u16 *buf, int len, void *end)
-{
-       int n;
-
-       len = ((len + 1) >> 1);
-       if ((void *)&buf[len] > end) {
-               pr_err("swap_buf: swap exceeds boundary (%p > %p)!",
-                      &buf[len], end);
-               return;
-       }
-       for (n = 0; n < len; n++) {
-               *buf = cpu_to_be16(*buf);
-               buf++;
-       }
-}
-
-/**
- *     mrdy_assert             -       assert MRDY line
- *     @ifx_dev: our SPI device
- *
- *     Assert mrdy and set timer to wait for SRDY interrupt, if SRDY is low
- *     now.
- *
- *     FIXME: Can SRDY even go high as we are running this code ?
- */
-static void mrdy_assert(struct ifx_spi_device *ifx_dev)
-{
-       int val = gpio_get_value(ifx_dev->gpio.srdy);
-       if (!val) {
-               if (!test_and_set_bit(IFX_SPI_STATE_TIMER_PENDING,
-                                     &ifx_dev->flags)) {
-                       ifx_dev->spi_timer.expires =
-                               jiffies + IFX_SPI_TIMEOUT_SEC*HZ;
-                       add_timer(&ifx_dev->spi_timer);
-
-               }
-       }
-       ifx_spi_power_state_set(ifx_dev, IFX_SPI_POWER_DATA_PENDING);
-       mrdy_set_high(ifx_dev);
-}
-
-/**
- *     ifx_spi_hangup          -       hang up an IFX device
- *     @ifx_dev: our SPI device
- *
- *     Hang up the tty attached to the IFX device if one is currently
- *     open. If not take no action
- */
-static void ifx_spi_ttyhangup(struct ifx_spi_device *ifx_dev)
-{
-       struct tty_port *pport = &ifx_dev->tty_port;
-       struct tty_struct *tty = tty_port_tty_get(pport);
-       if (tty) {
-               tty_hangup(tty);
-               tty_kref_put(tty);
-       }
-}
-
-/**
- *     ifx_spi_timeout         -       SPI timeout
- *     @arg: our SPI device
- *
- *     The SPI has timed out: hang up the tty. Users will then see a hangup
- *     and error events.
- */
-static void ifx_spi_timeout(unsigned long arg)
-{
-       struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *)arg;
-
-       dev_warn(&ifx_dev->spi_dev->dev, "*** SPI Timeout ***");
-       ifx_spi_ttyhangup(ifx_dev);
-       mrdy_set_low(ifx_dev);
-       clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
-}
-
-/* char/tty operations */
-
-/**
- *     ifx_spi_tiocmget        -       get modem lines
- *     @tty: our tty device
- *     @filp: file handle issuing the request
- *
- *     Map the signal state into Linux modem flags and report the value
- *     in Linux terms
- */
-static int ifx_spi_tiocmget(struct tty_struct *tty, struct file *filp)
-{
-       unsigned int value;
-       struct ifx_spi_device *ifx_dev = tty->driver_data;
-
-       value =
-       (test_bit(IFX_SPI_RTS, &ifx_dev->signal_state) ? TIOCM_RTS : 0) |
-       (test_bit(IFX_SPI_DTR, &ifx_dev->signal_state) ? TIOCM_DTR : 0) |
-       (test_bit(IFX_SPI_CTS, &ifx_dev->signal_state) ? TIOCM_CTS : 0) |
-       (test_bit(IFX_SPI_DSR, &ifx_dev->signal_state) ? TIOCM_DSR : 0) |
-       (test_bit(IFX_SPI_DCD, &ifx_dev->signal_state) ? TIOCM_CAR : 0) |
-       (test_bit(IFX_SPI_RI, &ifx_dev->signal_state) ? TIOCM_RNG : 0);
-       return value;
-}
-
-/**
- *     ifx_spi_tiocmset        -       set modem bits
- *     @tty: the tty structure
- *     @filp: file handle issuing the request
- *     @set: bits to set
- *     @clear: bits to clear
- *
- *     The IFX6x60 only supports DTR and RTS. Set them accordingly
- *     and flag that an update to the modem is needed.
- *
- *     FIXME: do we need to kick the tranfers when we do this ?
- */
-static int ifx_spi_tiocmset(struct tty_struct *tty, struct file *filp,
-                           unsigned int set, unsigned int clear)
-{
-       struct ifx_spi_device *ifx_dev = tty->driver_data;
-
-       if (set & TIOCM_RTS)
-               set_bit(IFX_SPI_RTS, &ifx_dev->signal_state);
-       if (set & TIOCM_DTR)
-               set_bit(IFX_SPI_DTR, &ifx_dev->signal_state);
-       if (clear & TIOCM_RTS)
-               clear_bit(IFX_SPI_RTS, &ifx_dev->signal_state);
-       if (clear & TIOCM_DTR)
-               clear_bit(IFX_SPI_DTR, &ifx_dev->signal_state);
-
-       set_bit(IFX_SPI_UPDATE, &ifx_dev->signal_state);
-       return 0;
-}
-
-/**
- *     ifx_spi_open    -       called on tty open
- *     @tty: our tty device
- *     @filp: file handle being associated with the tty
- *
- *     Open the tty interface. We let the tty_port layer do all the work
- *     for us.
- *
- *     FIXME: Remove single device assumption and saved_ifx_dev
- */
-static int ifx_spi_open(struct tty_struct *tty, struct file *filp)
-{
-       return tty_port_open(&saved_ifx_dev->tty_port, tty, filp);
-}
-
-/**
- *     ifx_spi_close   -       called when our tty closes
- *     @tty: the tty being closed
- *     @filp: the file handle being closed
- *
- *     Perform the close of the tty. We use the tty_port layer to do all
- *     our hard work.
- */
-static void ifx_spi_close(struct tty_struct *tty, struct file *filp)
-{
-       struct ifx_spi_device *ifx_dev = tty->driver_data;
-       tty_port_close(&ifx_dev->tty_port, tty, filp);
-       /* FIXME: should we do an ifx_spi_reset here ? */
-}
-
-/**
- *     ifx_decode_spi_header   -       decode received header
- *     @buffer: the received data
- *     @length: decoded length
- *     @more: decoded more flag
- *     @received_cts: status of cts we received
- *
- *     Note how received_cts is handled -- if header is all F it is left
- *     the same as it was, if header is all 0 it is set to 0 otherwise it is
- *     taken from the incoming header.
- *
- *     FIXME: endianness
- */
-static int ifx_spi_decode_spi_header(unsigned char *buffer, int *length,
-                       unsigned char *more, unsigned char *received_cts)
-{
-       u16 h1;
-       u16 h2;
-       u16 *in_buffer = (u16 *)buffer;
-
-       h1 = *in_buffer;
-       h2 = *(in_buffer+1);
-
-       if (h1 == 0 && h2 == 0) {
-               *received_cts = 0;
-               return IFX_SPI_HEADER_0;
-       } else if (h1 == 0xffff && h2 == 0xffff) {
-               /* spi_slave_cts remains as it was */
-               return IFX_SPI_HEADER_F;
-       }
-
-       *length = h1 & 0xfff;   /* upper bits of byte are flags */
-       *more = (buffer[1] >> IFX_SPI_MORE_BIT) & 1;
-       *received_cts = (buffer[3] >> IFX_SPI_CTS_BIT) & 1;
-       return 0;
-}
-
-/**
- *     ifx_setup_spi_header    -       set header fields
- *     @txbuffer: pointer to start of SPI buffer
- *     @tx_count: bytes
- *     @more: indicate if more to follow
- *
- *     Format up an SPI header for a transfer
- *
- *     FIXME: endianness?
- */
-static void ifx_spi_setup_spi_header(unsigned char *txbuffer, int tx_count,
-                                       unsigned char more)
-{
-       *(u16 *)(txbuffer) = tx_count;
-       *(u16 *)(txbuffer+2) = IFX_SPI_PAYLOAD_SIZE;
-       txbuffer[1] |= (more << IFX_SPI_MORE_BIT) & IFX_SPI_MORE_MASK;
-}
-
-/**
- *     ifx_spi_wakeup_serial   -       SPI space made
- *     @port_data: our SPI device
- *
- *     We have emptied the FIFO enough that we want to get more data
- *     queued into it. Poke the line discipline via tty_wakeup so that
- *     it will feed us more bits
- */
-static void ifx_spi_wakeup_serial(struct ifx_spi_device *ifx_dev)
-{
-       struct tty_struct *tty;
-
-       tty = tty_port_tty_get(&ifx_dev->tty_port);
-       if (!tty)
-               return;
-       tty_wakeup(tty);
-       tty_kref_put(tty);
-}
-
-/**
- *     ifx_spi_prepare_tx_buffer       -       prepare transmit frame
- *     @ifx_dev: our SPI device
- *
- *     The transmit buffr needs a header and various other bits of
- *     information followed by as much data as we can pull from the FIFO
- *     and transfer. This function formats up a suitable buffer in the
- *     ifx_dev->tx_buffer
- *
- *     FIXME: performance - should we wake the tty when the queue is half
- *                          empty ?
- */
-static int ifx_spi_prepare_tx_buffer(struct ifx_spi_device *ifx_dev)
-{
-       int temp_count;
-       int queue_length;
-       int tx_count;
-       unsigned char *tx_buffer;
-
-       tx_buffer = ifx_dev->tx_buffer;
-       memset(tx_buffer, 0, IFX_SPI_TRANSFER_SIZE);
-
-       /* make room for required SPI header */
-       tx_buffer += IFX_SPI_HEADER_OVERHEAD;
-       tx_count = IFX_SPI_HEADER_OVERHEAD;
-
-       /* clear to signal no more data if this turns out to be the
-        * last buffer sent in a sequence */
-       ifx_dev->spi_more = 0;
-
-       /* if modem cts is set, just send empty buffer */
-       if (!ifx_dev->spi_slave_cts) {
-               /* see if there's tx data */
-               queue_length = kfifo_len(&ifx_dev->tx_fifo);
-               if (queue_length != 0) {
-                       /* data to mux -- see if there's room for it */
-                       temp_count = min(queue_length, IFX_SPI_PAYLOAD_SIZE);
-                       temp_count = kfifo_out_locked(&ifx_dev->tx_fifo,
-                                       tx_buffer, temp_count,
-                                       &ifx_dev->fifo_lock);
-
-                       /* update buffer pointer and data count in message */
-                       tx_buffer += temp_count;
-                       tx_count += temp_count;
-                       if (temp_count == queue_length)
-                               /* poke port to get more data */
-                               ifx_spi_wakeup_serial(ifx_dev);
-                       else /* more data in port, use next SPI message */
-                               ifx_dev->spi_more = 1;
-               }
-       }
-       /* have data and info for header -- set up SPI header in buffer */
-       /* spi header needs payload size, not entire buffer size */
-       ifx_spi_setup_spi_header(ifx_dev->tx_buffer,
-                                       tx_count-IFX_SPI_HEADER_OVERHEAD,
-                                       ifx_dev->spi_more);
-       /* swap actual data in the buffer */
-       swap_buf((u16 *)(ifx_dev->tx_buffer), tx_count,
-               &ifx_dev->tx_buffer[IFX_SPI_TRANSFER_SIZE]);
-       return tx_count;
-}
-
-/**
- *     ifx_spi_write           -       line discipline write
- *     @tty: our tty device
- *     @buf: pointer to buffer to write (kernel space)
- *     @count: size of buffer
- *
- *     Write the characters we have been given into the FIFO. If the device
- *     is not active then activate it, when the SRDY line is asserted back
- *     this will commence I/O
- */
-static int ifx_spi_write(struct tty_struct *tty, const unsigned char *buf,
-                        int count)
-{
-       struct ifx_spi_device *ifx_dev = tty->driver_data;
-       unsigned char *tmp_buf = (unsigned char *)buf;
-       int tx_count = kfifo_in_locked(&ifx_dev->tx_fifo, tmp_buf, count,
-                                  &ifx_dev->fifo_lock);
-       mrdy_assert(ifx_dev);
-       return tx_count;
-}
-
-/**
- *     ifx_spi_chars_in_buffer -       line discipline helper
- *     @tty: our tty device
- *
- *     Report how much data we can accept before we drop bytes. As we use
- *     a simple FIFO this is nice and easy.
- */
-static int ifx_spi_write_room(struct tty_struct *tty)
-{
-       struct ifx_spi_device *ifx_dev = tty->driver_data;
-       return IFX_SPI_FIFO_SIZE - kfifo_len(&ifx_dev->tx_fifo);
-}
-
-/**
- *     ifx_spi_chars_in_buffer -       line discipline helper
- *     @tty: our tty device
- *
- *     Report how many characters we have buffered. In our case this is the
- *     number of bytes sitting in our transmit FIFO.
- */
-static int ifx_spi_chars_in_buffer(struct tty_struct *tty)
-{
-       struct ifx_spi_device *ifx_dev = tty->driver_data;
-       return kfifo_len(&ifx_dev->tx_fifo);
-}
-
-/**
- *     ifx_port_hangup
- *     @port: our tty port
- *
- *     tty port hang up. Called when tty_hangup processing is invoked either
- *     by loss of carrier, or by software (eg vhangup). Serialized against
- *     activate/shutdown by the tty layer.
- */
-static void ifx_spi_hangup(struct tty_struct *tty)
-{
-       struct ifx_spi_device *ifx_dev = tty->driver_data;
-       tty_port_hangup(&ifx_dev->tty_port);
-}
-
-/**
- *     ifx_port_activate
- *     @port: our tty port
- *
- *     tty port activate method - called for first open. Serialized
- *     with hangup and shutdown by the tty layer.
- */
-static int ifx_port_activate(struct tty_port *port, struct tty_struct *tty)
-{
-       struct ifx_spi_device *ifx_dev =
-               container_of(port, struct ifx_spi_device, tty_port);
-
-       /* clear any old data; can't do this in 'close' */
-       kfifo_reset(&ifx_dev->tx_fifo);
-
-       /* put port data into this tty */
-       tty->driver_data = ifx_dev;
-
-       /* allows flip string push from int context */
-       tty->low_latency = 1;
-
-       return 0;
-}
-
-/**
- *     ifx_port_shutdown
- *     @port: our tty port
- *
- *     tty port shutdown method - called for last port close. Serialized
- *     with hangup and activate by the tty layer.
- */
-static void ifx_port_shutdown(struct tty_port *port)
-{
-       struct ifx_spi_device *ifx_dev =
-               container_of(port, struct ifx_spi_device, tty_port);
-
-       mrdy_set_low(ifx_dev);
-       clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
-       tasklet_kill(&ifx_dev->io_work_tasklet);
-}
-
-static const struct tty_port_operations ifx_tty_port_ops = {
-       .activate = ifx_port_activate,
-       .shutdown = ifx_port_shutdown,
-};
-
-static const struct tty_operations ifx_spi_serial_ops = {
-       .open = ifx_spi_open,
-       .close = ifx_spi_close,
-       .write = ifx_spi_write,
-       .hangup = ifx_spi_hangup,
-       .write_room = ifx_spi_write_room,
-       .chars_in_buffer = ifx_spi_chars_in_buffer,
-       .tiocmget = ifx_spi_tiocmget,
-       .tiocmset = ifx_spi_tiocmset,
-};
-
-/**
- *     ifx_spi_insert_fip_string       -       queue received data
- *     @ifx_ser: our SPI device
- *     @chars: buffer we have received
- *     @size: number of chars reeived
- *
- *     Queue bytes to the tty assuming the tty side is currently open. If
- *     not the discard the data.
- */
-static void ifx_spi_insert_flip_string(struct ifx_spi_device *ifx_dev,
-                                   unsigned char *chars, size_t size)
-{
-       struct tty_struct *tty = tty_port_tty_get(&ifx_dev->tty_port);
-       if (!tty)
-               return;
-       tty_insert_flip_string(tty, chars, size);
-       tty_flip_buffer_push(tty);
-       tty_kref_put(tty);
-}
-
-/**
- *     ifx_spi_complete        -       SPI transfer completed
- *     @ctx: our SPI device
- *
- *     An SPI transfer has completed. Process any received data and kick off
- *     any further transmits we can commence.
- */
-static void ifx_spi_complete(void *ctx)
-{
-       struct ifx_spi_device *ifx_dev = ctx;
-       struct tty_struct *tty;
-       struct tty_ldisc *ldisc = NULL;
-       int length;
-       int actual_length;
-       unsigned char more;
-       unsigned char cts;
-       int local_write_pending = 0;
-       int queue_length;
-       int srdy;
-       int decode_result;
-
-       mrdy_set_low(ifx_dev);
-
-       if (!ifx_dev->spi_msg.status) {
-               /* check header validity, get comm flags */
-               swap_buf((u16 *)ifx_dev->rx_buffer, IFX_SPI_HEADER_OVERHEAD,
-                       &ifx_dev->rx_buffer[IFX_SPI_HEADER_OVERHEAD]);
-               decode_result = ifx_spi_decode_spi_header(ifx_dev->rx_buffer,
-                               &length, &more, &cts);
-               if (decode_result == IFX_SPI_HEADER_0) {
-                       dev_dbg(&ifx_dev->spi_dev->dev,
-                               "ignore input: invalid header 0");
-                       ifx_dev->spi_slave_cts = 0;
-                       goto complete_exit;
-               } else if (decode_result == IFX_SPI_HEADER_F) {
-                       dev_dbg(&ifx_dev->spi_dev->dev,
-                               "ignore input: invalid header F");
-                       goto complete_exit;
-               }
-
-               ifx_dev->spi_slave_cts = cts;
-
-               actual_length = min((unsigned int)length,
-                                       ifx_dev->spi_msg.actual_length);
-               swap_buf((u16 *)(ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD),
-                        actual_length,
-                        &ifx_dev->rx_buffer[IFX_SPI_TRANSFER_SIZE]);
-               ifx_spi_insert_flip_string(
-                       ifx_dev,
-                       ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD,
-                       (size_t)actual_length);
-       } else {
-               dev_dbg(&ifx_dev->spi_dev->dev, "SPI transfer error %d",
-                      ifx_dev->spi_msg.status);
-       }
-
-complete_exit:
-       if (ifx_dev->write_pending) {
-               ifx_dev->write_pending = 0;
-               local_write_pending = 1;
-       }
-
-       clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &(ifx_dev->flags));
-
-       queue_length = kfifo_len(&ifx_dev->tx_fifo);
-       srdy = gpio_get_value(ifx_dev->gpio.srdy);
-       if (!srdy)
-               ifx_spi_power_state_clear(ifx_dev, IFX_SPI_POWER_SRDY);
-
-       /* schedule output if there is more to do */
-       if (test_and_clear_bit(IFX_SPI_STATE_IO_READY, &ifx_dev->flags))
-               tasklet_schedule(&ifx_dev->io_work_tasklet);
-       else {
-               if (more || ifx_dev->spi_more || queue_length > 0 ||
-                       local_write_pending) {
-                       if (ifx_dev->spi_slave_cts) {
-                               if (more)
-                                       mrdy_assert(ifx_dev);
-                       } else
-                               mrdy_assert(ifx_dev);
-               } else {
-                       /*
-                        * poke line discipline driver if any for more data
-                        * may or may not get more data to write
-                        * for now, say not busy
-                        */
-                       ifx_spi_power_state_clear(ifx_dev,
-                                                 IFX_SPI_POWER_DATA_PENDING);
-                       tty = tty_port_tty_get(&ifx_dev->tty_port);
-                       if (tty) {
-                               ldisc = tty_ldisc_ref(tty);
-                               if (ldisc) {
-                                       ldisc->ops->write_wakeup(tty);
-                                       tty_ldisc_deref(ldisc);
-                               }
-                               tty_kref_put(tty);
-                       }
-               }
-       }
-}
-
-/**
- *     ifx_spio_io             -       I/O tasklet
- *     @data: our SPI device
- *
- *     Queue data for transmission if possible and then kick off the
- *     transfer.
- */
-static void ifx_spi_io(unsigned long data)
-{
-       int retval;
-       struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *) data;
-
-       if (!test_and_set_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags)) {
-               if (ifx_dev->gpio.unack_srdy_int_nb > 0)
-                       ifx_dev->gpio.unack_srdy_int_nb--;
-
-               ifx_spi_prepare_tx_buffer(ifx_dev);
-
-               spi_message_init(&ifx_dev->spi_msg);
-               INIT_LIST_HEAD(&ifx_dev->spi_msg.queue);
-
-               ifx_dev->spi_msg.context = ifx_dev;
-               ifx_dev->spi_msg.complete = ifx_spi_complete;
-
-               /* set up our spi transfer */
-               /* note len is BYTES, not transfers */
-               ifx_dev->spi_xfer.len = IFX_SPI_TRANSFER_SIZE;
-               ifx_dev->spi_xfer.cs_change = 0;
-               ifx_dev->spi_xfer.speed_hz = 12500000;
-               /* ifx_dev->spi_xfer.speed_hz = 390625; */
-               ifx_dev->spi_xfer.bits_per_word = spi_b16 ? 16 : 8;
-
-               ifx_dev->spi_xfer.tx_buf = ifx_dev->tx_buffer;
-               ifx_dev->spi_xfer.rx_buf = ifx_dev->rx_buffer;
-
-               /*
-                * setup dma pointers
-                */
-               if (ifx_dev->is_6160) {
-                       ifx_dev->spi_msg.is_dma_mapped = 1;
-                       ifx_dev->tx_dma = ifx_dev->tx_bus;
-                       ifx_dev->rx_dma = ifx_dev->rx_bus;
-                       ifx_dev->spi_xfer.tx_dma = ifx_dev->tx_dma;
-                       ifx_dev->spi_xfer.rx_dma = ifx_dev->rx_dma;
-               } else {
-                       ifx_dev->spi_msg.is_dma_mapped = 0;
-                       ifx_dev->tx_dma = (dma_addr_t)0;
-                       ifx_dev->rx_dma = (dma_addr_t)0;
-                       ifx_dev->spi_xfer.tx_dma = (dma_addr_t)0;
-                       ifx_dev->spi_xfer.rx_dma = (dma_addr_t)0;
-               }
-
-               spi_message_add_tail(&ifx_dev->spi_xfer, &ifx_dev->spi_msg);
-
-               /* Assert MRDY. This may have already been done by the write
-                * routine.
-                */
-               mrdy_assert(ifx_dev);
-
-               retval = spi_async(ifx_dev->spi_dev, &ifx_dev->spi_msg);
-               if (retval) {
-                       clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS,
-                                 &ifx_dev->flags);
-                       tasklet_schedule(&ifx_dev->io_work_tasklet);
-                       return;
-               }
-       } else
-               ifx_dev->write_pending = 1;
-}
-
-/**
- *     ifx_spi_free_port       -       free up the tty side
- *     @ifx_dev: IFX device going away
- *
- *     Unregister and free up a port when the device goes away
- */
-static void ifx_spi_free_port(struct ifx_spi_device *ifx_dev)
-{
-       if (ifx_dev->tty_dev)
-               tty_unregister_device(tty_drv, ifx_dev->minor);
-       kfifo_free(&ifx_dev->tx_fifo);
-}
-
-/**
- *     ifx_spi_create_port     -       create a new port
- *     @ifx_dev: our spi device
- *
- *     Allocate and initialise the tty port that goes with this interface
- *     and add it to the tty layer so that it can be opened.
- */
-static int ifx_spi_create_port(struct ifx_spi_device *ifx_dev)
-{
-       int ret = 0;
-       struct tty_port *pport = &ifx_dev->tty_port;
-
-       spin_lock_init(&ifx_dev->fifo_lock);
-       lockdep_set_class_and_subclass(&ifx_dev->fifo_lock,
-               &ifx_spi_key, 0);
-
-       if (kfifo_alloc(&ifx_dev->tx_fifo, IFX_SPI_FIFO_SIZE, GFP_KERNEL)) {
-               ret = -ENOMEM;
-               goto error_ret;
-       }
-
-       pport->ops = &ifx_tty_port_ops;
-       tty_port_init(pport);
-       ifx_dev->minor = IFX_SPI_TTY_ID;
-       ifx_dev->tty_dev = tty_register_device(tty_drv, ifx_dev->minor,
-                                              &ifx_dev->spi_dev->dev);
-       if (IS_ERR(ifx_dev->tty_dev)) {
-               dev_dbg(&ifx_dev->spi_dev->dev,
-                       "%s: registering tty device failed", __func__);
-               ret = PTR_ERR(ifx_dev->tty_dev);
-               goto error_ret;
-       }
-       return 0;
-
-error_ret:
-       ifx_spi_free_port(ifx_dev);
-       return ret;
-}
-
-/**
- *     ifx_spi_handle_srdy             -       handle SRDY
- *     @ifx_dev: device asserting SRDY
- *
- *     Check our device state and see what we need to kick off when SRDY
- *     is asserted. This usually means killing the timer and firing off the
- *     I/O processing.
- */
-static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev)
-{
-       if (test_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags)) {
-               del_timer_sync(&ifx_dev->spi_timer);
-               clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
-       }
-
-       ifx_spi_power_state_set(ifx_dev, IFX_SPI_POWER_SRDY);
-
-       if (!test_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags))
-               tasklet_schedule(&ifx_dev->io_work_tasklet);
-       else
-               set_bit(IFX_SPI_STATE_IO_READY, &ifx_dev->flags);
-}
-
-/**
- *     ifx_spi_srdy_interrupt  -       SRDY asserted
- *     @irq: our IRQ number
- *     @dev: our ifx device
- *
- *     The modem asserted SRDY. Handle the srdy event
- */
-static irqreturn_t ifx_spi_srdy_interrupt(int irq, void *dev)
-{
-       struct ifx_spi_device *ifx_dev = dev;
-       ifx_dev->gpio.unack_srdy_int_nb++;
-       ifx_spi_handle_srdy(ifx_dev);
-       return IRQ_HANDLED;
-}
-
-/**
- *     ifx_spi_reset_interrupt -       Modem has changed reset state
- *     @irq: interrupt number
- *     @dev: our device pointer
- *
- *     The modem has either entered or left reset state. Check the GPIO
- *     line to see which.
- *
- *     FIXME: review locking on MR_INPROGRESS versus
- *     parallel unsolicited reset/solicited reset
- */
-static irqreturn_t ifx_spi_reset_interrupt(int irq, void *dev)
-{
-       struct ifx_spi_device *ifx_dev = dev;
-       int val = gpio_get_value(ifx_dev->gpio.reset_out);
-       int solreset = test_bit(MR_START, &ifx_dev->mdm_reset_state);
-
-       if (val == 0) {
-               /* entered reset */
-               set_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state);
-               if (!solreset) {
-                       /* unsolicited reset  */
-                       ifx_spi_ttyhangup(ifx_dev);
-               }
-       } else {
-               /* exited reset */
-               clear_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state);
-               if (solreset) {
-                       set_bit(MR_COMPLETE, &ifx_dev->mdm_reset_state);
-                       wake_up(&ifx_dev->mdm_reset_wait);
-               }
-       }
-       return IRQ_HANDLED;
-}
-
-/**
- *     ifx_spi_free_device - free device
- *     @ifx_dev: device to free
- *
- *     Free the IFX device
- */
-static void ifx_spi_free_device(struct ifx_spi_device *ifx_dev)
-{
-       ifx_spi_free_port(ifx_dev);
-       dma_free_coherent(&ifx_dev->spi_dev->dev,
-                               IFX_SPI_TRANSFER_SIZE,
-                               ifx_dev->tx_buffer,
-                               ifx_dev->tx_bus);
-       dma_free_coherent(&ifx_dev->spi_dev->dev,
-                               IFX_SPI_TRANSFER_SIZE,
-                               ifx_dev->rx_buffer,
-                               ifx_dev->rx_bus);
-}
-
-/**
- *     ifx_spi_reset   -       reset modem
- *     @ifx_dev: modem to reset
- *
- *     Perform a reset on the modem
- */
-static int ifx_spi_reset(struct ifx_spi_device *ifx_dev)
-{
-       int ret;
-       /*
-        * set up modem power, reset
-        *
-        * delays are required on some platforms for the modem
-        * to reset properly
-        */
-       set_bit(MR_START, &ifx_dev->mdm_reset_state);
-       gpio_set_value(ifx_dev->gpio.po, 0);
-       gpio_set_value(ifx_dev->gpio.reset, 0);
-       msleep(25);
-       gpio_set_value(ifx_dev->gpio.reset, 1);
-       msleep(1);
-       gpio_set_value(ifx_dev->gpio.po, 1);
-       msleep(1);
-       gpio_set_value(ifx_dev->gpio.po, 0);
-       ret = wait_event_timeout(ifx_dev->mdm_reset_wait,
-                                test_bit(MR_COMPLETE,
-                                         &ifx_dev->mdm_reset_state),
-                                IFX_RESET_TIMEOUT);
-       if (!ret)
-               dev_warn(&ifx_dev->spi_dev->dev, "Modem reset timeout: (state:%lx)",
-                        ifx_dev->mdm_reset_state);
-
-       ifx_dev->mdm_reset_state = 0;
-       return ret;
-}
-
-/**
- *     ifx_spi_spi_probe       -       probe callback
- *     @spi: our possible matching SPI device
- *
- *     Probe for a 6x60 modem on SPI bus. Perform any needed device and
- *     GPIO setup.
- *
- *     FIXME:
- *     -       Support for multiple devices
- *     -       Split out MID specific GPIO handling eventually
- */
-
-static int ifx_spi_spi_probe(struct spi_device *spi)
-{
-       int ret;
-       int srdy;
-       struct ifx_modem_platform_data *pl_data = NULL;
-       struct ifx_spi_device *ifx_dev;
-
-       if (saved_ifx_dev) {
-               dev_dbg(&spi->dev, "ignoring subsequent detection");
-               return -ENODEV;
-       }
-
-       /* initialize structure to hold our device variables */
-       ifx_dev = kzalloc(sizeof(struct ifx_spi_device), GFP_KERNEL);
-       if (!ifx_dev) {
-               dev_err(&spi->dev, "spi device allocation failed");
-               return -ENOMEM;
-       }
-       saved_ifx_dev = ifx_dev;
-       ifx_dev->spi_dev = spi;
-       clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags);
-       spin_lock_init(&ifx_dev->write_lock);
-       spin_lock_init(&ifx_dev->power_lock);
-       ifx_dev->power_status = 0;
-       init_timer(&ifx_dev->spi_timer);
-       ifx_dev->spi_timer.function = ifx_spi_timeout;
-       ifx_dev->spi_timer.data = (unsigned long)ifx_dev;
-       ifx_dev->is_6160 = pl_data->is_6160;
-
-       /* ensure SPI protocol flags are initialized to enable transfer */
-       ifx_dev->spi_more = 0;
-       ifx_dev->spi_slave_cts = 0;
-
-       /*initialize transfer and dma buffers */
-       ifx_dev->tx_buffer = dma_alloc_coherent(&ifx_dev->spi_dev->dev,
-                               IFX_SPI_TRANSFER_SIZE,
-                               &ifx_dev->tx_bus,
-                               GFP_KERNEL);
-       if (!ifx_dev->tx_buffer) {
-               dev_err(&spi->dev, "DMA-TX buffer allocation failed");
-               ret = -ENOMEM;
-               goto error_ret;
-       }
-       ifx_dev->rx_buffer = dma_alloc_coherent(&ifx_dev->spi_dev->dev,
-                               IFX_SPI_TRANSFER_SIZE,
-                               &ifx_dev->rx_bus,
-                               GFP_KERNEL);
-       if (!ifx_dev->rx_buffer) {
-               dev_err(&spi->dev, "DMA-RX buffer allocation failed");
-               ret = -ENOMEM;
-               goto error_ret;
-       }
-
-       /* initialize waitq for modem reset */
-       init_waitqueue_head(&ifx_dev->mdm_reset_wait);
-
-       spi_set_drvdata(spi, ifx_dev);
-       tasklet_init(&ifx_dev->io_work_tasklet, ifx_spi_io,
-                                               (unsigned long)ifx_dev);
-
-       set_bit(IFX_SPI_STATE_PRESENT, &ifx_dev->flags);
-
-       /* create our tty port */
-       ret = ifx_spi_create_port(ifx_dev);
-       if (ret != 0) {
-               dev_err(&spi->dev, "create default tty port failed");
-               goto error_ret;
-       }
-
-       pl_data = (struct ifx_modem_platform_data *)spi->dev.platform_data;
-       if (pl_data) {
-               ifx_dev->gpio.reset = pl_data->rst_pmu;
-               ifx_dev->gpio.po = pl_data->pwr_on;
-               ifx_dev->gpio.mrdy = pl_data->mrdy;
-               ifx_dev->gpio.srdy = pl_data->srdy;
-               ifx_dev->gpio.reset_out = pl_data->rst_out;
-       } else {
-               dev_err(&spi->dev, "missing platform data!");
-               ret = -ENODEV;
-               goto error_ret;
-       }
-
-       dev_info(&spi->dev, "gpios %d, %d, %d, %d, %d",
-                ifx_dev->gpio.reset, ifx_dev->gpio.po, ifx_dev->gpio.mrdy,
-                ifx_dev->gpio.srdy, ifx_dev->gpio.reset_out);
-
-       /* Configure gpios */
-       ret = gpio_request(ifx_dev->gpio.reset, "ifxModem");
-       if (ret < 0) {
-               dev_err(&spi->dev, "Unable to allocate GPIO%d (RESET)",
-                       ifx_dev->gpio.reset);
-               goto error_ret;
-       }
-       ret += gpio_direction_output(ifx_dev->gpio.reset, 0);
-       ret += gpio_export(ifx_dev->gpio.reset, 1);
-       if (ret) {
-               dev_err(&spi->dev, "Unable to configure GPIO%d (RESET)",
-                       ifx_dev->gpio.reset);
-               ret = -EBUSY;
-               goto error_ret2;
-       }
-
-       ret = gpio_request(ifx_dev->gpio.po, "ifxModem");
-       ret += gpio_direction_output(ifx_dev->gpio.po, 0);
-       ret += gpio_export(ifx_dev->gpio.po, 1);
-       if (ret) {
-               dev_err(&spi->dev, "Unable to configure GPIO%d (ON)",
-                       ifx_dev->gpio.po);
-               ret = -EBUSY;
-               goto error_ret3;
-       }
-
-       ret = gpio_request(ifx_dev->gpio.mrdy, "ifxModem");
-       if (ret < 0) {
-               dev_err(&spi->dev, "Unable to allocate GPIO%d (MRDY)",
-                       ifx_dev->gpio.mrdy);
-               goto error_ret3;
-       }
-       ret += gpio_export(ifx_dev->gpio.mrdy, 1);
-       ret += gpio_direction_output(ifx_dev->gpio.mrdy, 0);
-       if (ret) {
-               dev_err(&spi->dev, "Unable to configure GPIO%d (MRDY)",
-                       ifx_dev->gpio.mrdy);
-               ret = -EBUSY;
-               goto error_ret4;
-       }
-
-       ret = gpio_request(ifx_dev->gpio.srdy, "ifxModem");
-       if (ret < 0) {
-               dev_err(&spi->dev, "Unable to allocate GPIO%d (SRDY)",
-                       ifx_dev->gpio.srdy);
-               ret = -EBUSY;
-               goto error_ret4;
-       }
-       ret += gpio_export(ifx_dev->gpio.srdy, 1);
-       ret += gpio_direction_input(ifx_dev->gpio.srdy);
-       if (ret) {
-               dev_err(&spi->dev, "Unable to configure GPIO%d (SRDY)",
-                       ifx_dev->gpio.srdy);
-               ret = -EBUSY;
-               goto error_ret5;
-       }
-
-       ret = gpio_request(ifx_dev->gpio.reset_out, "ifxModem");
-       if (ret < 0) {
-               dev_err(&spi->dev, "Unable to allocate GPIO%d (RESET_OUT)",
-                       ifx_dev->gpio.reset_out);
-               goto error_ret5;
-       }
-       ret += gpio_export(ifx_dev->gpio.reset_out, 1);
-       ret += gpio_direction_input(ifx_dev->gpio.reset_out);
-       if (ret) {
-               dev_err(&spi->dev, "Unable to configure GPIO%d (RESET_OUT)",
-                       ifx_dev->gpio.reset_out);
-               ret = -EBUSY;
-               goto error_ret6;
-       }
-
-       ret = request_irq(gpio_to_irq(ifx_dev->gpio.reset_out),
-                         ifx_spi_reset_interrupt,
-                         IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, DRVNAME,
-               (void *)ifx_dev);
-       if (ret) {
-               dev_err(&spi->dev, "Unable to get irq %x\n",
-                       gpio_to_irq(ifx_dev->gpio.reset_out));
-               goto error_ret6;
-       }
-
-       ret = ifx_spi_reset(ifx_dev);
-
-       ret = request_irq(gpio_to_irq(ifx_dev->gpio.srdy),
-                         ifx_spi_srdy_interrupt,
-                         IRQF_TRIGGER_RISING, DRVNAME,
-                         (void *)ifx_dev);
-       if (ret) {
-               dev_err(&spi->dev, "Unable to get irq %x",
-                       gpio_to_irq(ifx_dev->gpio.srdy));
-               goto error_ret7;
-       }
-
-       /* set pm runtime power state and register with power system */
-       pm_runtime_set_active(&spi->dev);
-       pm_runtime_enable(&spi->dev);
-
-       /* handle case that modem is already signaling SRDY */
-       /* no outgoing tty open at this point, this just satisfies the
-        * modem's read and should reset communication properly
-        */
-       srdy = gpio_get_value(ifx_dev->gpio.srdy);
-
-       if (srdy) {
-               mrdy_assert(ifx_dev);
-               ifx_spi_handle_srdy(ifx_dev);
-       } else
-               mrdy_set_low(ifx_dev);
-       return 0;
-
-error_ret7:
-       free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev);
-error_ret6:
-       gpio_free(ifx_dev->gpio.srdy);
-error_ret5:
-       gpio_free(ifx_dev->gpio.mrdy);
-error_ret4:
-       gpio_free(ifx_dev->gpio.reset);
-error_ret3:
-       gpio_free(ifx_dev->gpio.po);
-error_ret2:
-       gpio_free(ifx_dev->gpio.reset_out);
-error_ret:
-       ifx_spi_free_device(ifx_dev);
-       saved_ifx_dev = NULL;
-       return ret;
-}
-
-/**
- *     ifx_spi_spi_remove      -       SPI device was removed
- *     @spi: SPI device
- *
- *     FIXME: We should be shutting the device down here not in
- *     the module unload path.
- */
-
-static int ifx_spi_spi_remove(struct spi_device *spi)
-{
-       struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi);
-       /* stop activity */
-       tasklet_kill(&ifx_dev->io_work_tasklet);
-       /* free irq */
-       free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev);
-       free_irq(gpio_to_irq(ifx_dev->gpio.srdy), (void *)ifx_dev);
-
-       gpio_free(ifx_dev->gpio.srdy);
-       gpio_free(ifx_dev->gpio.mrdy);
-       gpio_free(ifx_dev->gpio.reset);
-       gpio_free(ifx_dev->gpio.po);
-       gpio_free(ifx_dev->gpio.reset_out);
-
-       /* free allocations */
-       ifx_spi_free_device(ifx_dev);
-
-       saved_ifx_dev = NULL;
-       return 0;
-}
-
-/**
- *     ifx_spi_spi_shutdown    -       called on SPI shutdown
- *     @spi: SPI device
- *
- *     No action needs to be taken here
- */
-
-static void ifx_spi_spi_shutdown(struct spi_device *spi)
-{
-}
-
-/*
- * various suspends and resumes have nothing to do
- * no hardware to save state for
- */
-
-/**
- *     ifx_spi_spi_suspend     -       suspend SPI on system suspend
- *     @dev: device being suspended
- *
- *     Suspend the SPI side. No action needed on Intel MID platforms, may
- *     need extending for other systems.
- */
-static int ifx_spi_spi_suspend(struct spi_device *spi, pm_message_t msg)
-{
-       return 0;
-}
-
-/**
- *     ifx_spi_spi_resume      -       resume SPI side on system resume
- *     @dev: device being suspended
- *
- *     Suspend the SPI side. No action needed on Intel MID platforms, may
- *     need extending for other systems.
- */
-static int ifx_spi_spi_resume(struct spi_device *spi)
-{
-       return 0;
-}
-
-/**
- *     ifx_spi_pm_suspend      -       suspend modem on system suspend
- *     @dev: device being suspended
- *
- *     Suspend the modem. No action needed on Intel MID platforms, may
- *     need extending for other systems.
- */
-static int ifx_spi_pm_suspend(struct device *dev)
-{
-       return 0;
-}
-
-/**
- *     ifx_spi_pm_resume       -       resume modem on system resume
- *     @dev: device being suspended
- *
- *     Allow the modem to resume. No action needed.
- *
- *     FIXME: do we need to reset anything here ?
- */
-static int ifx_spi_pm_resume(struct device *dev)
-{
-       return 0;
-}
-
-/**
- *     ifx_spi_pm_runtime_resume       -       suspend modem
- *     @dev: device being suspended
- *
- *     Allow the modem to resume. No action needed.
- */
-static int ifx_spi_pm_runtime_resume(struct device *dev)
-{
-       return 0;
-}
-
-/**
- *     ifx_spi_pm_runtime_suspend      -       suspend modem
- *     @dev: device being suspended
- *
- *     Allow the modem to suspend and thus suspend to continue up the
- *     device tree.
- */
-static int ifx_spi_pm_runtime_suspend(struct device *dev)
-{
-       return 0;
-}
-
-/**
- *     ifx_spi_pm_runtime_idle         -       check if modem idle
- *     @dev: our device
- *
- *     Check conditions and queue runtime suspend if idle.
- */
-static int ifx_spi_pm_runtime_idle(struct device *dev)
-{
-       struct spi_device *spi = to_spi_device(dev);
-       struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi);
-
-       if (!ifx_dev->power_status)
-               pm_runtime_suspend(dev);
-
-       return 0;
-}
-
-static const struct dev_pm_ops ifx_spi_pm = {
-       .resume = ifx_spi_pm_resume,
-       .suspend = ifx_spi_pm_suspend,
-       .runtime_resume = ifx_spi_pm_runtime_resume,
-       .runtime_suspend = ifx_spi_pm_runtime_suspend,
-       .runtime_idle = ifx_spi_pm_runtime_idle
-};
-
-static const struct spi_device_id ifx_id_table[] = {
-       {"ifx6160", 0},
-       {"ifx6260", 0},
-       { }
-};
-MODULE_DEVICE_TABLE(spi, ifx_id_table);
-
-/* spi operations */
-static const struct spi_driver ifx_spi_driver_6160 = {
-       .driver = {
-               .name = "ifx6160",
-               .bus = &spi_bus_type,
-               .pm = &ifx_spi_pm,
-               .owner = THIS_MODULE},
-       .probe = ifx_spi_spi_probe,
-       .shutdown = ifx_spi_spi_shutdown,
-       .remove = __devexit_p(ifx_spi_spi_remove),
-       .suspend = ifx_spi_spi_suspend,
-       .resume = ifx_spi_spi_resume,
-       .id_table = ifx_id_table
-};
-
-/**
- *     ifx_spi_exit    -       module exit
- *
- *     Unload the module.
- */
-
-static void __exit ifx_spi_exit(void)
-{
-       /* unregister */
-       tty_unregister_driver(tty_drv);
-       spi_unregister_driver((void *)&ifx_spi_driver_6160);
-}
-
-/**
- *     ifx_spi_init            -       module entry point
- *
- *     Initialise the SPI and tty interfaces for the IFX SPI driver
- *     We need to initialize upper-edge spi driver after the tty
- *     driver because otherwise the spi probe will race
- */
-
-static int __init ifx_spi_init(void)
-{
-       int result;
-
-       tty_drv = alloc_tty_driver(1);
-       if (!tty_drv) {
-               pr_err("%s: alloc_tty_driver failed", DRVNAME);
-               return -ENOMEM;
-       }
-
-       tty_drv->magic = TTY_DRIVER_MAGIC;
-       tty_drv->owner = THIS_MODULE;
-       tty_drv->driver_name = DRVNAME;
-       tty_drv->name = TTYNAME;
-       tty_drv->minor_start = IFX_SPI_TTY_ID;
-       tty_drv->num = 1;
-       tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
-       tty_drv->subtype = SERIAL_TYPE_NORMAL;
-       tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
-       tty_drv->init_termios = tty_std_termios;
-
-       tty_set_operations(tty_drv, &ifx_spi_serial_ops);
-
-       result = tty_register_driver(tty_drv);
-       if (result) {
-               pr_err("%s: tty_register_driver failed(%d)",
-                       DRVNAME, result);
-               put_tty_driver(tty_drv);
-               return result;
-       }
-
-       result = spi_register_driver((void *)&ifx_spi_driver_6160);
-       if (result) {
-               pr_err("%s: spi_register_driver failed(%d)",
-                       DRVNAME, result);
-               tty_unregister_driver(tty_drv);
-       }
-       return result;
-}
-
-module_init(ifx_spi_init);
-module_exit(ifx_spi_exit);
-
-MODULE_AUTHOR("Intel");
-MODULE_DESCRIPTION("IFX6x60 spi driver");
-MODULE_LICENSE("GPL");
-MODULE_INFO(Version, "0.1-IFX6x60");
diff --git a/drivers/serial/ifx6x60.h b/drivers/serial/ifx6x60.h
deleted file mode 100644 (file)
index deb7b8d..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/****************************************************************************
- *
- * Driver for the IFX spi modem.
- *
- * Copyright (C) 2009, 2010 Intel Corp
- * Jim Stanley <jim.stanley@intel.com>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
- * USA
- *
- *
- *
- *****************************************************************************/
-#ifndef _IFX6X60_H
-#define _IFX6X60_H
-
-#define DRVNAME                                "ifx6x60"
-#define TTYNAME                                "ttyIFX"
-
-/* #define IFX_THROTTLE_CODE */
-
-#define IFX_SPI_MAX_MINORS             1
-#define IFX_SPI_TRANSFER_SIZE          2048
-#define IFX_SPI_FIFO_SIZE              4096
-
-#define IFX_SPI_HEADER_OVERHEAD                4
-#define IFX_RESET_TIMEOUT              msecs_to_jiffies(50)
-
-/* device flags bitfield definitions */
-#define IFX_SPI_STATE_PRESENT          0
-#define IFX_SPI_STATE_IO_IN_PROGRESS   1
-#define IFX_SPI_STATE_IO_READY         2
-#define IFX_SPI_STATE_TIMER_PENDING    3
-
-/* flow control bitfields */
-#define IFX_SPI_DCD                    0
-#define IFX_SPI_CTS                    1
-#define IFX_SPI_DSR                    2
-#define IFX_SPI_RI                     3
-#define IFX_SPI_DTR                    4
-#define IFX_SPI_RTS                    5
-#define IFX_SPI_TX_FC                  6
-#define IFX_SPI_RX_FC                  7
-#define IFX_SPI_UPDATE                 8
-
-#define IFX_SPI_PAYLOAD_SIZE           (IFX_SPI_TRANSFER_SIZE - \
-                                               IFX_SPI_HEADER_OVERHEAD)
-
-#define IFX_SPI_IRQ_TYPE               DETECT_EDGE_RISING
-#define IFX_SPI_GPIO_TARGET            0
-#define IFX_SPI_GPIO0                  0x105
-
-#define IFX_SPI_STATUS_TIMEOUT         (2000*HZ)
-
-/* values for bits in power status byte */
-#define IFX_SPI_POWER_DATA_PENDING     1
-#define IFX_SPI_POWER_SRDY             2
-
-struct ifx_spi_device {
-       /* Our SPI device */
-       struct spi_device *spi_dev;
-
-       /* Port specific data */
-       struct kfifo tx_fifo;
-       spinlock_t fifo_lock;
-       unsigned long signal_state;
-
-       /* TTY Layer logic */
-       struct tty_port tty_port;
-       struct device *tty_dev;
-       int minor;
-
-       /* Low level I/O work */
-       struct tasklet_struct io_work_tasklet;
-       unsigned long flags;
-       dma_addr_t rx_dma;
-       dma_addr_t tx_dma;
-
-       int is_6160;                            /* Modem type */
-
-       spinlock_t write_lock;
-       int write_pending;
-       spinlock_t power_lock;
-       unsigned char power_status;
-
-       unsigned char *rx_buffer;
-       unsigned char *tx_buffer;
-       dma_addr_t rx_bus;
-       dma_addr_t tx_bus;
-       unsigned char spi_more;
-       unsigned char spi_slave_cts;
-
-       struct timer_list spi_timer;
-
-       struct spi_message spi_msg;
-       struct spi_transfer spi_xfer;
-
-       struct {
-               /* gpio lines */
-               unsigned short srdy;            /* slave-ready gpio */
-               unsigned short mrdy;            /* master-ready gpio */
-               unsigned short reset;           /* modem-reset gpio */
-               unsigned short po;              /* modem-on gpio */
-               unsigned short reset_out;       /* modem-in-reset gpio */
-               /* state/stats */
-               int unack_srdy_int_nb;
-       } gpio;
-
-       /* modem reset */
-       unsigned long mdm_reset_state;
-#define MR_START       0
-#define MR_INPROGRESS  1
-#define MR_COMPLETE    2
-       wait_queue_head_t mdm_reset_wait;
-};
-
-#endif /* _IFX6X60_H */
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
deleted file mode 100644 (file)
index dfcf4b1..0000000
+++ /dev/null
@@ -1,1380 +0,0 @@
-/*
- *  linux/drivers/serial/imx.c
- *
- *  Driver for Motorola IMX serial ports
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *
- *  Author: Sascha Hauer <sascha@saschahauer.de>
- *  Copyright (C) 2004 Pengutronix
- *
- *  Copyright (C) 2009 emlix GmbH
- *  Author: Fabian Godehardt (added IrDA support for iMX)
- *
- * 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
- *
- * [29-Mar-2005] Mike Lee
- * Added hardware handshake
- */
-
-#if defined(CONFIG_SERIAL_IMX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/platform_device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/rational.h>
-#include <linux/slab.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <mach/hardware.h>
-#include <mach/imx-uart.h>
-
-/* Register definitions */
-#define URXD0 0x0  /* Receiver Register */
-#define URTX0 0x40 /* Transmitter Register */
-#define UCR1  0x80 /* Control Register 1 */
-#define UCR2  0x84 /* Control Register 2 */
-#define UCR3  0x88 /* Control Register 3 */
-#define UCR4  0x8c /* Control Register 4 */
-#define UFCR  0x90 /* FIFO Control Register */
-#define USR1  0x94 /* Status Register 1 */
-#define USR2  0x98 /* Status Register 2 */
-#define UESC  0x9c /* Escape Character Register */
-#define UTIM  0xa0 /* Escape Timer Register */
-#define UBIR  0xa4 /* BRM Incremental Register */
-#define UBMR  0xa8 /* BRM Modulator Register */
-#define UBRC  0xac /* Baud Rate Count Register */
-#define MX2_ONEMS 0xb0 /* One Millisecond register */
-#define UTS (cpu_is_mx1() ? 0xd0 : 0xb4) /* UART Test Register */
-
-/* UART Control Register Bit Fields.*/
-#define  URXD_CHARRDY    (1<<15)
-#define  URXD_ERR        (1<<14)
-#define  URXD_OVRRUN     (1<<13)
-#define  URXD_FRMERR     (1<<12)
-#define  URXD_BRK        (1<<11)
-#define  URXD_PRERR      (1<<10)
-#define  UCR1_ADEN       (1<<15) /* Auto dectect interrupt */
-#define  UCR1_ADBR       (1<<14) /* Auto detect baud rate */
-#define  UCR1_TRDYEN     (1<<13) /* Transmitter ready interrupt enable */
-#define  UCR1_IDEN       (1<<12) /* Idle condition interrupt */
-#define  UCR1_RRDYEN     (1<<9)         /* Recv ready interrupt enable */
-#define  UCR1_RDMAEN     (1<<8)         /* Recv ready DMA enable */
-#define  UCR1_IREN       (1<<7)         /* Infrared interface enable */
-#define  UCR1_TXMPTYEN   (1<<6)         /* Transimitter empty interrupt enable */
-#define  UCR1_RTSDEN     (1<<5)         /* RTS delta interrupt enable */
-#define  UCR1_SNDBRK     (1<<4)         /* Send break */
-#define  UCR1_TDMAEN     (1<<3)         /* Transmitter ready DMA enable */
-#define  MX1_UCR1_UARTCLKEN  (1<<2)     /* UART clock enabled, mx1 only */
-#define  UCR1_DOZE       (1<<1)         /* Doze */
-#define  UCR1_UARTEN     (1<<0)         /* UART enabled */
-#define  UCR2_ESCI              (1<<15) /* Escape seq interrupt enable */
-#define  UCR2_IRTS      (1<<14) /* Ignore RTS pin */
-#define  UCR2_CTSC      (1<<13) /* CTS pin control */
-#define  UCR2_CTS        (1<<12) /* Clear to send */
-#define  UCR2_ESCEN      (1<<11) /* Escape enable */
-#define  UCR2_PREN       (1<<8)  /* Parity enable */
-#define  UCR2_PROE       (1<<7)  /* Parity odd/even */
-#define  UCR2_STPB       (1<<6)         /* Stop */
-#define  UCR2_WS         (1<<5)         /* Word size */
-#define  UCR2_RTSEN      (1<<4)         /* Request to send interrupt enable */
-#define  UCR2_TXEN       (1<<2)         /* Transmitter enabled */
-#define  UCR2_RXEN       (1<<1)         /* Receiver enabled */
-#define  UCR2_SRST      (1<<0)  /* SW reset */
-#define  UCR3_DTREN     (1<<13) /* DTR interrupt enable */
-#define  UCR3_PARERREN   (1<<12) /* Parity enable */
-#define  UCR3_FRAERREN   (1<<11) /* Frame error interrupt enable */
-#define  UCR3_DSR        (1<<10) /* Data set ready */
-#define  UCR3_DCD        (1<<9)  /* Data carrier detect */
-#define  UCR3_RI         (1<<8)  /* Ring indicator */
-#define  UCR3_TIMEOUTEN  (1<<7)  /* Timeout interrupt enable */
-#define  UCR3_RXDSEN    (1<<6)  /* Receive status interrupt enable */
-#define  UCR3_AIRINTEN   (1<<5)  /* Async IR wake interrupt enable */
-#define  UCR3_AWAKEN    (1<<4)  /* Async wake interrupt enable */
-#define  MX1_UCR3_REF25         (1<<3)  /* Ref freq 25 MHz, only on mx1 */
-#define  MX1_UCR3_REF30         (1<<2)  /* Ref Freq 30 MHz, only on mx1 */
-#define  MX2_UCR3_RXDMUXSEL     (1<<2)  /* RXD Muxed Input Select, on mx2/mx3 */
-#define  UCR3_INVT      (1<<1)  /* Inverted Infrared transmission */
-#define  UCR3_BPEN      (1<<0)  /* Preset registers enable */
-#define  UCR4_CTSTL_SHF  10      /* CTS trigger level shift */
-#define  UCR4_CTSTL_MASK 0x3F    /* CTS trigger is 6 bits wide */
-#define  UCR4_INVR      (1<<9)  /* Inverted infrared reception */
-#define  UCR4_ENIRI     (1<<8)  /* Serial infrared interrupt enable */
-#define  UCR4_WKEN      (1<<7)  /* Wake interrupt enable */
-#define  UCR4_REF16     (1<<6)  /* Ref freq 16 MHz */
-#define  UCR4_IRSC      (1<<5)  /* IR special case */
-#define  UCR4_TCEN      (1<<3)  /* Transmit complete interrupt enable */
-#define  UCR4_BKEN      (1<<2)  /* Break condition interrupt enable */
-#define  UCR4_OREN      (1<<1)  /* Receiver overrun interrupt enable */
-#define  UCR4_DREN      (1<<0)  /* Recv data ready interrupt enable */
-#define  UFCR_RXTL_SHF   0       /* Receiver trigger level shift */
-#define  UFCR_RFDIV      (7<<7)  /* Reference freq divider mask */
-#define  UFCR_RFDIV_REG(x)     (((x) < 7 ? 6 - (x) : 6) << 7)
-#define  UFCR_TXTL_SHF   10      /* Transmitter trigger level shift */
-#define  USR1_PARITYERR  (1<<15) /* Parity error interrupt flag */
-#define  USR1_RTSS      (1<<14) /* RTS pin status */
-#define  USR1_TRDY      (1<<13) /* Transmitter ready interrupt/dma flag */
-#define  USR1_RTSD      (1<<12) /* RTS delta */
-#define  USR1_ESCF      (1<<11) /* Escape seq interrupt flag */
-#define  USR1_FRAMERR    (1<<10) /* Frame error interrupt flag */
-#define  USR1_RRDY       (1<<9)         /* Receiver ready interrupt/dma flag */
-#define  USR1_TIMEOUT    (1<<7)         /* Receive timeout interrupt status */
-#define  USR1_RXDS      (1<<6)  /* Receiver idle interrupt flag */
-#define  USR1_AIRINT    (1<<5)  /* Async IR wake interrupt flag */
-#define  USR1_AWAKE     (1<<4)  /* Aysnc wake interrupt flag */
-#define  USR2_ADET      (1<<15) /* Auto baud rate detect complete */
-#define  USR2_TXFE      (1<<14) /* Transmit buffer FIFO empty */
-#define  USR2_DTRF      (1<<13) /* DTR edge interrupt flag */
-#define  USR2_IDLE      (1<<12) /* Idle condition */
-#define  USR2_IRINT     (1<<8)  /* Serial infrared interrupt flag */
-#define  USR2_WAKE      (1<<7)  /* Wake */
-#define  USR2_RTSF      (1<<4)  /* RTS edge interrupt flag */
-#define  USR2_TXDC      (1<<3)  /* Transmitter complete */
-#define  USR2_BRCD      (1<<2)  /* Break condition */
-#define  USR2_ORE        (1<<1)         /* Overrun error */
-#define  USR2_RDR        (1<<0)         /* Recv data ready */
-#define  UTS_FRCPERR    (1<<13) /* Force parity error */
-#define  UTS_LOOP        (1<<12) /* Loop tx and rx */
-#define  UTS_TXEMPTY    (1<<6)  /* TxFIFO empty */
-#define  UTS_RXEMPTY    (1<<5)  /* RxFIFO empty */
-#define  UTS_TXFULL     (1<<4)  /* TxFIFO full */
-#define  UTS_RXFULL     (1<<3)  /* RxFIFO full */
-#define  UTS_SOFTRST    (1<<0)  /* Software reset */
-
-/* We've been assigned a range on the "Low-density serial ports" major */
-#define SERIAL_IMX_MAJOR        207
-#define MINOR_START            16
-#define DEV_NAME               "ttymxc"
-#define MAX_INTERNAL_IRQ       MXC_INTERNAL_IRQS
-
-/*
- * This determines how often we check the modem status signals
- * for any change.  They generally aren't connected to an IRQ
- * so we have to poll them.  We also check immediately before
- * filling the TX fifo incase CTS has been dropped.
- */
-#define MCTRL_TIMEOUT  (250*HZ/1000)
-
-#define DRIVER_NAME "IMX-uart"
-
-#define UART_NR 8
-
-struct imx_port {
-       struct uart_port        port;
-       struct timer_list       timer;
-       unsigned int            old_status;
-       int                     txirq,rxirq,rtsirq;
-       unsigned int            have_rtscts:1;
-       unsigned int            use_irda:1;
-       unsigned int            irda_inv_rx:1;
-       unsigned int            irda_inv_tx:1;
-       unsigned short          trcv_delay; /* transceiver delay */
-       struct clk              *clk;
-};
-
-#ifdef CONFIG_IRDA
-#define USE_IRDA(sport)        ((sport)->use_irda)
-#else
-#define USE_IRDA(sport)        (0)
-#endif
-
-/*
- * Handle any change of modem status signal since we were last called.
- */
-static void imx_mctrl_check(struct imx_port *sport)
-{
-       unsigned int status, changed;
-
-       status = sport->port.ops->get_mctrl(&sport->port);
-       changed = status ^ sport->old_status;
-
-       if (changed == 0)
-               return;
-
-       sport->old_status = status;
-
-       if (changed & TIOCM_RI)
-               sport->port.icount.rng++;
-       if (changed & TIOCM_DSR)
-               sport->port.icount.dsr++;
-       if (changed & TIOCM_CAR)
-               uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
-       if (changed & TIOCM_CTS)
-               uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
-
-       wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
-}
-
-/*
- * This is our per-port timeout handler, for checking the
- * modem status signals.
- */
-static void imx_timeout(unsigned long data)
-{
-       struct imx_port *sport = (struct imx_port *)data;
-       unsigned long flags;
-
-       if (sport->port.state) {
-               spin_lock_irqsave(&sport->port.lock, flags);
-               imx_mctrl_check(sport);
-               spin_unlock_irqrestore(&sport->port.lock, flags);
-
-               mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
-       }
-}
-
-/*
- * interrupts disabled on entry
- */
-static void imx_stop_tx(struct uart_port *port)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-       unsigned long temp;
-
-       if (USE_IRDA(sport)) {
-               /* half duplex - wait for end of transmission */
-               int n = 256;
-               while ((--n > 0) &&
-                     !(readl(sport->port.membase + USR2) & USR2_TXDC)) {
-                       udelay(5);
-                       barrier();
-               }
-               /*
-                * irda transceiver - wait a bit more to avoid
-                * cutoff, hardware dependent
-                */
-               udelay(sport->trcv_delay);
-
-               /*
-                * half duplex - reactivate receive mode,
-                * flush receive pipe echo crap
-                */
-               if (readl(sport->port.membase + USR2) & USR2_TXDC) {
-                       temp = readl(sport->port.membase + UCR1);
-                       temp &= ~(UCR1_TXMPTYEN | UCR1_TRDYEN);
-                       writel(temp, sport->port.membase + UCR1);
-
-                       temp = readl(sport->port.membase + UCR4);
-                       temp &= ~(UCR4_TCEN);
-                       writel(temp, sport->port.membase + UCR4);
-
-                       while (readl(sport->port.membase + URXD0) &
-                              URXD_CHARRDY)
-                               barrier();
-
-                       temp = readl(sport->port.membase + UCR1);
-                       temp |= UCR1_RRDYEN;
-                       writel(temp, sport->port.membase + UCR1);
-
-                       temp = readl(sport->port.membase + UCR4);
-                       temp |= UCR4_DREN;
-                       writel(temp, sport->port.membase + UCR4);
-               }
-               return;
-       }
-
-       temp = readl(sport->port.membase + UCR1);
-       writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1);
-}
-
-/*
- * interrupts disabled on entry
- */
-static void imx_stop_rx(struct uart_port *port)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-       unsigned long temp;
-
-       temp = readl(sport->port.membase + UCR2);
-       writel(temp &~ UCR2_RXEN, sport->port.membase + UCR2);
-}
-
-/*
- * Set the modem control timer to fire immediately.
- */
-static void imx_enable_ms(struct uart_port *port)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-
-       mod_timer(&sport->timer, jiffies);
-}
-
-static inline void imx_transmit_buffer(struct imx_port *sport)
-{
-       struct circ_buf *xmit = &sport->port.state->xmit;
-
-       while (!uart_circ_empty(xmit) &&
-                       !(readl(sport->port.membase + UTS) & UTS_TXFULL)) {
-               /* send xmit->buf[xmit->tail]
-                * out the port here */
-               writel(xmit->buf[xmit->tail], sport->port.membase + URTX0);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               sport->port.icount.tx++;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&sport->port);
-
-       if (uart_circ_empty(xmit))
-               imx_stop_tx(&sport->port);
-}
-
-/*
- * interrupts disabled on entry
- */
-static void imx_start_tx(struct uart_port *port)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-       unsigned long temp;
-
-       if (USE_IRDA(sport)) {
-               /* half duplex in IrDA mode; have to disable receive mode */
-               temp = readl(sport->port.membase + UCR4);
-               temp &= ~(UCR4_DREN);
-               writel(temp, sport->port.membase + UCR4);
-
-               temp = readl(sport->port.membase + UCR1);
-               temp &= ~(UCR1_RRDYEN);
-               writel(temp, sport->port.membase + UCR1);
-       }
-
-       temp = readl(sport->port.membase + UCR1);
-       writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
-
-       if (USE_IRDA(sport)) {
-               temp = readl(sport->port.membase + UCR1);
-               temp |= UCR1_TRDYEN;
-               writel(temp, sport->port.membase + UCR1);
-
-               temp = readl(sport->port.membase + UCR4);
-               temp |= UCR4_TCEN;
-               writel(temp, sport->port.membase + UCR4);
-       }
-
-       if (readl(sport->port.membase + UTS) & UTS_TXEMPTY)
-               imx_transmit_buffer(sport);
-}
-
-static irqreturn_t imx_rtsint(int irq, void *dev_id)
-{
-       struct imx_port *sport = dev_id;
-       unsigned int val = readl(sport->port.membase + USR1) & USR1_RTSS;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sport->port.lock, flags);
-
-       writel(USR1_RTSD, sport->port.membase + USR1);
-       uart_handle_cts_change(&sport->port, !!val);
-       wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
-
-       spin_unlock_irqrestore(&sport->port.lock, flags);
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t imx_txint(int irq, void *dev_id)
-{
-       struct imx_port *sport = dev_id;
-       struct circ_buf *xmit = &sport->port.state->xmit;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sport->port.lock,flags);
-       if (sport->port.x_char)
-       {
-               /* Send next char */
-               writel(sport->port.x_char, sport->port.membase + URTX0);
-               goto out;
-       }
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
-               imx_stop_tx(&sport->port);
-               goto out;
-       }
-
-       imx_transmit_buffer(sport);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&sport->port);
-
-out:
-       spin_unlock_irqrestore(&sport->port.lock,flags);
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t imx_rxint(int irq, void *dev_id)
-{
-       struct imx_port *sport = dev_id;
-       unsigned int rx,flg,ignored = 0;
-       struct tty_struct *tty = sport->port.state->port.tty;
-       unsigned long flags, temp;
-
-       spin_lock_irqsave(&sport->port.lock,flags);
-
-       while (readl(sport->port.membase + USR2) & USR2_RDR) {
-               flg = TTY_NORMAL;
-               sport->port.icount.rx++;
-
-               rx = readl(sport->port.membase + URXD0);
-
-               temp = readl(sport->port.membase + USR2);
-               if (temp & USR2_BRCD) {
-                       writel(USR2_BRCD, sport->port.membase + USR2);
-                       if (uart_handle_break(&sport->port))
-                               continue;
-               }
-
-               if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
-                       continue;
-
-               if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) {
-                       if (rx & URXD_PRERR)
-                               sport->port.icount.parity++;
-                       else if (rx & URXD_FRMERR)
-                               sport->port.icount.frame++;
-                       if (rx & URXD_OVRRUN)
-                               sport->port.icount.overrun++;
-
-                       if (rx & sport->port.ignore_status_mask) {
-                               if (++ignored > 100)
-                                       goto out;
-                               continue;
-                       }
-
-                       rx &= sport->port.read_status_mask;
-
-                       if (rx & URXD_PRERR)
-                               flg = TTY_PARITY;
-                       else if (rx & URXD_FRMERR)
-                               flg = TTY_FRAME;
-                       if (rx & URXD_OVRRUN)
-                               flg = TTY_OVERRUN;
-
-#ifdef SUPPORT_SYSRQ
-                       sport->port.sysrq = 0;
-#endif
-               }
-
-               tty_insert_flip_char(tty, rx, flg);
-       }
-
-out:
-       spin_unlock_irqrestore(&sport->port.lock,flags);
-       tty_flip_buffer_push(tty);
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t imx_int(int irq, void *dev_id)
-{
-       struct imx_port *sport = dev_id;
-       unsigned int sts;
-
-       sts = readl(sport->port.membase + USR1);
-
-       if (sts & USR1_RRDY)
-               imx_rxint(irq, dev_id);
-
-       if (sts & USR1_TRDY &&
-                       readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN)
-               imx_txint(irq, dev_id);
-
-       if (sts & USR1_RTSD)
-               imx_rtsint(irq, dev_id);
-
-       return IRQ_HANDLED;
-}
-
-/*
- * Return TIOCSER_TEMT when transmitter is not busy.
- */
-static unsigned int imx_tx_empty(struct uart_port *port)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-
-       return (readl(sport->port.membase + USR2) & USR2_TXDC) ?  TIOCSER_TEMT : 0;
-}
-
-/*
- * We have a modem side uart, so the meanings of RTS and CTS are inverted.
- */
-static unsigned int imx_get_mctrl(struct uart_port *port)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-       unsigned int tmp = TIOCM_DSR | TIOCM_CAR;
-
-       if (readl(sport->port.membase + USR1) & USR1_RTSS)
-               tmp |= TIOCM_CTS;
-
-       if (readl(sport->port.membase + UCR2) & UCR2_CTS)
-               tmp |= TIOCM_RTS;
-
-       return tmp;
-}
-
-static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-       unsigned long temp;
-
-       temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS;
-
-       if (mctrl & TIOCM_RTS)
-               temp |= UCR2_CTS;
-
-       writel(temp, sport->port.membase + UCR2);
-}
-
-/*
- * Interrupts always disabled.
- */
-static void imx_break_ctl(struct uart_port *port, int break_state)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-       unsigned long flags, temp;
-
-       spin_lock_irqsave(&sport->port.lock, flags);
-
-       temp = readl(sport->port.membase + UCR1) & ~UCR1_SNDBRK;
-
-       if ( break_state != 0 )
-               temp |= UCR1_SNDBRK;
-
-       writel(temp, sport->port.membase + UCR1);
-
-       spin_unlock_irqrestore(&sport->port.lock, flags);
-}
-
-#define TXTL 2 /* reset default */
-#define RXTL 1 /* reset default */
-
-static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
-{
-       unsigned int val;
-       unsigned int ufcr_rfdiv;
-
-       /* set receiver / transmitter trigger level.
-        * RFDIV is set such way to satisfy requested uartclk value
-        */
-       val = TXTL << 10 | RXTL;
-       ufcr_rfdiv = (clk_get_rate(sport->clk) + sport->port.uartclk / 2)
-                       / sport->port.uartclk;
-
-       if(!ufcr_rfdiv)
-               ufcr_rfdiv = 1;
-
-       val |= UFCR_RFDIV_REG(ufcr_rfdiv);
-
-       writel(val, sport->port.membase + UFCR);
-
-       return 0;
-}
-
-/* half the RX buffer size */
-#define CTSTL 16
-
-static int imx_startup(struct uart_port *port)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-       int retval;
-       unsigned long flags, temp;
-
-       imx_setup_ufcr(sport, 0);
-
-       /* disable the DREN bit (Data Ready interrupt enable) before
-        * requesting IRQs
-        */
-       temp = readl(sport->port.membase + UCR4);
-
-       if (USE_IRDA(sport))
-               temp |= UCR4_IRSC;
-
-       /* set the trigger level for CTS */
-       temp &= ~(UCR4_CTSTL_MASK<<  UCR4_CTSTL_SHF);
-       temp |= CTSTL<<  UCR4_CTSTL_SHF;
-
-       writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
-
-       if (USE_IRDA(sport)) {
-               /* reset fifo's and state machines */
-               int i = 100;
-               temp = readl(sport->port.membase + UCR2);
-               temp &= ~UCR2_SRST;
-               writel(temp, sport->port.membase + UCR2);
-               while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) &&
-                   (--i > 0)) {
-                       udelay(1);
-               }
-       }
-
-       /*
-        * Allocate the IRQ(s) i.MX1 has three interrupts whereas later
-        * chips only have one interrupt.
-        */
-       if (sport->txirq > 0) {
-               retval = request_irq(sport->rxirq, imx_rxint, 0,
-                               DRIVER_NAME, sport);
-               if (retval)
-                       goto error_out1;
-
-               retval = request_irq(sport->txirq, imx_txint, 0,
-                               DRIVER_NAME, sport);
-               if (retval)
-                       goto error_out2;
-
-               /* do not use RTS IRQ on IrDA */
-               if (!USE_IRDA(sport)) {
-                       retval = request_irq(sport->rtsirq, imx_rtsint,
-                                    (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 :
-                                      IRQF_TRIGGER_FALLING |
-                                      IRQF_TRIGGER_RISING,
-                                       DRIVER_NAME, sport);
-                       if (retval)
-                               goto error_out3;
-               }
-       } else {
-               retval = request_irq(sport->port.irq, imx_int, 0,
-                               DRIVER_NAME, sport);
-               if (retval) {
-                       free_irq(sport->port.irq, sport);
-                       goto error_out1;
-               }
-       }
-
-       /*
-        * Finally, clear and enable interrupts
-        */
-       writel(USR1_RTSD, sport->port.membase + USR1);
-
-       temp = readl(sport->port.membase + UCR1);
-       temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
-
-       if (USE_IRDA(sport)) {
-               temp |= UCR1_IREN;
-               temp &= ~(UCR1_RTSDEN);
-       }
-
-       writel(temp, sport->port.membase + UCR1);
-
-       temp = readl(sport->port.membase + UCR2);
-       temp |= (UCR2_RXEN | UCR2_TXEN);
-       writel(temp, sport->port.membase + UCR2);
-
-       if (USE_IRDA(sport)) {
-               /* clear RX-FIFO */
-               int i = 64;
-               while ((--i > 0) &&
-                       (readl(sport->port.membase + URXD0) & URXD_CHARRDY)) {
-                       barrier();
-               }
-       }
-
-       if (!cpu_is_mx1()) {
-               temp = readl(sport->port.membase + UCR3);
-               temp |= MX2_UCR3_RXDMUXSEL;
-               writel(temp, sport->port.membase + UCR3);
-       }
-
-       if (USE_IRDA(sport)) {
-               temp = readl(sport->port.membase + UCR4);
-               if (sport->irda_inv_rx)
-                       temp |= UCR4_INVR;
-               else
-                       temp &= ~(UCR4_INVR);
-               writel(temp | UCR4_DREN, sport->port.membase + UCR4);
-
-               temp = readl(sport->port.membase + UCR3);
-               if (sport->irda_inv_tx)
-                       temp |= UCR3_INVT;
-               else
-                       temp &= ~(UCR3_INVT);
-               writel(temp, sport->port.membase + UCR3);
-       }
-
-       /*
-        * Enable modem status interrupts
-        */
-       spin_lock_irqsave(&sport->port.lock,flags);
-       imx_enable_ms(&sport->port);
-       spin_unlock_irqrestore(&sport->port.lock,flags);
-
-       if (USE_IRDA(sport)) {
-               struct imxuart_platform_data *pdata;
-               pdata = sport->port.dev->platform_data;
-               sport->irda_inv_rx = pdata->irda_inv_rx;
-               sport->irda_inv_tx = pdata->irda_inv_tx;
-               sport->trcv_delay = pdata->transceiver_delay;
-               if (pdata->irda_enable)
-                       pdata->irda_enable(1);
-       }
-
-       return 0;
-
-error_out3:
-       if (sport->txirq)
-               free_irq(sport->txirq, sport);
-error_out2:
-       if (sport->rxirq)
-               free_irq(sport->rxirq, sport);
-error_out1:
-       return retval;
-}
-
-static void imx_shutdown(struct uart_port *port)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-       unsigned long temp;
-
-       temp = readl(sport->port.membase + UCR2);
-       temp &= ~(UCR2_TXEN);
-       writel(temp, sport->port.membase + UCR2);
-
-       if (USE_IRDA(sport)) {
-               struct imxuart_platform_data *pdata;
-               pdata = sport->port.dev->platform_data;
-               if (pdata->irda_enable)
-                       pdata->irda_enable(0);
-       }
-
-       /*
-        * Stop our timer.
-        */
-       del_timer_sync(&sport->timer);
-
-       /*
-        * Free the interrupts
-        */
-       if (sport->txirq > 0) {
-               if (!USE_IRDA(sport))
-                       free_irq(sport->rtsirq, sport);
-               free_irq(sport->txirq, sport);
-               free_irq(sport->rxirq, sport);
-       } else
-               free_irq(sport->port.irq, sport);
-
-       /*
-        * Disable all interrupts, port and break condition.
-        */
-
-       temp = readl(sport->port.membase + UCR1);
-       temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);
-       if (USE_IRDA(sport))
-               temp &= ~(UCR1_IREN);
-
-       writel(temp, sport->port.membase + UCR1);
-}
-
-static void
-imx_set_termios(struct uart_port *port, struct ktermios *termios,
-                  struct ktermios *old)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-       unsigned long flags;
-       unsigned int ucr2, old_ucr1, old_txrxen, baud, quot;
-       unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
-       unsigned int div, ufcr;
-       unsigned long num, denom;
-       uint64_t tdiv64;
-
-       /*
-        * If we don't support modem control lines, don't allow
-        * these to be set.
-        */
-       if (0) {
-               termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR);
-               termios->c_cflag |= CLOCAL;
-       }
-
-       /*
-        * We only support CS7 and CS8.
-        */
-       while ((termios->c_cflag & CSIZE) != CS7 &&
-              (termios->c_cflag & CSIZE) != CS8) {
-               termios->c_cflag &= ~CSIZE;
-               termios->c_cflag |= old_csize;
-               old_csize = CS8;
-       }
-
-       if ((termios->c_cflag & CSIZE) == CS8)
-               ucr2 = UCR2_WS | UCR2_SRST | UCR2_IRTS;
-       else
-               ucr2 = UCR2_SRST | UCR2_IRTS;
-
-       if (termios->c_cflag & CRTSCTS) {
-               if( sport->have_rtscts ) {
-                       ucr2 &= ~UCR2_IRTS;
-                       ucr2 |= UCR2_CTSC;
-               } else {
-                       termios->c_cflag &= ~CRTSCTS;
-               }
-       }
-
-       if (termios->c_cflag & CSTOPB)
-               ucr2 |= UCR2_STPB;
-       if (termios->c_cflag & PARENB) {
-               ucr2 |= UCR2_PREN;
-               if (termios->c_cflag & PARODD)
-                       ucr2 |= UCR2_PROE;
-       }
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16);
-       quot = uart_get_divisor(port, baud);
-
-       spin_lock_irqsave(&sport->port.lock, flags);
-
-       sport->port.read_status_mask = 0;
-       if (termios->c_iflag & INPCK)
-               sport->port.read_status_mask |= (URXD_FRMERR | URXD_PRERR);
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               sport->port.read_status_mask |= URXD_BRK;
-
-       /*
-        * Characters to ignore
-        */
-       sport->port.ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               sport->port.ignore_status_mask |= URXD_PRERR;
-       if (termios->c_iflag & IGNBRK) {
-               sport->port.ignore_status_mask |= URXD_BRK;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       sport->port.ignore_status_mask |= URXD_OVRRUN;
-       }
-
-       del_timer_sync(&sport->timer);
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       /*
-        * disable interrupts and drain transmitter
-        */
-       old_ucr1 = readl(sport->port.membase + UCR1);
-       writel(old_ucr1 & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN),
-                       sport->port.membase + UCR1);
-
-       while ( !(readl(sport->port.membase + USR2) & USR2_TXDC))
-               barrier();
-
-       /* then, disable everything */
-       old_txrxen = readl(sport->port.membase + UCR2);
-       writel(old_txrxen & ~( UCR2_TXEN | UCR2_RXEN),
-                       sport->port.membase + UCR2);
-       old_txrxen &= (UCR2_TXEN | UCR2_RXEN);
-
-       if (USE_IRDA(sport)) {
-               /*
-                * use maximum available submodule frequency to
-                * avoid missing short pulses due to low sampling rate
-                */
-               div = 1;
-       } else {
-               div = sport->port.uartclk / (baud * 16);
-               if (div > 7)
-                       div = 7;
-               if (!div)
-                       div = 1;
-       }
-
-       rational_best_approximation(16 * div * baud, sport->port.uartclk,
-               1 << 16, 1 << 16, &num, &denom);
-
-       tdiv64 = sport->port.uartclk;
-       tdiv64 *= num;
-       do_div(tdiv64, denom * 16 * div);
-       tty_termios_encode_baud_rate(termios,
-                               (speed_t)tdiv64, (speed_t)tdiv64);
-
-       num -= 1;
-       denom -= 1;
-
-       ufcr = readl(sport->port.membase + UFCR);
-       ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div);
-       writel(ufcr, sport->port.membase + UFCR);
-
-       writel(num, sport->port.membase + UBIR);
-       writel(denom, sport->port.membase + UBMR);
-
-       if (!cpu_is_mx1())
-               writel(sport->port.uartclk / div / 1000,
-                               sport->port.membase + MX2_ONEMS);
-
-       writel(old_ucr1, sport->port.membase + UCR1);
-
-       /* set the parity, stop bits and data size */
-       writel(ucr2 | old_txrxen, sport->port.membase + UCR2);
-
-       if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
-               imx_enable_ms(&sport->port);
-
-       spin_unlock_irqrestore(&sport->port.lock, flags);
-}
-
-static const char *imx_type(struct uart_port *port)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-
-       return sport->port.type == PORT_IMX ? "IMX" : NULL;
-}
-
-/*
- * Release the memory region(s) being used by 'port'.
- */
-static void imx_release_port(struct uart_port *port)
-{
-       struct platform_device *pdev = to_platform_device(port->dev);
-       struct resource *mmres;
-
-       mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(mmres->start, mmres->end - mmres->start + 1);
-}
-
-/*
- * Request the memory region(s) being used by 'port'.
- */
-static int imx_request_port(struct uart_port *port)
-{
-       struct platform_device *pdev = to_platform_device(port->dev);
-       struct resource *mmres;
-       void *ret;
-
-       mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!mmres)
-               return -ENODEV;
-
-       ret = request_mem_region(mmres->start, mmres->end - mmres->start + 1,
-                       "imx-uart");
-
-       return  ret ? 0 : -EBUSY;
-}
-
-/*
- * Configure/autoconfigure the port.
- */
-static void imx_config_port(struct uart_port *port, int flags)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-
-       if (flags & UART_CONFIG_TYPE &&
-           imx_request_port(&sport->port) == 0)
-               sport->port.type = PORT_IMX;
-}
-
-/*
- * Verify the new serial_struct (for TIOCSSERIAL).
- * The only change we allow are to the flags and type, and
- * even then only between PORT_IMX and PORT_UNKNOWN
- */
-static int
-imx_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-       int ret = 0;
-
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_IMX)
-               ret = -EINVAL;
-       if (sport->port.irq != ser->irq)
-               ret = -EINVAL;
-       if (ser->io_type != UPIO_MEM)
-               ret = -EINVAL;
-       if (sport->port.uartclk / 16 != ser->baud_base)
-               ret = -EINVAL;
-       if ((void *)sport->port.mapbase != ser->iomem_base)
-               ret = -EINVAL;
-       if (sport->port.iobase != ser->port)
-               ret = -EINVAL;
-       if (ser->hub6 != 0)
-               ret = -EINVAL;
-       return ret;
-}
-
-static struct uart_ops imx_pops = {
-       .tx_empty       = imx_tx_empty,
-       .set_mctrl      = imx_set_mctrl,
-       .get_mctrl      = imx_get_mctrl,
-       .stop_tx        = imx_stop_tx,
-       .start_tx       = imx_start_tx,
-       .stop_rx        = imx_stop_rx,
-       .enable_ms      = imx_enable_ms,
-       .break_ctl      = imx_break_ctl,
-       .startup        = imx_startup,
-       .shutdown       = imx_shutdown,
-       .set_termios    = imx_set_termios,
-       .type           = imx_type,
-       .release_port   = imx_release_port,
-       .request_port   = imx_request_port,
-       .config_port    = imx_config_port,
-       .verify_port    = imx_verify_port,
-};
-
-static struct imx_port *imx_ports[UART_NR];
-
-#ifdef CONFIG_SERIAL_IMX_CONSOLE
-static void imx_console_putchar(struct uart_port *port, int ch)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-
-       while (readl(sport->port.membase + UTS) & UTS_TXFULL)
-               barrier();
-
-       writel(ch, sport->port.membase + URTX0);
-}
-
-/*
- * Interrupts are disabled on entering
- */
-static void
-imx_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct imx_port *sport = imx_ports[co->index];
-       unsigned int old_ucr1, old_ucr2, ucr1;
-
-       /*
-        *      First, save UCR1/2 and then disable interrupts
-        */
-       ucr1 = old_ucr1 = readl(sport->port.membase + UCR1);
-       old_ucr2 = readl(sport->port.membase + UCR2);
-
-       if (cpu_is_mx1())
-               ucr1 |= MX1_UCR1_UARTCLKEN;
-       ucr1 |= UCR1_UARTEN;
-       ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN);
-
-       writel(ucr1, sport->port.membase + UCR1);
-
-       writel(old_ucr2 | UCR2_TXEN, sport->port.membase + UCR2);
-
-       uart_console_write(&sport->port, s, count, imx_console_putchar);
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore UCR1/2
-        */
-       while (!(readl(sport->port.membase + USR2) & USR2_TXDC));
-
-       writel(old_ucr1, sport->port.membase + UCR1);
-       writel(old_ucr2, sport->port.membase + UCR2);
-}
-
-/*
- * If the port was already initialised (eg, by a boot loader),
- * try to determine the current setup.
- */
-static void __init
-imx_console_get_options(struct imx_port *sport, int *baud,
-                          int *parity, int *bits)
-{
-
-       if (readl(sport->port.membase + UCR1) & UCR1_UARTEN) {
-               /* ok, the port was enabled */
-               unsigned int ucr2, ubir,ubmr, uartclk;
-               unsigned int baud_raw;
-               unsigned int ucfr_rfdiv;
-
-               ucr2 = readl(sport->port.membase + UCR2);
-
-               *parity = 'n';
-               if (ucr2 & UCR2_PREN) {
-                       if (ucr2 & UCR2_PROE)
-                               *parity = 'o';
-                       else
-                               *parity = 'e';
-               }
-
-               if (ucr2 & UCR2_WS)
-                       *bits = 8;
-               else
-                       *bits = 7;
-
-               ubir = readl(sport->port.membase + UBIR) & 0xffff;
-               ubmr = readl(sport->port.membase + UBMR) & 0xffff;
-
-               ucfr_rfdiv = (readl(sport->port.membase + UFCR) & UFCR_RFDIV) >> 7;
-               if (ucfr_rfdiv == 6)
-                       ucfr_rfdiv = 7;
-               else
-                       ucfr_rfdiv = 6 - ucfr_rfdiv;
-
-               uartclk = clk_get_rate(sport->clk);
-               uartclk /= ucfr_rfdiv;
-
-               {       /*
-                        * The next code provides exact computation of
-                        *   baud_raw = round(((uartclk/16) * (ubir + 1)) / (ubmr + 1))
-                        * without need of float support or long long division,
-                        * which would be required to prevent 32bit arithmetic overflow
-                        */
-                       unsigned int mul = ubir + 1;
-                       unsigned int div = 16 * (ubmr + 1);
-                       unsigned int rem = uartclk % div;
-
-                       baud_raw = (uartclk / div) * mul;
-                       baud_raw += (rem * mul + div / 2) / div;
-                       *baud = (baud_raw + 50) / 100 * 100;
-               }
-
-               if(*baud != baud_raw)
-                       printk(KERN_INFO "Serial: Console IMX rounded baud rate from %d to %d\n",
-                               baud_raw, *baud);
-       }
-}
-
-static int __init
-imx_console_setup(struct console *co, char *options)
-{
-       struct imx_port *sport;
-       int baud = 9600;
-       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.
-        */
-       if (co->index == -1 || co->index >= ARRAY_SIZE(imx_ports))
-               co->index = 0;
-       sport = imx_ports[co->index];
-       if(sport == NULL)
-               return -ENODEV;
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               imx_console_get_options(sport, &baud, &parity, &bits);
-
-       imx_setup_ufcr(sport, 0);
-
-       return uart_set_options(&sport->port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver imx_reg;
-static struct console imx_console = {
-       .name           = DEV_NAME,
-       .write          = imx_console_write,
-       .device         = uart_console_device,
-       .setup          = imx_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &imx_reg,
-};
-
-#define IMX_CONSOLE    &imx_console
-#else
-#define IMX_CONSOLE    NULL
-#endif
-
-static struct uart_driver imx_reg = {
-       .owner          = THIS_MODULE,
-       .driver_name    = DRIVER_NAME,
-       .dev_name       = DEV_NAME,
-       .major          = SERIAL_IMX_MAJOR,
-       .minor          = MINOR_START,
-       .nr             = ARRAY_SIZE(imx_ports),
-       .cons           = IMX_CONSOLE,
-};
-
-static int serial_imx_suspend(struct platform_device *dev, pm_message_t state)
-{
-       struct imx_port *sport = platform_get_drvdata(dev);
-
-       if (sport)
-               uart_suspend_port(&imx_reg, &sport->port);
-
-       return 0;
-}
-
-static int serial_imx_resume(struct platform_device *dev)
-{
-       struct imx_port *sport = platform_get_drvdata(dev);
-
-       if (sport)
-               uart_resume_port(&imx_reg, &sport->port);
-
-       return 0;
-}
-
-static int serial_imx_probe(struct platform_device *pdev)
-{
-       struct imx_port *sport;
-       struct imxuart_platform_data *pdata;
-       void __iomem *base;
-       int ret = 0;
-       struct resource *res;
-
-       sport = kzalloc(sizeof(*sport), GFP_KERNEL);
-       if (!sport)
-               return -ENOMEM;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               ret = -ENODEV;
-               goto free;
-       }
-
-       base = ioremap(res->start, PAGE_SIZE);
-       if (!base) {
-               ret = -ENOMEM;
-               goto free;
-       }
-
-       sport->port.dev = &pdev->dev;
-       sport->port.mapbase = res->start;
-       sport->port.membase = base;
-       sport->port.type = PORT_IMX,
-       sport->port.iotype = UPIO_MEM;
-       sport->port.irq = platform_get_irq(pdev, 0);
-       sport->rxirq = platform_get_irq(pdev, 0);
-       sport->txirq = platform_get_irq(pdev, 1);
-       sport->rtsirq = platform_get_irq(pdev, 2);
-       sport->port.fifosize = 32;
-       sport->port.ops = &imx_pops;
-       sport->port.flags = UPF_BOOT_AUTOCONF;
-       sport->port.line = pdev->id;
-       init_timer(&sport->timer);
-       sport->timer.function = imx_timeout;
-       sport->timer.data     = (unsigned long)sport;
-
-       sport->clk = clk_get(&pdev->dev, "uart");
-       if (IS_ERR(sport->clk)) {
-               ret = PTR_ERR(sport->clk);
-               goto unmap;
-       }
-       clk_enable(sport->clk);
-
-       sport->port.uartclk = clk_get_rate(sport->clk);
-
-       imx_ports[pdev->id] = sport;
-
-       pdata = pdev->dev.platform_data;
-       if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS))
-               sport->have_rtscts = 1;
-
-#ifdef CONFIG_IRDA
-       if (pdata && (pdata->flags & IMXUART_IRDA))
-               sport->use_irda = 1;
-#endif
-
-       if (pdata && pdata->init) {
-               ret = pdata->init(pdev);
-               if (ret)
-                       goto clkput;
-       }
-
-       ret = uart_add_one_port(&imx_reg, &sport->port);
-       if (ret)
-               goto deinit;
-       platform_set_drvdata(pdev, &sport->port);
-
-       return 0;
-deinit:
-       if (pdata && pdata->exit)
-               pdata->exit(pdev);
-clkput:
-       clk_put(sport->clk);
-       clk_disable(sport->clk);
-unmap:
-       iounmap(sport->port.membase);
-free:
-       kfree(sport);
-
-       return ret;
-}
-
-static int serial_imx_remove(struct platform_device *pdev)
-{
-       struct imxuart_platform_data *pdata;
-       struct imx_port *sport = platform_get_drvdata(pdev);
-
-       pdata = pdev->dev.platform_data;
-
-       platform_set_drvdata(pdev, NULL);
-
-       if (sport) {
-               uart_remove_one_port(&imx_reg, &sport->port);
-               clk_put(sport->clk);
-       }
-
-       clk_disable(sport->clk);
-
-       if (pdata && pdata->exit)
-               pdata->exit(pdev);
-
-       iounmap(sport->port.membase);
-       kfree(sport);
-
-       return 0;
-}
-
-static struct platform_driver serial_imx_driver = {
-       .probe          = serial_imx_probe,
-       .remove         = serial_imx_remove,
-
-       .suspend        = serial_imx_suspend,
-       .resume         = serial_imx_resume,
-       .driver         = {
-               .name   = "imx-uart",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init imx_serial_init(void)
-{
-       int ret;
-
-       printk(KERN_INFO "Serial: IMX driver\n");
-
-       ret = uart_register_driver(&imx_reg);
-       if (ret)
-               return ret;
-
-       ret = platform_driver_register(&serial_imx_driver);
-       if (ret != 0)
-               uart_unregister_driver(&imx_reg);
-
-       return 0;
-}
-
-static void __exit imx_serial_exit(void)
-{
-       platform_driver_unregister(&serial_imx_driver);
-       uart_unregister_driver(&imx_reg);
-}
-
-module_init(imx_serial_init);
-module_exit(imx_serial_exit);
-
-MODULE_AUTHOR("Sascha Hauer");
-MODULE_DESCRIPTION("IMX generic serial port driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-uart");
diff --git a/drivers/serial/ioc3_serial.c b/drivers/serial/ioc3_serial.c
deleted file mode 100644 (file)
index ee43efc..0000000
+++ /dev/null
@@ -1,2199 +0,0 @@
-/*
- * 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.
- *
- * Copyright (C) 2005 Silicon Graphics, Inc.  All Rights Reserved.
- */
-
-/*
- * This file contains a module version of the ioc3 serial driver. This
- * includes all the support functions needed (support functions, etc.)
- * and the serial driver itself.
- */
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/serial.h>
-#include <linux/circ_buf.h>
-#include <linux/serial_reg.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/serial_core.h>
-#include <linux/ioc3.h>
-#include <linux/slab.h>
-
-/*
- * Interesting things about the ioc3
- */
-
-#define LOGICAL_PORTS          2       /* rs232(0) and rs422(1) */
-#define PORTS_PER_CARD         2
-#define LOGICAL_PORTS_PER_CARD (PORTS_PER_CARD * LOGICAL_PORTS)
-#define MAX_CARDS              8
-#define MAX_LOGICAL_PORTS      (LOGICAL_PORTS_PER_CARD * MAX_CARDS)
-
-/* determine given the sio_ir what port it applies to */
-#define GET_PORT_FROM_SIO_IR(_x)       (_x & SIO_IR_SA) ? 0 : 1
-
-
-/*
- * we have 2 logical ports (rs232, rs422) for each physical port
- * evens are rs232, odds are rs422
- */
-#define GET_PHYSICAL_PORT(_x)  ((_x) >> 1)
-#define GET_LOGICAL_PORT(_x)   ((_x) & 1)
-#define IS_PHYSICAL_PORT(_x)   !((_x) & 1)
-#define IS_RS232(_x)           !((_x) & 1)
-
-static unsigned int Num_of_ioc3_cards;
-static unsigned int Submodule_slot;
-
-/* defining this will get you LOTS of great debug info */
-//#define DEBUG_INTERRUPTS
-#define DPRINT_CONFIG(_x...)   ;
-//#define DPRINT_CONFIG(_x...)  printk _x
-#define NOT_PROGRESS() ;
-//#define NOT_PROGRESS()       printk("%s : fails %d\n", __func__, __LINE__)
-
-/* number of characters we want to transmit to the lower level at a time */
-#define MAX_CHARS              256
-#define FIFO_SIZE              (MAX_CHARS-1)   /* it's a uchar */
-
-/* Device name we're using */
-#define DEVICE_NAME            "ttySIOC"
-#define DEVICE_MAJOR           204
-#define DEVICE_MINOR           116
-
-/* flags for next_char_state */
-#define NCS_BREAK              0x1
-#define NCS_PARITY             0x2
-#define NCS_FRAMING            0x4
-#define NCS_OVERRUN            0x8
-
-/* cause we need SOME parameters ... */
-#define MIN_BAUD_SUPPORTED     1200
-#define MAX_BAUD_SUPPORTED     115200
-
-/* protocol types supported */
-#define PROTO_RS232            0
-#define PROTO_RS422            1
-
-/* Notification types */
-#define N_DATA_READY           0x01
-#define N_OUTPUT_LOWAT         0x02
-#define N_BREAK                        0x04
-#define N_PARITY_ERROR         0x08
-#define N_FRAMING_ERROR                0x10
-#define N_OVERRUN_ERROR                0x20
-#define N_DDCD                 0x40
-#define N_DCTS                 0x80
-
-#define N_ALL_INPUT            (N_DATA_READY | N_BREAK                    \
-                                       | N_PARITY_ERROR | N_FRAMING_ERROR \
-                                       | N_OVERRUN_ERROR | N_DDCD | N_DCTS)
-
-#define N_ALL_OUTPUT           N_OUTPUT_LOWAT
-
-#define N_ALL_ERRORS           (N_PARITY_ERROR | N_FRAMING_ERROR \
-                                               | N_OVERRUN_ERROR)
-
-#define N_ALL                  (N_DATA_READY | N_OUTPUT_LOWAT | N_BREAK    \
-                                       | N_PARITY_ERROR | N_FRAMING_ERROR  \
-                                       | N_OVERRUN_ERROR | N_DDCD | N_DCTS)
-
-#define SER_CLK_SPEED(prediv)  ((22000000 << 1) / prediv)
-#define SER_DIVISOR(x, clk)    (((clk) + (x) * 8) / ((x) * 16))
-#define DIVISOR_TO_BAUD(div, clk) ((clk) / 16 / (div))
-
-/* Some masks */
-#define LCR_MASK_BITS_CHAR     (UART_LCR_WLEN5 | UART_LCR_WLEN6 \
-                                       | UART_LCR_WLEN7 | UART_LCR_WLEN8)
-#define LCR_MASK_STOP_BITS     (UART_LCR_STOP)
-
-#define PENDING(_a, _p)                (readl(&(_p)->vma->sio_ir) & (_a)->ic_enable)
-
-#define RING_BUF_SIZE          4096
-#define BUF_SIZE_BIT           SBBR_L_SIZE
-#define PROD_CONS_MASK         PROD_CONS_PTR_4K
-
-#define TOTAL_RING_BUF_SIZE    (RING_BUF_SIZE * 4)
-
-/* driver specific - one per card */
-struct ioc3_card {
-       struct {
-               /* uart ports are allocated here */
-               struct uart_port icp_uart_port[LOGICAL_PORTS];
-               /* the ioc3_port used for this port */
-               struct ioc3_port *icp_port;
-       } ic_port[PORTS_PER_CARD];
-       /* currently enabled interrupts */
-       uint32_t ic_enable;
-};
-
-/* Local port info for each IOC3 serial port */
-struct ioc3_port {
-       /* handy reference material */
-       struct uart_port *ip_port;
-       struct ioc3_card *ip_card;
-       struct ioc3_driver_data *ip_idd;
-       struct ioc3_submodule *ip_is;
-
-       /* pci mem addresses for this port */
-       struct ioc3_serialregs __iomem *ip_serial_regs;
-       struct ioc3_uartregs __iomem *ip_uart_regs;
-
-       /* Ring buffer page for this port */
-       dma_addr_t ip_dma_ringbuf;
-       /* vaddr of ring buffer */
-       struct ring_buffer *ip_cpu_ringbuf;
-
-       /* Rings for this port */
-       struct ring *ip_inring;
-       struct ring *ip_outring;
-
-       /* Hook to port specific values */
-       struct port_hooks *ip_hooks;
-
-       spinlock_t ip_lock;
-
-       /* Various rx/tx parameters */
-       int ip_baud;
-       int ip_tx_lowat;
-       int ip_rx_timeout;
-
-       /* Copy of notification bits */
-       int ip_notify;
-
-       /* Shadow copies of various registers so we don't need to PIO
-        * read them constantly
-        */
-       uint32_t ip_sscr;
-       uint32_t ip_tx_prod;
-       uint32_t ip_rx_cons;
-       unsigned char ip_flags;
-};
-
-/* tx low water mark.  We need to notify the driver whenever tx is getting
- * close to empty so it can refill the tx buffer and keep things going.
- * Let's assume that if we interrupt 1 ms before the tx goes idle, we'll
- * have no trouble getting in more chars in time (I certainly hope so).
- */
-#define TX_LOWAT_LATENCY      1000
-#define TX_LOWAT_HZ          (1000000 / TX_LOWAT_LATENCY)
-#define TX_LOWAT_CHARS(baud) (baud / 10 / TX_LOWAT_HZ)
-
-/* Flags per port */
-#define INPUT_HIGH             0x01
-       /* used to signify that we have turned off the rx_high
-        * temporarily - we need to drain the fifo and don't
-        * want to get blasted with interrupts.
-        */
-#define DCD_ON                 0x02
-       /* DCD state is on */
-#define LOWAT_WRITTEN          0x04
-#define READ_ABORTED           0x08
-       /* the read was aborted - used to avaoid infinate looping
-        * in the interrupt handler
-        */
-#define INPUT_ENABLE           0x10
-
-/* Since each port has different register offsets and bitmasks
- * for everything, we'll store those that we need in tables so we
- * don't have to be constantly checking the port we are dealing with.
- */
-struct port_hooks {
-       uint32_t intr_delta_dcd;
-       uint32_t intr_delta_cts;
-       uint32_t intr_tx_mt;
-       uint32_t intr_rx_timer;
-       uint32_t intr_rx_high;
-       uint32_t intr_tx_explicit;
-       uint32_t intr_clear;
-       uint32_t intr_all;
-       char rs422_select_pin;
-};
-
-static struct port_hooks hooks_array[PORTS_PER_CARD] = {
-       /* values for port A */
-       {
-       .intr_delta_dcd = SIO_IR_SA_DELTA_DCD,
-       .intr_delta_cts = SIO_IR_SA_DELTA_CTS,
-       .intr_tx_mt = SIO_IR_SA_TX_MT,
-       .intr_rx_timer = SIO_IR_SA_RX_TIMER,
-       .intr_rx_high = SIO_IR_SA_RX_HIGH,
-       .intr_tx_explicit = SIO_IR_SA_TX_EXPLICIT,
-       .intr_clear = (SIO_IR_SA_TX_MT | SIO_IR_SA_RX_FULL
-                               | SIO_IR_SA_RX_HIGH
-                               | SIO_IR_SA_RX_TIMER
-                               | SIO_IR_SA_DELTA_DCD
-                               | SIO_IR_SA_DELTA_CTS
-                               | SIO_IR_SA_INT
-                               | SIO_IR_SA_TX_EXPLICIT
-                               | SIO_IR_SA_MEMERR),
-       .intr_all =  SIO_IR_SA,
-       .rs422_select_pin = GPPR_UARTA_MODESEL_PIN,
-        },
-
-       /* values for port B */
-       {
-       .intr_delta_dcd = SIO_IR_SB_DELTA_DCD,
-       .intr_delta_cts = SIO_IR_SB_DELTA_CTS,
-       .intr_tx_mt = SIO_IR_SB_TX_MT,
-       .intr_rx_timer = SIO_IR_SB_RX_TIMER,
-       .intr_rx_high = SIO_IR_SB_RX_HIGH,
-       .intr_tx_explicit = SIO_IR_SB_TX_EXPLICIT,
-       .intr_clear = (SIO_IR_SB_TX_MT | SIO_IR_SB_RX_FULL
-                               | SIO_IR_SB_RX_HIGH
-                               | SIO_IR_SB_RX_TIMER
-                               | SIO_IR_SB_DELTA_DCD
-                               | SIO_IR_SB_DELTA_CTS
-                               | SIO_IR_SB_INT
-                               | SIO_IR_SB_TX_EXPLICIT
-                               | SIO_IR_SB_MEMERR),
-       .intr_all = SIO_IR_SB,
-       .rs422_select_pin = GPPR_UARTB_MODESEL_PIN,
-        }
-};
-
-struct ring_entry {
-       union {
-               struct {
-                       uint32_t alldata;
-                       uint32_t allsc;
-               } all;
-               struct {
-                       char data[4];   /* data bytes */
-                       char sc[4];     /* status/control */
-               } s;
-       } u;
-};
-
-/* Test the valid bits in any of the 4 sc chars using "allsc" member */
-#define RING_ANY_VALID \
-       ((uint32_t)(RXSB_MODEM_VALID | RXSB_DATA_VALID) * 0x01010101)
-
-#define ring_sc                u.s.sc
-#define ring_data      u.s.data
-#define ring_allsc     u.all.allsc
-
-/* Number of entries per ring buffer. */
-#define ENTRIES_PER_RING (RING_BUF_SIZE / (int) sizeof(struct ring_entry))
-
-/* An individual ring */
-struct ring {
-       struct ring_entry entries[ENTRIES_PER_RING];
-};
-
-/* The whole enchilada */
-struct ring_buffer {
-       struct ring TX_A;
-       struct ring RX_A;
-       struct ring TX_B;
-       struct ring RX_B;
-};
-
-/* Get a ring from a port struct */
-#define RING(_p, _wh)  &(((struct ring_buffer *)((_p)->ip_cpu_ringbuf))->_wh)
-
-/* for Infinite loop detection  */
-#define MAXITER                10000000
-
-
-/**
- * set_baud - Baud rate setting code
- * @port: port to set
- * @baud: baud rate to use
- */
-static int set_baud(struct ioc3_port *port, int baud)
-{
-       int divisor;
-       int actual_baud;
-       int diff;
-       int lcr, prediv;
-       struct ioc3_uartregs __iomem *uart;
-
-       for (prediv = 6; prediv < 64; prediv++) {
-               divisor = SER_DIVISOR(baud, SER_CLK_SPEED(prediv));
-               if (!divisor)
-                       continue;       /* invalid divisor */
-               actual_baud = DIVISOR_TO_BAUD(divisor, SER_CLK_SPEED(prediv));
-
-               diff = actual_baud - baud;
-               if (diff < 0)
-                       diff = -diff;
-
-               /* if we're within 1% we've found a match */
-               if (diff * 100 <= actual_baud)
-                       break;
-       }
-
-       /* if the above loop completed, we didn't match
-        * the baud rate.  give up.
-        */
-       if (prediv == 64) {
-               NOT_PROGRESS();
-               return 1;
-       }
-
-       uart = port->ip_uart_regs;
-       lcr = readb(&uart->iu_lcr);
-
-       writeb(lcr | UART_LCR_DLAB, &uart->iu_lcr);
-       writeb((unsigned char)divisor, &uart->iu_dll);
-       writeb((unsigned char)(divisor >> 8), &uart->iu_dlm);
-       writeb((unsigned char)prediv, &uart->iu_scr);
-       writeb((unsigned char)lcr, &uart->iu_lcr);
-
-       return 0;
-}
-
-/**
- * get_ioc3_port - given a uart port, return the control structure
- * @the_port: uart port to find
- */
-static struct ioc3_port *get_ioc3_port(struct uart_port *the_port)
-{
-       struct ioc3_driver_data *idd = dev_get_drvdata(the_port->dev);
-       struct ioc3_card *card_ptr = idd->data[Submodule_slot];
-       int ii, jj;
-
-       if (!card_ptr) {
-               NOT_PROGRESS();
-               return NULL;
-       }
-       for (ii = 0; ii < PORTS_PER_CARD; ii++) {
-               for (jj = 0; jj < LOGICAL_PORTS; jj++) {
-                       if (the_port == &card_ptr->ic_port[ii].icp_uart_port[jj])
-                               return card_ptr->ic_port[ii].icp_port;
-               }
-       }
-       NOT_PROGRESS();
-       return NULL;
-}
-
-/**
- * port_init - Initialize the sio and ioc3 hardware for a given port
- *                     called per port from attach...
- * @port: port to initialize
- */
-static int inline port_init(struct ioc3_port *port)
-{
-       uint32_t sio_cr;
-       struct port_hooks *hooks = port->ip_hooks;
-       struct ioc3_uartregs __iomem *uart;
-       int reset_loop_counter = 0xfffff;
-       struct ioc3_driver_data *idd = port->ip_idd;
-
-       /* Idle the IOC3 serial interface */
-       writel(SSCR_RESET, &port->ip_serial_regs->sscr);
-
-       /* Wait until any pending bus activity for this port has ceased */
-       do {
-               sio_cr = readl(&idd->vma->sio_cr);
-               if (reset_loop_counter-- <= 0) {
-                       printk(KERN_WARNING
-                              "IOC3 unable to come out of reset"
-                               " scr 0x%x\n", sio_cr);
-                       return -1;
-               }
-       } while (!(sio_cr & SIO_CR_ARB_DIAG_IDLE) &&
-              (((sio_cr &= SIO_CR_ARB_DIAG) == SIO_CR_ARB_DIAG_TXA)
-               || sio_cr == SIO_CR_ARB_DIAG_TXB
-               || sio_cr == SIO_CR_ARB_DIAG_RXA
-               || sio_cr == SIO_CR_ARB_DIAG_RXB));
-
-       /* Finish reset sequence */
-       writel(0, &port->ip_serial_regs->sscr);
-
-       /* Once RESET is done, reload cached tx_prod and rx_cons values
-        * and set rings to empty by making prod == cons
-        */
-       port->ip_tx_prod = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
-       writel(port->ip_tx_prod, &port->ip_serial_regs->stpir);
-       port->ip_rx_cons = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
-       writel(port->ip_rx_cons | SRCIR_ARM, &port->ip_serial_regs->srcir);
-
-       /* Disable interrupts for this 16550 */
-       uart = port->ip_uart_regs;
-       writeb(0, &uart->iu_lcr);
-       writeb(0, &uart->iu_ier);
-
-       /* Set the default baud */
-       set_baud(port, port->ip_baud);
-
-       /* Set line control to 8 bits no parity */
-       writeb(UART_LCR_WLEN8 | 0, &uart->iu_lcr);
-       /* UART_LCR_STOP == 1 stop */
-
-       /* Enable the FIFOs */
-       writeb(UART_FCR_ENABLE_FIFO, &uart->iu_fcr);
-       /* then reset 16550 FIFOs */
-       writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
-              &uart->iu_fcr);
-
-       /* Clear modem control register */
-       writeb(0, &uart->iu_mcr);
-
-       /* Clear deltas in modem status register */
-       writel(0, &port->ip_serial_regs->shadow);
-
-       /* Only do this once per port pair */
-       if (port->ip_hooks == &hooks_array[0]) {
-               unsigned long ring_pci_addr;
-               uint32_t __iomem *sbbr_l, *sbbr_h;
-
-               sbbr_l = &idd->vma->sbbr_l;
-               sbbr_h = &idd->vma->sbbr_h;
-               ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf;
-               DPRINT_CONFIG(("%s: ring_pci_addr 0x%p\n",
-                              __func__, (void *)ring_pci_addr));
-
-               writel((unsigned int)((uint64_t) ring_pci_addr >> 32), sbbr_h);
-               writel((unsigned int)ring_pci_addr | BUF_SIZE_BIT, sbbr_l);
-       }
-
-       /* Set the receive timeout value to 10 msec */
-       writel(SRTR_HZ / 100, &port->ip_serial_regs->srtr);
-
-       /* Set rx threshold, enable DMA */
-       /* Set high water mark at 3/4 of full ring */
-       port->ip_sscr = (ENTRIES_PER_RING * 3 / 4);
-
-       /* uart experiences pauses at high baud rate reducing actual
-        * throughput by 10% or so unless we enable high speed polling
-        * XXX when this hardware bug is resolved we should revert to
-        * normal polling speed
-        */
-       port->ip_sscr |= SSCR_HIGH_SPD;
-
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-
-       /* Disable and clear all serial related interrupt bits */
-       port->ip_card->ic_enable &= ~hooks->intr_clear;
-       ioc3_disable(port->ip_is, idd, hooks->intr_clear);
-       ioc3_ack(port->ip_is, idd, hooks->intr_clear);
-       return 0;
-}
-
-/**
- * enable_intrs - enable interrupts
- * @port: port to enable
- * @mask: mask to use
- */
-static void enable_intrs(struct ioc3_port *port, uint32_t mask)
-{
-       if ((port->ip_card->ic_enable & mask) != mask) {
-               port->ip_card->ic_enable |= mask;
-               ioc3_enable(port->ip_is, port->ip_idd, mask);
-       }
-}
-
-/**
- * local_open - local open a port
- * @port: port to open
- */
-static inline int local_open(struct ioc3_port *port)
-{
-       int spiniter = 0;
-
-       port->ip_flags = INPUT_ENABLE;
-
-       /* Pause the DMA interface if necessary */
-       if (port->ip_sscr & SSCR_DMA_EN) {
-               writel(port->ip_sscr | SSCR_DMA_PAUSE,
-                      &port->ip_serial_regs->sscr);
-               while ((readl(&port->ip_serial_regs->sscr)
-                       & SSCR_PAUSE_STATE) == 0) {
-                       spiniter++;
-                       if (spiniter > MAXITER) {
-                               NOT_PROGRESS();
-                               return -1;
-                       }
-               }
-       }
-
-       /* Reset the input fifo.  If the uart received chars while the port
-        * was closed and DMA is not enabled, the uart may have a bunch of
-        * chars hanging around in its rx fifo which will not be discarded
-        * by rclr in the upper layer. We must get rid of them here.
-        */
-       writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR,
-              &port->ip_uart_regs->iu_fcr);
-
-       writeb(UART_LCR_WLEN8, &port->ip_uart_regs->iu_lcr);
-       /* UART_LCR_STOP == 1 stop */
-
-       /* Re-enable DMA, set default threshold to intr whenever there is
-        * data available.
-        */
-       port->ip_sscr &= ~SSCR_RX_THRESHOLD;
-       port->ip_sscr |= 1;     /* default threshold */
-
-       /* Plug in the new sscr.  This implicitly clears the DMA_PAUSE
-        * flag if it was set above
-        */
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       port->ip_tx_lowat = 1;
-       return 0;
-}
-
-/**
- * set_rx_timeout - Set rx timeout and threshold values.
- * @port: port to use
- * @timeout: timeout value in ticks
- */
-static inline int set_rx_timeout(struct ioc3_port *port, int timeout)
-{
-       int threshold;
-
-       port->ip_rx_timeout = timeout;
-
-       /* Timeout is in ticks.  Let's figure out how many chars we
-        * can receive at the current baud rate in that interval
-        * and set the rx threshold to that amount.  There are 4 chars
-        * per ring entry, so we'll divide the number of chars that will
-        * arrive in timeout by 4.
-        * So .... timeout * baud / 10 / HZ / 4, with HZ = 100.
-        */
-       threshold = timeout * port->ip_baud / 4000;
-       if (threshold == 0)
-               threshold = 1;  /* otherwise we'll intr all the time! */
-
-       if ((unsigned)threshold > (unsigned)SSCR_RX_THRESHOLD)
-               return 1;
-
-       port->ip_sscr &= ~SSCR_RX_THRESHOLD;
-       port->ip_sscr |= threshold;
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-
-       /* Now set the rx timeout to the given value
-        * again timeout * SRTR_HZ / HZ
-        */
-       timeout = timeout * SRTR_HZ / 100;
-       if (timeout > SRTR_CNT)
-               timeout = SRTR_CNT;
-       writel(timeout, &port->ip_serial_regs->srtr);
-       return 0;
-}
-
-/**
- * config_port - config the hardware
- * @port: port to config
- * @baud: baud rate for the port
- * @byte_size: data size
- * @stop_bits: number of stop bits
- * @parenb: parity enable ?
- * @parodd: odd parity ?
- */
-static inline int
-config_port(struct ioc3_port *port,
-           int baud, int byte_size, int stop_bits, int parenb, int parodd)
-{
-       char lcr, sizebits;
-       int spiniter = 0;
-
-       DPRINT_CONFIG(("%s: line %d baud %d byte_size %d stop %d parenb %d "
-                       "parodd %d\n",
-                      __func__, ((struct uart_port *)port->ip_port)->line,
-                       baud, byte_size, stop_bits, parenb, parodd));
-
-       if (set_baud(port, baud))
-               return 1;
-
-       switch (byte_size) {
-       case 5:
-               sizebits = UART_LCR_WLEN5;
-               break;
-       case 6:
-               sizebits = UART_LCR_WLEN6;
-               break;
-       case 7:
-               sizebits = UART_LCR_WLEN7;
-               break;
-       case 8:
-               sizebits = UART_LCR_WLEN8;
-               break;
-       default:
-               return 1;
-       }
-
-       /* Pause the DMA interface if necessary */
-       if (port->ip_sscr & SSCR_DMA_EN) {
-               writel(port->ip_sscr | SSCR_DMA_PAUSE,
-                      &port->ip_serial_regs->sscr);
-               while ((readl(&port->ip_serial_regs->sscr)
-                       & SSCR_PAUSE_STATE) == 0) {
-                       spiniter++;
-                       if (spiniter > MAXITER)
-                               return -1;
-               }
-       }
-
-       /* Clear relevant fields in lcr */
-       lcr = readb(&port->ip_uart_regs->iu_lcr);
-       lcr &= ~(LCR_MASK_BITS_CHAR | UART_LCR_EPAR |
-                UART_LCR_PARITY | LCR_MASK_STOP_BITS);
-
-       /* Set byte size in lcr */
-       lcr |= sizebits;
-
-       /* Set parity */
-       if (parenb) {
-               lcr |= UART_LCR_PARITY;
-               if (!parodd)
-                       lcr |= UART_LCR_EPAR;
-       }
-
-       /* Set stop bits */
-       if (stop_bits)
-               lcr |= UART_LCR_STOP /* 2 stop bits */ ;
-
-       writeb(lcr, &port->ip_uart_regs->iu_lcr);
-
-       /* Re-enable the DMA interface if necessary */
-       if (port->ip_sscr & SSCR_DMA_EN) {
-               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       }
-       port->ip_baud = baud;
-
-       /* When we get within this number of ring entries of filling the
-        * entire ring on tx, place an EXPLICIT intr to generate a lowat
-        * notification when output has drained.
-        */
-       port->ip_tx_lowat = (TX_LOWAT_CHARS(baud) + 3) / 4;
-       if (port->ip_tx_lowat == 0)
-               port->ip_tx_lowat = 1;
-
-       set_rx_timeout(port, 2);
-       return 0;
-}
-
-/**
- * do_write - Write bytes to the port.  Returns the number of bytes
- *                     actually written. Called from transmit_chars
- * @port: port to use
- * @buf: the stuff to write
- * @len: how many bytes in 'buf'
- */
-static inline int do_write(struct ioc3_port *port, char *buf, int len)
-{
-       int prod_ptr, cons_ptr, total = 0;
-       struct ring *outring;
-       struct ring_entry *entry;
-       struct port_hooks *hooks = port->ip_hooks;
-
-       BUG_ON(!(len >= 0));
-
-       prod_ptr = port->ip_tx_prod;
-       cons_ptr = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
-       outring = port->ip_outring;
-
-       /* Maintain a 1-entry red-zone.  The ring buffer is full when
-        * (cons - prod) % ring_size is 1.  Rather than do this subtraction
-        * in the body of the loop, I'll do it now.
-        */
-       cons_ptr = (cons_ptr - (int)sizeof(struct ring_entry)) & PROD_CONS_MASK;
-
-       /* Stuff the bytes into the output */
-       while ((prod_ptr != cons_ptr) && (len > 0)) {
-               int xx;
-
-               /* Get 4 bytes (one ring entry) at a time */
-               entry = (struct ring_entry *)((caddr_t) outring + prod_ptr);
-
-               /* Invalidate all entries */
-               entry->ring_allsc = 0;
-
-               /* Copy in some bytes */
-               for (xx = 0; (xx < 4) && (len > 0); xx++) {
-                       entry->ring_data[xx] = *buf++;
-                       entry->ring_sc[xx] = TXCB_VALID;
-                       len--;
-                       total++;
-               }
-
-               /* If we are within some small threshold of filling up the
-                * entire ring buffer, we must place an EXPLICIT intr here
-                * to generate a lowat interrupt in case we subsequently
-                * really do fill up the ring and the caller goes to sleep.
-                * No need to place more than one though.
-                */
-               if (!(port->ip_flags & LOWAT_WRITTEN) &&
-                   ((cons_ptr - prod_ptr) & PROD_CONS_MASK)
-                   <= port->ip_tx_lowat * (int)sizeof(struct ring_entry)) {
-                       port->ip_flags |= LOWAT_WRITTEN;
-                       entry->ring_sc[0] |= TXCB_INT_WHEN_DONE;
-               }
-
-               /* Go on to next entry */
-               prod_ptr += sizeof(struct ring_entry);
-               prod_ptr &= PROD_CONS_MASK;
-       }
-
-       /* If we sent something, start DMA if necessary */
-       if (total > 0 && !(port->ip_sscr & SSCR_DMA_EN)) {
-               port->ip_sscr |= SSCR_DMA_EN;
-               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       }
-
-       /* Store the new producer pointer.  If tx is disabled, we stuff the
-        * data into the ring buffer, but we don't actually start tx.
-        */
-       if (!uart_tx_stopped(port->ip_port)) {
-               writel(prod_ptr, &port->ip_serial_regs->stpir);
-
-               /* If we are now transmitting, enable tx_mt interrupt so we
-                * can disable DMA if necessary when the tx finishes.
-                */
-               if (total > 0)
-                       enable_intrs(port, hooks->intr_tx_mt);
-       }
-       port->ip_tx_prod = prod_ptr;
-
-       return total;
-}
-
-/**
- * disable_intrs - disable interrupts
- * @port: port to enable
- * @mask: mask to use
- */
-static inline void disable_intrs(struct ioc3_port *port, uint32_t mask)
-{
-       if (port->ip_card->ic_enable & mask) {
-               ioc3_disable(port->ip_is, port->ip_idd, mask);
-               port->ip_card->ic_enable &= ~mask;
-       }
-}
-
-/**
- * set_notification - Modify event notification
- * @port: port to use
- * @mask: events mask
- * @set_on: set ?
- */
-static int set_notification(struct ioc3_port *port, int mask, int set_on)
-{
-       struct port_hooks *hooks = port->ip_hooks;
-       uint32_t intrbits, sscrbits;
-
-       BUG_ON(!mask);
-
-       intrbits = sscrbits = 0;
-
-       if (mask & N_DATA_READY)
-               intrbits |= (hooks->intr_rx_timer | hooks->intr_rx_high);
-       if (mask & N_OUTPUT_LOWAT)
-               intrbits |= hooks->intr_tx_explicit;
-       if (mask & N_DDCD) {
-               intrbits |= hooks->intr_delta_dcd;
-               sscrbits |= SSCR_RX_RING_DCD;
-       }
-       if (mask & N_DCTS)
-               intrbits |= hooks->intr_delta_cts;
-
-       if (set_on) {
-               enable_intrs(port, intrbits);
-               port->ip_notify |= mask;
-               port->ip_sscr |= sscrbits;
-       } else {
-               disable_intrs(port, intrbits);
-               port->ip_notify &= ~mask;
-               port->ip_sscr &= ~sscrbits;
-       }
-
-       /* We require DMA if either DATA_READY or DDCD notification is
-        * currently requested. If neither of these is requested and
-        * there is currently no tx in progress, DMA may be disabled.
-        */
-       if (port->ip_notify & (N_DATA_READY | N_DDCD))
-               port->ip_sscr |= SSCR_DMA_EN;
-       else if (!(port->ip_card->ic_enable & hooks->intr_tx_mt))
-               port->ip_sscr &= ~SSCR_DMA_EN;
-
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       return 0;
-}
-
-/**
- * set_mcr - set the master control reg
- * @the_port: port to use
- * @mask1: mcr mask
- * @mask2: shadow mask
- */
-static inline int set_mcr(struct uart_port *the_port,
-                         int mask1, int mask2)
-{
-       struct ioc3_port *port = get_ioc3_port(the_port);
-       uint32_t shadow;
-       int spiniter = 0;
-       char mcr;
-
-       if (!port)
-               return -1;
-
-       /* Pause the DMA interface if necessary */
-       if (port->ip_sscr & SSCR_DMA_EN) {
-               writel(port->ip_sscr | SSCR_DMA_PAUSE,
-                      &port->ip_serial_regs->sscr);
-               while ((readl(&port->ip_serial_regs->sscr)
-                       & SSCR_PAUSE_STATE) == 0) {
-                       spiniter++;
-                       if (spiniter > MAXITER)
-                               return -1;
-               }
-       }
-       shadow = readl(&port->ip_serial_regs->shadow);
-       mcr = (shadow & 0xff000000) >> 24;
-
-       /* Set new value */
-       mcr |= mask1;
-       shadow |= mask2;
-       writeb(mcr, &port->ip_uart_regs->iu_mcr);
-       writel(shadow, &port->ip_serial_regs->shadow);
-
-       /* Re-enable the DMA interface if necessary */
-       if (port->ip_sscr & SSCR_DMA_EN) {
-               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       }
-       return 0;
-}
-
-/**
- * ioc3_set_proto - set the protocol for the port
- * @port: port to use
- * @proto: protocol to use
- */
-static int ioc3_set_proto(struct ioc3_port *port, int proto)
-{
-       struct port_hooks *hooks = port->ip_hooks;
-
-       switch (proto) {
-       default:
-       case PROTO_RS232:
-               /* Clear the appropriate GIO pin */
-               DPRINT_CONFIG(("%s: rs232\n", __func__));
-               writel(0, (&port->ip_idd->vma->gppr[0]
-                                       + hooks->rs422_select_pin));
-               break;
-
-       case PROTO_RS422:
-               /* Set the appropriate GIO pin */
-               DPRINT_CONFIG(("%s: rs422\n", __func__));
-               writel(1, (&port->ip_idd->vma->gppr[0]
-                                       + hooks->rs422_select_pin));
-               break;
-       }
-       return 0;
-}
-
-/**
- * transmit_chars - upper level write, called with the_port->lock
- * @the_port: port to write
- */
-static void transmit_chars(struct uart_port *the_port)
-{
-       int xmit_count, tail, head;
-       int result;
-       char *start;
-       struct tty_struct *tty;
-       struct ioc3_port *port = get_ioc3_port(the_port);
-       struct uart_state *state;
-
-       if (!the_port)
-               return;
-       if (!port)
-               return;
-
-       state = the_port->state;
-       tty = state->port.tty;
-
-       if (uart_circ_empty(&state->xmit) || uart_tx_stopped(the_port)) {
-               /* Nothing to do or hw stopped */
-               set_notification(port, N_ALL_OUTPUT, 0);
-               return;
-       }
-
-       head = state->xmit.head;
-       tail = state->xmit.tail;
-       start = (char *)&state->xmit.buf[tail];
-
-       /* write out all the data or until the end of the buffer */
-       xmit_count = (head < tail) ? (UART_XMIT_SIZE - tail) : (head - tail);
-       if (xmit_count > 0) {
-               result = do_write(port, start, xmit_count);
-               if (result > 0) {
-                       /* booking */
-                       xmit_count -= result;
-                       the_port->icount.tx += result;
-                       /* advance the pointers */
-                       tail += result;
-                       tail &= UART_XMIT_SIZE - 1;
-                       state->xmit.tail = tail;
-                       start = (char *)&state->xmit.buf[tail];
-               }
-       }
-       if (uart_circ_chars_pending(&state->xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(the_port);
-
-       if (uart_circ_empty(&state->xmit)) {
-               set_notification(port, N_OUTPUT_LOWAT, 0);
-       } else {
-               set_notification(port, N_OUTPUT_LOWAT, 1);
-       }
-}
-
-/**
- * ioc3_change_speed - change the speed of the port
- * @the_port: port to change
- * @new_termios: new termios settings
- * @old_termios: old termios settings
- */
-static void
-ioc3_change_speed(struct uart_port *the_port,
-                 struct ktermios *new_termios, struct ktermios *old_termios)
-{
-       struct ioc3_port *port = get_ioc3_port(the_port);
-       unsigned int cflag, iflag;
-       int baud;
-       int new_parity = 0, new_parity_enable = 0, new_stop = 0, new_data = 8;
-       struct uart_state *state = the_port->state;
-
-       cflag = new_termios->c_cflag;
-       iflag = new_termios->c_iflag;
-
-       switch (cflag & CSIZE) {
-       case CS5:
-               new_data = 5;
-               break;
-       case CS6:
-               new_data = 6;
-               break;
-       case CS7:
-               new_data = 7;
-               break;
-       case CS8:
-               new_data = 8;
-               break;
-       default:
-               /* cuz we always need a default ... */
-               new_data = 5;
-               break;
-       }
-       if (cflag & CSTOPB) {
-               new_stop = 1;
-       }
-       if (cflag & PARENB) {
-               new_parity_enable = 1;
-               if (cflag & PARODD)
-                       new_parity = 1;
-       }
-       baud = uart_get_baud_rate(the_port, new_termios, old_termios,
-                                 MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED);
-       DPRINT_CONFIG(("%s: returned baud %d for line %d\n", __func__, baud,
-                               the_port->line));
-
-       if (!the_port->fifosize)
-               the_port->fifosize = FIFO_SIZE;
-       uart_update_timeout(the_port, cflag, baud);
-
-       the_port->ignore_status_mask = N_ALL_INPUT;
-
-       state->port.tty->low_latency = 1;
-
-       if (iflag & IGNPAR)
-               the_port->ignore_status_mask &= ~(N_PARITY_ERROR
-                                                 | N_FRAMING_ERROR);
-       if (iflag & IGNBRK) {
-               the_port->ignore_status_mask &= ~N_BREAK;
-               if (iflag & IGNPAR)
-                       the_port->ignore_status_mask &= ~N_OVERRUN_ERROR;
-       }
-       if (!(cflag & CREAD)) {
-               /* ignore everything */
-               the_port->ignore_status_mask &= ~N_DATA_READY;
-       }
-
-       if (cflag & CRTSCTS) {
-               /* enable hardware flow control */
-               port->ip_sscr |= SSCR_HFC_EN;
-       }
-       else {
-               /* disable hardware flow control */
-               port->ip_sscr &= ~SSCR_HFC_EN;
-       }
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-
-       /* Set the configuration and proper notification call */
-       DPRINT_CONFIG(("%s : port 0x%p line %d cflag 0%o "
-                      "config_port(baud %d data %d stop %d penable %d "
-                       " parity %d), notification 0x%x\n",
-                      __func__, (void *)port, the_port->line, cflag, baud,
-                      new_data, new_stop, new_parity_enable, new_parity,
-                      the_port->ignore_status_mask));
-
-       if ((config_port(port, baud,    /* baud */
-                        new_data,      /* byte size */
-                        new_stop,      /* stop bits */
-                        new_parity_enable,     /* set parity */
-                        new_parity)) >= 0) {   /* parity 1==odd */
-               set_notification(port, the_port->ignore_status_mask, 1);
-       }
-}
-
-/**
- * ic3_startup_local - Start up the serial port - returns >= 0 if no errors
- * @the_port: Port to operate on
- */
-static inline int ic3_startup_local(struct uart_port *the_port)
-{
-       struct ioc3_port *port;
-
-       if (!the_port) {
-               NOT_PROGRESS();
-               return -1;
-       }
-
-       port = get_ioc3_port(the_port);
-       if (!port) {
-               NOT_PROGRESS();
-               return -1;
-       }
-
-       local_open(port);
-
-       /* set the protocol */
-       ioc3_set_proto(port, IS_RS232(the_port->line) ? PROTO_RS232 :
-                                                       PROTO_RS422);
-       return 0;
-}
-
-/*
- * ioc3_cb_output_lowat - called when the output low water mark is hit
- * @port: port to output
- */
-static void ioc3_cb_output_lowat(struct ioc3_port *port)
-{
-       unsigned long pflags;
-
-       /* the_port->lock is set on the call here */
-       if (port->ip_port) {
-               spin_lock_irqsave(&port->ip_port->lock, pflags);
-               transmit_chars(port->ip_port);
-               spin_unlock_irqrestore(&port->ip_port->lock, pflags);
-       }
-}
-
-/*
- * ioc3_cb_post_ncs - called for some basic errors
- * @port: port to use
- * @ncs: event
- */
-static void ioc3_cb_post_ncs(struct uart_port *the_port, int ncs)
-{
-       struct uart_icount *icount;
-
-       icount = &the_port->icount;
-
-       if (ncs & NCS_BREAK)
-               icount->brk++;
-       if (ncs & NCS_FRAMING)
-               icount->frame++;
-       if (ncs & NCS_OVERRUN)
-               icount->overrun++;
-       if (ncs & NCS_PARITY)
-               icount->parity++;
-}
-
-/**
- * do_read - Read in bytes from the port.  Return the number of bytes
- *                     actually read.
- * @the_port: port to use
- * @buf: place to put the stuff we read
- * @len: how big 'buf' is
- */
-
-static inline int do_read(struct uart_port *the_port, char *buf, int len)
-{
-       int prod_ptr, cons_ptr, total;
-       struct ioc3_port *port = get_ioc3_port(the_port);
-       struct ring *inring;
-       struct ring_entry *entry;
-       struct port_hooks *hooks = port->ip_hooks;
-       int byte_num;
-       char *sc;
-       int loop_counter;
-
-       BUG_ON(!(len >= 0));
-       BUG_ON(!port);
-
-       /* There is a nasty timing issue in the IOC3. When the rx_timer
-        * expires or the rx_high condition arises, we take an interrupt.
-        * At some point while servicing the interrupt, we read bytes from
-        * the ring buffer and re-arm the rx_timer.  However the rx_timer is
-        * not started until the first byte is received *after* it is armed,
-        * and any bytes pending in the rx construction buffers are not drained
-        * to memory until either there are 4 bytes available or the rx_timer
-        * expires.  This leads to a potential situation where data is left
-        * in the construction buffers forever - 1 to 3 bytes were received
-        * after the interrupt was generated but before the rx_timer was
-        * re-armed. At that point as long as no subsequent bytes are received
-        * the timer will never be started and the bytes will remain in the
-        * construction buffer forever.  The solution is to execute a DRAIN
-        * command after rearming the timer.  This way any bytes received before
-        * the DRAIN will be drained to memory, and any bytes received after
-        * the DRAIN will start the TIMER and be drained when it expires.
-        * Luckily, this only needs to be done when the DMA buffer is empty
-        * since there is no requirement that this function return all
-        * available data as long as it returns some.
-        */
-       /* Re-arm the timer */
-
-       writel(port->ip_rx_cons | SRCIR_ARM, &port->ip_serial_regs->srcir);
-
-       prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
-       cons_ptr = port->ip_rx_cons;
-
-       if (prod_ptr == cons_ptr) {
-               int reset_dma = 0;
-
-               /* Input buffer appears empty, do a flush. */
-
-               /* DMA must be enabled for this to work. */
-               if (!(port->ip_sscr & SSCR_DMA_EN)) {
-                       port->ip_sscr |= SSCR_DMA_EN;
-                       reset_dma = 1;
-               }
-
-               /* Potential race condition: we must reload the srpir after
-                * issuing the drain command, otherwise we could think the rx
-                * buffer is empty, then take a very long interrupt, and when
-                * we come back it's full and we wait forever for the drain to
-                * complete.
-                */
-               writel(port->ip_sscr | SSCR_RX_DRAIN,
-                      &port->ip_serial_regs->sscr);
-               prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
-
-               /* We must not wait for the DRAIN to complete unless there are
-                * at least 8 bytes (2 ring entries) available to receive the
-                * data otherwise the DRAIN will never complete and we'll
-                * deadlock here.
-                * In fact, to make things easier, I'll just ignore the flush if
-                * there is any data at all now available.
-                */
-               if (prod_ptr == cons_ptr) {
-                       loop_counter = 0;
-                       while (readl(&port->ip_serial_regs->sscr) &
-                              SSCR_RX_DRAIN) {
-                               loop_counter++;
-                               if (loop_counter > MAXITER)
-                                       return -1;
-                       }
-
-                       /* SIGH. We have to reload the prod_ptr *again* since
-                        * the drain may have caused it to change
-                        */
-                       prod_ptr = readl(&port->ip_serial_regs->srpir)
-                           & PROD_CONS_MASK;
-               }
-               if (reset_dma) {
-                       port->ip_sscr &= ~SSCR_DMA_EN;
-                       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-               }
-       }
-       inring = port->ip_inring;
-       port->ip_flags &= ~READ_ABORTED;
-
-       total = 0;
-       loop_counter = 0xfffff; /* to avoid hangs */
-
-       /* Grab bytes from the hardware */
-       while ((prod_ptr != cons_ptr) && (len > 0)) {
-               entry = (struct ring_entry *)((caddr_t) inring + cons_ptr);
-
-               if (loop_counter-- <= 0) {
-                       printk(KERN_WARNING "IOC3 serial: "
-                              "possible hang condition/"
-                              "port stuck on read (line %d).\n",
-                               the_port->line);
-                       break;
-               }
-
-               /* According to the producer pointer, this ring entry
-                * must contain some data.  But if the PIO happened faster
-                * than the DMA, the data may not be available yet, so let's
-                * wait until it arrives.
-                */
-               if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
-                       /* Indicate the read is aborted so we don't disable
-                        * the interrupt thinking that the consumer is
-                        * congested.
-                        */
-                       port->ip_flags |= READ_ABORTED;
-                       len = 0;
-                       break;
-               }
-
-               /* Load the bytes/status out of the ring entry */
-               for (byte_num = 0; byte_num < 4 && len > 0; byte_num++) {
-                       sc = &(entry->ring_sc[byte_num]);
-
-                       /* Check for change in modem state or overrun */
-                       if ((*sc & RXSB_MODEM_VALID)
-                           && (port->ip_notify & N_DDCD)) {
-                               /* Notify upper layer if DCD dropped */
-                               if ((port->ip_flags & DCD_ON)
-                                   && !(*sc & RXSB_DCD)) {
-                                       /* If we have already copied some data,
-                                        * return it.  We'll pick up the carrier
-                                        * drop on the next pass.  That way we
-                                        * don't throw away the data that has
-                                        * already been copied back to
-                                        * the caller's buffer.
-                                        */
-                                       if (total > 0) {
-                                               len = 0;
-                                               break;
-                                       }
-                                       port->ip_flags &= ~DCD_ON;
-
-                                       /* Turn off this notification so the
-                                        * carrier drop protocol won't see it
-                                        * again when it does a read.
-                                        */
-                                       *sc &= ~RXSB_MODEM_VALID;
-
-                                       /* To keep things consistent, we need
-                                        * to update the consumer pointer so
-                                        * the next reader won't come in and
-                                        * try to read the same ring entries
-                                        * again. This must be done here before
-                                        * the dcd change.
-                                        */
-
-                                       if ((entry->ring_allsc & RING_ANY_VALID)
-                                           == 0) {
-                                               cons_ptr += (int)sizeof
-                                                   (struct ring_entry);
-                                               cons_ptr &= PROD_CONS_MASK;
-                                       }
-                                       writel(cons_ptr,
-                                              &port->ip_serial_regs->srcir);
-                                       port->ip_rx_cons = cons_ptr;
-
-                                       /* Notify upper layer of carrier drop */
-                                       if ((port->ip_notify & N_DDCD)
-                                           && port->ip_port) {
-                                               uart_handle_dcd_change
-                                                       (port->ip_port, 0);
-                                               wake_up_interruptible
-                                                   (&the_port->state->
-                                                    port.delta_msr_wait);
-                                       }
-
-                                       /* If we had any data to return, we
-                                        * would have returned it above.
-                                        */
-                                       return 0;
-                               }
-                       }
-                       if (*sc & RXSB_MODEM_VALID) {
-                               /* Notify that an input overrun occurred */
-                               if ((*sc & RXSB_OVERRUN)
-                                   && (port->ip_notify & N_OVERRUN_ERROR)) {
-                                       ioc3_cb_post_ncs(the_port, NCS_OVERRUN);
-                               }
-                               /* Don't look at this byte again */
-                               *sc &= ~RXSB_MODEM_VALID;
-                       }
-
-                       /* Check for valid data or RX errors */
-                       if ((*sc & RXSB_DATA_VALID) &&
-                           ((*sc & (RXSB_PAR_ERR
-                                    | RXSB_FRAME_ERR | RXSB_BREAK))
-                            && (port->ip_notify & (N_PARITY_ERROR
-                                                   | N_FRAMING_ERROR
-                                                   | N_BREAK)))) {
-                               /* There is an error condition on the next byte.
-                                * If we have already transferred some bytes,
-                                * we'll stop here. Otherwise if this is the
-                                * first byte to be read, we'll just transfer
-                                * it alone after notifying the
-                                * upper layer of its status.
-                                */
-                               if (total > 0) {
-                                       len = 0;
-                                       break;
-                               } else {
-                                       if ((*sc & RXSB_PAR_ERR) &&
-                                           (port->
-                                            ip_notify & N_PARITY_ERROR)) {
-                                               ioc3_cb_post_ncs(the_port,
-                                                                NCS_PARITY);
-                                       }
-                                       if ((*sc & RXSB_FRAME_ERR) &&
-                                           (port->
-                                            ip_notify & N_FRAMING_ERROR)) {
-                                               ioc3_cb_post_ncs(the_port,
-                                                                NCS_FRAMING);
-                                       }
-                                       if ((*sc & RXSB_BREAK)
-                                           && (port->ip_notify & N_BREAK)) {
-                                               ioc3_cb_post_ncs
-                                                   (the_port, NCS_BREAK);
-                                       }
-                                       len = 1;
-                               }
-                       }
-                       if (*sc & RXSB_DATA_VALID) {
-                               *sc &= ~RXSB_DATA_VALID;
-                               *buf = entry->ring_data[byte_num];
-                               buf++;
-                               len--;
-                               total++;
-                       }
-               }
-
-               /* If we used up this entry entirely, go on to the next one,
-                * otherwise we must have run out of buffer space, so
-                * leave the consumer pointer here for the next read in case
-                * there are still unread bytes in this entry.
-                */
-               if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
-                       cons_ptr += (int)sizeof(struct ring_entry);
-                       cons_ptr &= PROD_CONS_MASK;
-               }
-       }
-
-       /* Update consumer pointer and re-arm rx timer interrupt */
-       writel(cons_ptr, &port->ip_serial_regs->srcir);
-       port->ip_rx_cons = cons_ptr;
-
-       /* If we have now dipped below the rx high water mark and we have
-        * rx_high interrupt turned off, we can now turn it back on again.
-        */
-       if ((port->ip_flags & INPUT_HIGH) && (((prod_ptr - cons_ptr)
-                                              & PROD_CONS_MASK) <
-                                             ((port->
-                                               ip_sscr &
-                                               SSCR_RX_THRESHOLD)
-                                              << PROD_CONS_PTR_OFF))) {
-               port->ip_flags &= ~INPUT_HIGH;
-               enable_intrs(port, hooks->intr_rx_high);
-       }
-       return total;
-}
-
-/**
- * receive_chars - upper level read.
- * @the_port: port to read from
- */
-static int receive_chars(struct uart_port *the_port)
-{
-       struct tty_struct *tty;
-       unsigned char ch[MAX_CHARS];
-       int read_count = 0, read_room, flip = 0;
-       struct uart_state *state = the_port->state;
-       struct ioc3_port *port = get_ioc3_port(the_port);
-       unsigned long pflags;
-
-       /* Make sure all the pointers are "good" ones */
-       if (!state)
-               return 0;
-       if (!state->port.tty)
-               return 0;
-
-       if (!(port->ip_flags & INPUT_ENABLE))
-               return 0;
-
-       spin_lock_irqsave(&the_port->lock, pflags);
-       tty = state->port.tty;
-
-       read_count = do_read(the_port, ch, MAX_CHARS);
-       if (read_count > 0) {
-               flip = 1;
-               read_room = tty_insert_flip_string(tty, ch, read_count);
-               the_port->icount.rx += read_count;
-       }
-       spin_unlock_irqrestore(&the_port->lock, pflags);
-
-       if (flip)
-               tty_flip_buffer_push(tty);
-
-       return read_count;
-}
-
-/**
- * ioc3uart_intr_one - lowest level (per port) interrupt handler.
- * @is : submodule
- * @idd: driver data
- * @pending: interrupts to handle
- */
-
-static int inline
-ioc3uart_intr_one(struct ioc3_submodule *is,
-                       struct ioc3_driver_data *idd,
-                       unsigned int pending)
-{
-       int port_num = GET_PORT_FROM_SIO_IR(pending);
-       struct port_hooks *hooks;
-       unsigned int rx_high_rd_aborted = 0;
-       unsigned long flags;
-       struct uart_port *the_port;
-       struct ioc3_port *port;
-       int loop_counter;
-       struct ioc3_card *card_ptr;
-       unsigned int sio_ir;
-
-       card_ptr = idd->data[is->id];
-       port = card_ptr->ic_port[port_num].icp_port;
-       hooks = port->ip_hooks;
-
-       /* Possible race condition here: The tx_mt interrupt bit may be
-        * cleared without the intervention of the interrupt handler,
-        * e.g. by a write.  If the top level interrupt handler reads a
-        * tx_mt, then some other processor does a write, starting up
-        * output, then we come in here, see the tx_mt and stop DMA, the
-        * output started by the other processor will hang.  Thus we can
-        * only rely on tx_mt being legitimate if it is read while the
-        * port lock is held.  Therefore this bit must be ignored in the
-        * passed in interrupt mask which was read by the top level
-        * interrupt handler since the port lock was not held at the time
-        * it was read.  We can only rely on this bit being accurate if it
-        * is read while the port lock is held.  So we'll clear it for now,
-        * and reload it later once we have the port lock.
-        */
-
-       sio_ir = pending & ~(hooks->intr_tx_mt);
-       spin_lock_irqsave(&port->ip_lock, flags);
-
-       loop_counter = MAXITER; /* to avoid hangs */
-
-       do {
-               uint32_t shadow;
-
-               if (loop_counter-- <= 0) {
-                       printk(KERN_WARNING "IOC3 serial: "
-                              "possible hang condition/"
-                              "port stuck on interrupt (line %d).\n",
-                               ((struct uart_port *)port->ip_port)->line);
-                       break;
-               }
-               /* Handle a DCD change */
-               if (sio_ir & hooks->intr_delta_dcd) {
-                       ioc3_ack(is, idd, hooks->intr_delta_dcd);
-                       shadow = readl(&port->ip_serial_regs->shadow);
-
-                       if ((port->ip_notify & N_DDCD)
-                           && (shadow & SHADOW_DCD)
-                           && (port->ip_port)) {
-                               the_port = port->ip_port;
-                               uart_handle_dcd_change(the_port,
-                                               shadow & SHADOW_DCD);
-                               wake_up_interruptible
-                                   (&the_port->state->port.delta_msr_wait);
-                       } else if ((port->ip_notify & N_DDCD)
-                                  && !(shadow & SHADOW_DCD)) {
-                               /* Flag delta DCD/no DCD */
-                               uart_handle_dcd_change(port->ip_port,
-                                               shadow & SHADOW_DCD);
-                               port->ip_flags |= DCD_ON;
-                       }
-               }
-
-               /* Handle a CTS change */
-               if (sio_ir & hooks->intr_delta_cts) {
-                       ioc3_ack(is, idd, hooks->intr_delta_cts);
-                       shadow = readl(&port->ip_serial_regs->shadow);
-
-                       if ((port->ip_notify & N_DCTS) && (port->ip_port)) {
-                               the_port = port->ip_port;
-                               uart_handle_cts_change(the_port, shadow
-                                               & SHADOW_CTS);
-                               wake_up_interruptible
-                                   (&the_port->state->port.delta_msr_wait);
-                       }
-               }
-
-               /* rx timeout interrupt.  Must be some data available.  Put this
-                * before the check for rx_high since servicing this condition
-                * may cause that condition to clear.
-                */
-               if (sio_ir & hooks->intr_rx_timer) {
-                       ioc3_ack(is, idd, hooks->intr_rx_timer);
-                       if ((port->ip_notify & N_DATA_READY)
-                                               && (port->ip_port)) {
-                               receive_chars(port->ip_port);
-                       }
-               }
-
-               /* rx high interrupt. Must be after rx_timer.  */
-               else if (sio_ir & hooks->intr_rx_high) {
-                       /* Data available, notify upper layer */
-                       if ((port->ip_notify & N_DATA_READY) && port->ip_port) {
-                               receive_chars(port->ip_port);
-                       }
-
-                       /* We can't ACK this interrupt.  If receive_chars didn't
-                        * cause the condition to clear, we'll have to disable
-                        * the interrupt until the data is drained.
-                        * If the read was aborted, don't disable the interrupt
-                        * as this may cause us to hang indefinitely.  An
-                        * aborted read generally means that this interrupt
-                        * hasn't been delivered to the cpu yet anyway, even
-                        * though we see it as asserted when we read the sio_ir.
-                        */
-                       if ((sio_ir = PENDING(card_ptr, idd))
-                                       & hooks->intr_rx_high) {
-                               if (port->ip_flags & READ_ABORTED) {
-                                       rx_high_rd_aborted++;
-                               }
-                               else {
-                                       card_ptr->ic_enable &= ~hooks->intr_rx_high;
-                                       port->ip_flags |= INPUT_HIGH;
-                               }
-                       }
-               }
-
-               /* We got a low water interrupt: notify upper layer to
-                * send more data.  Must come before tx_mt since servicing
-                * this condition may cause that condition to clear.
-                */
-               if (sio_ir & hooks->intr_tx_explicit) {
-                       port->ip_flags &= ~LOWAT_WRITTEN;
-                       ioc3_ack(is, idd, hooks->intr_tx_explicit);
-                       if (port->ip_notify & N_OUTPUT_LOWAT)
-                               ioc3_cb_output_lowat(port);
-               }
-
-               /* Handle tx_mt.  Must come after tx_explicit.  */
-               else if (sio_ir & hooks->intr_tx_mt) {
-                       /* If we are expecting a lowat notification
-                        * and we get to this point it probably means that for
-                        * some reason the tx_explicit didn't work as expected
-                        * (that can legitimately happen if the output buffer is
-                        * filled up in just the right way).
-                        * So send the notification now.
-                        */
-                       if (port->ip_notify & N_OUTPUT_LOWAT) {
-                               ioc3_cb_output_lowat(port);
-
-                               /* We need to reload the sio_ir since the lowat
-                                * call may have caused another write to occur,
-                                * clearing the tx_mt condition.
-                                */
-                               sio_ir = PENDING(card_ptr, idd);
-                       }
-
-                       /* If the tx_mt condition still persists even after the
-                        * lowat call, we've got some work to do.
-                        */
-                       if (sio_ir & hooks->intr_tx_mt) {
-                               /* If we are not currently expecting DMA input,
-                                * and the transmitter has just gone idle,
-                                * there is no longer any reason for DMA, so
-                                * disable it.
-                                */
-                               if (!(port->ip_notify
-                                     & (N_DATA_READY | N_DDCD))) {
-                                       BUG_ON(!(port->ip_sscr
-                                                & SSCR_DMA_EN));
-                                       port->ip_sscr &= ~SSCR_DMA_EN;
-                                       writel(port->ip_sscr,
-                                              &port->ip_serial_regs->sscr);
-                               }
-                               /* Prevent infinite tx_mt interrupt */
-                               card_ptr->ic_enable &= ~hooks->intr_tx_mt;
-                       }
-               }
-               sio_ir = PENDING(card_ptr, idd);
-
-               /* if the read was aborted and only hooks->intr_rx_high,
-                * clear hooks->intr_rx_high, so we do not loop forever.
-                */
-
-               if (rx_high_rd_aborted && (sio_ir == hooks->intr_rx_high)) {
-                       sio_ir &= ~hooks->intr_rx_high;
-               }
-       } while (sio_ir & hooks->intr_all);
-
-       spin_unlock_irqrestore(&port->ip_lock, flags);
-       ioc3_enable(is, idd, card_ptr->ic_enable);
-       return 0;
-}
-
-/**
- * ioc3uart_intr - field all serial interrupts
- * @is : submodule
- * @idd: driver data
- * @pending: interrupts to handle
- *
- */
-
-static int ioc3uart_intr(struct ioc3_submodule *is,
-                       struct ioc3_driver_data *idd,
-                       unsigned int pending)
-{
-       int ret = 0;
-
-       /*
-        * The upper level interrupt handler sends interrupts for both ports
-        * here. So we need to call for each port with its interrupts.
-        */
-
-       if (pending & SIO_IR_SA)
-               ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SA);
-       if (pending & SIO_IR_SB)
-               ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SB);
-
-       return ret;
-}
-
-/**
- * ic3_type
- * @port: Port to operate with (we ignore since we only have one port)
- *
- */
-static const char *ic3_type(struct uart_port *the_port)
-{
-       if (IS_RS232(the_port->line))
-               return "SGI IOC3 Serial [rs232]";
-       else
-               return "SGI IOC3 Serial [rs422]";
-}
-
-/**
- * ic3_tx_empty - Is the transmitter empty?
- * @port: Port to operate on
- *
- */
-static unsigned int ic3_tx_empty(struct uart_port *the_port)
-{
-       unsigned int ret = 0;
-       struct ioc3_port *port = get_ioc3_port(the_port);
-
-       if (readl(&port->ip_serial_regs->shadow) & SHADOW_TEMT)
-               ret = TIOCSER_TEMT;
-       return ret;
-}
-
-/**
- * ic3_stop_tx - stop the transmitter
- * @port: Port to operate on
- *
- */
-static void ic3_stop_tx(struct uart_port *the_port)
-{
-       struct ioc3_port *port = get_ioc3_port(the_port);
-
-       if (port)
-               set_notification(port, N_OUTPUT_LOWAT, 0);
-}
-
-/**
- * ic3_stop_rx - stop the receiver
- * @port: Port to operate on
- *
- */
-static void ic3_stop_rx(struct uart_port *the_port)
-{
-       struct ioc3_port *port = get_ioc3_port(the_port);
-
-       if (port)
-               port->ip_flags &= ~INPUT_ENABLE;
-}
-
-/**
- * null_void_function
- * @port: Port to operate on
- *
- */
-static void null_void_function(struct uart_port *the_port)
-{
-}
-
-/**
- * ic3_shutdown - shut down the port - free irq and disable
- * @port: port to shut down
- *
- */
-static void ic3_shutdown(struct uart_port *the_port)
-{
-       unsigned long port_flags;
-       struct ioc3_port *port;
-       struct uart_state *state;
-
-       port = get_ioc3_port(the_port);
-       if (!port)
-               return;
-
-       state = the_port->state;
-       wake_up_interruptible(&state->port.delta_msr_wait);
-
-       spin_lock_irqsave(&the_port->lock, port_flags);
-       set_notification(port, N_ALL, 0);
-       spin_unlock_irqrestore(&the_port->lock, port_flags);
-}
-
-/**
- * ic3_set_mctrl - set control lines (dtr, rts, etc)
- * @port: Port to operate on
- * @mctrl: Lines to set/unset
- *
- */
-static void ic3_set_mctrl(struct uart_port *the_port, unsigned int mctrl)
-{
-       unsigned char mcr = 0;
-
-       if (mctrl & TIOCM_RTS)
-               mcr |= UART_MCR_RTS;
-       if (mctrl & TIOCM_DTR)
-               mcr |= UART_MCR_DTR;
-       if (mctrl & TIOCM_OUT1)
-               mcr |= UART_MCR_OUT1;
-       if (mctrl & TIOCM_OUT2)
-               mcr |= UART_MCR_OUT2;
-       if (mctrl & TIOCM_LOOP)
-               mcr |= UART_MCR_LOOP;
-
-       set_mcr(the_port, mcr, SHADOW_DTR);
-}
-
-/**
- * ic3_get_mctrl - get control line info
- * @port: port to operate on
- *
- */
-static unsigned int ic3_get_mctrl(struct uart_port *the_port)
-{
-       struct ioc3_port *port = get_ioc3_port(the_port);
-       uint32_t shadow;
-       unsigned int ret = 0;
-
-       if (!port)
-               return 0;
-
-       shadow = readl(&port->ip_serial_regs->shadow);
-       if (shadow & SHADOW_DCD)
-               ret |= TIOCM_CD;
-       if (shadow & SHADOW_DR)
-               ret |= TIOCM_DSR;
-       if (shadow & SHADOW_CTS)
-               ret |= TIOCM_CTS;
-       return ret;
-}
-
-/**
- * ic3_start_tx - Start transmitter. Called with the_port->lock
- * @port: Port to operate on
- *
- */
-static void ic3_start_tx(struct uart_port *the_port)
-{
-       struct ioc3_port *port = get_ioc3_port(the_port);
-
-       if (port) {
-               set_notification(port, N_OUTPUT_LOWAT, 1);
-               enable_intrs(port, port->ip_hooks->intr_tx_mt);
-       }
-}
-
-/**
- * ic3_break_ctl - handle breaks
- * @port: Port to operate on
- * @break_state: Break state
- *
- */
-static void ic3_break_ctl(struct uart_port *the_port, int break_state)
-{
-}
-
-/**
- * ic3_startup - Start up the serial port - always return 0 (We're always on)
- * @port: Port to operate on
- *
- */
-static int ic3_startup(struct uart_port *the_port)
-{
-       int retval;
-       struct ioc3_port *port;
-       struct ioc3_card *card_ptr;
-       unsigned long port_flags;
-
-       if (!the_port) {
-               NOT_PROGRESS();
-               return -ENODEV;
-       }
-       port = get_ioc3_port(the_port);
-       if (!port) {
-               NOT_PROGRESS();
-               return -ENODEV;
-       }
-       card_ptr = port->ip_card;
-       port->ip_port = the_port;
-
-       if (!card_ptr) {
-               NOT_PROGRESS();
-               return -ENODEV;
-       }
-
-       /* Start up the serial port */
-       spin_lock_irqsave(&the_port->lock, port_flags);
-       retval = ic3_startup_local(the_port);
-       spin_unlock_irqrestore(&the_port->lock, port_flags);
-       return retval;
-}
-
-/**
- * ic3_set_termios - set termios stuff
- * @port: port to operate on
- * @termios: New settings
- * @termios: Old
- *
- */
-static void
-ic3_set_termios(struct uart_port *the_port,
-               struct ktermios *termios, struct ktermios *old_termios)
-{
-       unsigned long port_flags;
-
-       spin_lock_irqsave(&the_port->lock, port_flags);
-       ioc3_change_speed(the_port, termios, old_termios);
-       spin_unlock_irqrestore(&the_port->lock, port_flags);
-}
-
-/**
- * ic3_request_port - allocate resources for port - no op....
- * @port: port to operate on
- *
- */
-static int ic3_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-/* Associate the uart functions above - given to serial core */
-static struct uart_ops ioc3_ops = {
-       .tx_empty = ic3_tx_empty,
-       .set_mctrl = ic3_set_mctrl,
-       .get_mctrl = ic3_get_mctrl,
-       .stop_tx = ic3_stop_tx,
-       .start_tx = ic3_start_tx,
-       .stop_rx = ic3_stop_rx,
-       .enable_ms = null_void_function,
-       .break_ctl = ic3_break_ctl,
-       .startup = ic3_startup,
-       .shutdown = ic3_shutdown,
-       .set_termios = ic3_set_termios,
-       .type = ic3_type,
-       .release_port = null_void_function,
-       .request_port = ic3_request_port,
-};
-
-/*
- * Boot-time initialization code
- */
-
-static struct uart_driver ioc3_uart = {
-       .owner = THIS_MODULE,
-       .driver_name = "ioc3_serial",
-       .dev_name = DEVICE_NAME,
-       .major = DEVICE_MAJOR,
-       .minor = DEVICE_MINOR,
-       .nr = MAX_LOGICAL_PORTS
-};
-
-/**
- * ioc3_serial_core_attach - register with serial core
- *             This is done during pci probing
- * @is: submodule struct for this
- * @idd: handle for this card
- */
-static inline int ioc3_serial_core_attach( struct ioc3_submodule *is,
-                               struct ioc3_driver_data *idd)
-{
-       struct ioc3_port *port;
-       struct uart_port *the_port;
-       struct ioc3_card *card_ptr = idd->data[is->id];
-       int ii, phys_port;
-       struct pci_dev *pdev = idd->pdev;
-
-       DPRINT_CONFIG(("%s: attach pdev 0x%p - card_ptr 0x%p\n",
-                      __func__, pdev, (void *)card_ptr));
-
-       if (!card_ptr)
-               return -ENODEV;
-
-       /* once around for each logical port on this card */
-       for (ii = 0; ii < LOGICAL_PORTS_PER_CARD; ii++) {
-               phys_port = GET_PHYSICAL_PORT(ii);
-               the_port = &card_ptr->ic_port[phys_port].
-                               icp_uart_port[GET_LOGICAL_PORT(ii)];
-               port = card_ptr->ic_port[phys_port].icp_port;
-               port->ip_port = the_port;
-
-               DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p [%d/%d]\n",
-                       __func__, (void *)the_port, (void *)port,
-                               phys_port, ii));
-
-               /* membase, iobase and mapbase just need to be non-0 */
-               the_port->membase = (unsigned char __iomem *)1;
-               the_port->iobase = (pdev->bus->number << 16) |  ii;
-               the_port->line = (Num_of_ioc3_cards << 2) | ii;
-               the_port->mapbase = 1;
-               the_port->type = PORT_16550A;
-               the_port->fifosize = FIFO_SIZE;
-               the_port->ops = &ioc3_ops;
-               the_port->irq = idd->irq_io;
-               the_port->dev = &pdev->dev;
-
-               if (uart_add_one_port(&ioc3_uart, the_port) < 0) {
-                       printk(KERN_WARNING
-                         "%s: unable to add port %d bus %d\n",
-                              __func__, the_port->line, pdev->bus->number);
-               } else {
-                       DPRINT_CONFIG(("IOC3 serial port %d irq %d bus %d\n",
-                         the_port->line, the_port->irq, pdev->bus->number));
-               }
-
-               /* all ports are rs232 for now */
-               if (IS_PHYSICAL_PORT(ii))
-                       ioc3_set_proto(port, PROTO_RS232);
-       }
-       return 0;
-}
-
-/**
- * ioc3uart_remove - register detach function
- * @is: submodule struct for this submodule
- * @idd: ioc3 driver data for this submodule
- */
-
-static int ioc3uart_remove(struct ioc3_submodule *is,
-                       struct ioc3_driver_data *idd)
-{
-       struct ioc3_card *card_ptr = idd->data[is->id];
-       struct uart_port *the_port;
-       struct ioc3_port *port;
-       int ii;
-
-       if (card_ptr) {
-               for (ii = 0; ii < LOGICAL_PORTS_PER_CARD; ii++) {
-                       the_port = &card_ptr->ic_port[GET_PHYSICAL_PORT(ii)].
-                                       icp_uart_port[GET_LOGICAL_PORT(ii)];
-                       if (the_port)
-                               uart_remove_one_port(&ioc3_uart, the_port);
-                       port = card_ptr->ic_port[GET_PHYSICAL_PORT(ii)].icp_port;
-                       if (port && IS_PHYSICAL_PORT(ii)
-                                       && (GET_PHYSICAL_PORT(ii) == 0)) {
-                               pci_free_consistent(port->ip_idd->pdev,
-                                       TOTAL_RING_BUF_SIZE,
-                                       (void *)port->ip_cpu_ringbuf,
-                                       port->ip_dma_ringbuf);
-                               kfree(port);
-                               card_ptr->ic_port[GET_PHYSICAL_PORT(ii)].
-                                                       icp_port = NULL;
-                       }
-               }
-               kfree(card_ptr);
-               idd->data[is->id] = NULL;
-       }
-       return 0;
-}
-
-/**
- * ioc3uart_probe - card probe function called from shim driver
- * @is: submodule struct for this submodule
- * @idd: ioc3 driver data for this card
- */
-
-static int __devinit
-ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
-{
-       struct pci_dev *pdev = idd->pdev;
-       struct ioc3_card *card_ptr;
-       int ret = 0;
-       struct ioc3_port *port;
-       struct ioc3_port *ports[PORTS_PER_CARD];
-       int phys_port;
-       int cnt;
-
-       DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, is, idd));
-
-       card_ptr = kzalloc(sizeof(struct ioc3_card), GFP_KERNEL);
-       if (!card_ptr) {
-               printk(KERN_WARNING "ioc3_attach_one"
-                      ": unable to get memory for the IOC3\n");
-               return -ENOMEM;
-       }
-       idd->data[is->id] = card_ptr;
-       Submodule_slot = is->id;
-
-       writel(((UARTA_BASE >> 3) << SIO_CR_SER_A_BASE_SHIFT) |
-               ((UARTB_BASE >> 3) << SIO_CR_SER_B_BASE_SHIFT) |
-               (0xf << SIO_CR_CMD_PULSE_SHIFT), &idd->vma->sio_cr);
-
-       pci_write_config_dword(pdev, PCI_LAT, 0xff00);
-
-       /* Enable serial port mode select generic PIO pins as outputs */
-       ioc3_gpcr_set(idd, GPCR_UARTA_MODESEL | GPCR_UARTB_MODESEL);
-
-       /* Create port structures for each port */
-       for (phys_port = 0; phys_port < PORTS_PER_CARD; phys_port++) {
-               port = kzalloc(sizeof(struct ioc3_port), GFP_KERNEL);
-               if (!port) {
-                       printk(KERN_WARNING
-                              "IOC3 serial memory not available for port\n");
-                       ret = -ENOMEM;
-                       goto out4;
-               }
-               spin_lock_init(&port->ip_lock);
-
-               /* we need to remember the previous ones, to point back to
-                * them farther down - setting up the ring buffers.
-                */
-               ports[phys_port] = port;
-
-               /* init to something useful */
-               card_ptr->ic_port[phys_port].icp_port = port;
-               port->ip_is = is;
-               port->ip_idd = idd;
-               port->ip_baud = 9600;
-               port->ip_card = card_ptr;
-               port->ip_hooks = &hooks_array[phys_port];
-
-               /* Setup each port */
-               if (phys_port == 0) {
-                       port->ip_serial_regs = &idd->vma->port_a;
-                       port->ip_uart_regs = &idd->vma->sregs.uarta;
-
-                       DPRINT_CONFIG(("%s : Port A ip_serial_regs 0x%p "
-                                      "ip_uart_regs 0x%p\n",
-                                      __func__,
-                                      (void *)port->ip_serial_regs,
-                                      (void *)port->ip_uart_regs));
-
-                       /* setup ring buffers */
-                       port->ip_cpu_ringbuf = pci_alloc_consistent(pdev,
-                               TOTAL_RING_BUF_SIZE, &port->ip_dma_ringbuf);
-
-                       BUG_ON(!((((int64_t) port->ip_dma_ringbuf) &
-                                 (TOTAL_RING_BUF_SIZE - 1)) == 0));
-                       port->ip_inring = RING(port, RX_A);
-                       port->ip_outring = RING(port, TX_A);
-                       DPRINT_CONFIG(("%s : Port A ip_cpu_ringbuf 0x%p "
-                                      "ip_dma_ringbuf 0x%p, ip_inring 0x%p "
-                                       "ip_outring 0x%p\n",
-                                      __func__,
-                                      (void *)port->ip_cpu_ringbuf,
-                                      (void *)port->ip_dma_ringbuf,
-                                      (void *)port->ip_inring,
-                                      (void *)port->ip_outring));
-               }
-               else {
-                       port->ip_serial_regs = &idd->vma->port_b;
-                       port->ip_uart_regs = &idd->vma->sregs.uartb;
-
-                       DPRINT_CONFIG(("%s : Port B ip_serial_regs 0x%p "
-                                      "ip_uart_regs 0x%p\n",
-                                      __func__,
-                                      (void *)port->ip_serial_regs,
-                                      (void *)port->ip_uart_regs));
-
-                       /* share the ring buffers */
-                       port->ip_dma_ringbuf =
-                           ports[phys_port - 1]->ip_dma_ringbuf;
-                       port->ip_cpu_ringbuf =
-                           ports[phys_port - 1]->ip_cpu_ringbuf;
-                       port->ip_inring = RING(port, RX_B);
-                       port->ip_outring = RING(port, TX_B);
-                       DPRINT_CONFIG(("%s : Port B ip_cpu_ringbuf 0x%p "
-                                      "ip_dma_ringbuf 0x%p, ip_inring 0x%p "
-                                       "ip_outring 0x%p\n",
-                                      __func__,
-                                      (void *)port->ip_cpu_ringbuf,
-                                      (void *)port->ip_dma_ringbuf,
-                                      (void *)port->ip_inring,
-                                      (void *)port->ip_outring));
-               }
-
-               DPRINT_CONFIG(("%s : port %d [addr 0x%p] card_ptr 0x%p",
-                              __func__,
-                              phys_port, (void *)port, (void *)card_ptr));
-               DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n",
-                              (void *)port->ip_serial_regs,
-                              (void *)port->ip_uart_regs));
-
-               /* Initialize the hardware for IOC3 */
-               port_init(port);
-
-               DPRINT_CONFIG(("%s: phys_port %d port 0x%p inring 0x%p "
-                              "outring 0x%p\n",
-                              __func__,
-                              phys_port, (void *)port,
-                              (void *)port->ip_inring,
-                              (void *)port->ip_outring));
-
-       }
-
-       /* register port with the serial core */
-
-       if ((ret = ioc3_serial_core_attach(is, idd)))
-               goto out4;
-
-       Num_of_ioc3_cards++;
-
-       return ret;
-
-       /* error exits that give back resources */
-out4:
-       for (cnt = 0; cnt < phys_port; cnt++)
-               kfree(ports[cnt]);
-
-       kfree(card_ptr);
-       return ret;
-}
-
-static struct ioc3_submodule ioc3uart_ops = {
-       .name = "IOC3uart",
-       .probe = ioc3uart_probe,
-       .remove = ioc3uart_remove,
-       /* call .intr for both ports initially */
-       .irq_mask = SIO_IR_SA | SIO_IR_SB,
-       .intr = ioc3uart_intr,
-       .owner = THIS_MODULE,
-};
-
-/**
- * ioc3_detect - module init called,
- */
-static int __init ioc3uart_init(void)
-{
-       int ret;
-
-       /* register with serial core */
-       if ((ret = uart_register_driver(&ioc3_uart)) < 0) {
-               printk(KERN_WARNING
-                      "%s: Couldn't register IOC3 uart serial driver\n",
-                      __func__);
-               return ret;
-       }
-       ret = ioc3_register_submodule(&ioc3uart_ops);
-       if (ret)
-               uart_unregister_driver(&ioc3_uart);
-       return ret;
-}
-
-static void __exit ioc3uart_exit(void)
-{
-       ioc3_unregister_submodule(&ioc3uart_ops);
-       uart_unregister_driver(&ioc3_uart);
-}
-
-module_init(ioc3uart_init);
-module_exit(ioc3uart_exit);
-
-MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) <pfg@sgi.com>");
-MODULE_DESCRIPTION("Serial PCI driver module for SGI IOC3 card");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c
deleted file mode 100644 (file)
index fcfe826..0000000
+++ /dev/null
@@ -1,2953 +0,0 @@
-/*
- * 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.
- *
- * Copyright (C) 2003-2006 Silicon Graphics, Inc.  All Rights Reserved.
- */
-
-
-/*
- * This file contains a module version of the ioc4 serial driver. This
- * includes all the support functions needed (support functions, etc.)
- * and the serial driver itself.
- */
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/serial.h>
-#include <linux/serialP.h>
-#include <linux/circ_buf.h>
-#include <linux/serial_reg.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/ioc4.h>
-#include <linux/serial_core.h>
-#include <linux/slab.h>
-
-/*
- * interesting things about the ioc4
- */
-
-#define IOC4_NUM_SERIAL_PORTS  4       /* max ports per card */
-#define IOC4_NUM_CARDS         8       /* max cards per partition */
-
-#define        GET_SIO_IR(_n)  (_n == 0) ? (IOC4_SIO_IR_S0) : \
-                               (_n == 1) ? (IOC4_SIO_IR_S1) : \
-                               (_n == 2) ? (IOC4_SIO_IR_S2) : \
-                               (IOC4_SIO_IR_S3)
-
-#define        GET_OTHER_IR(_n)  (_n == 0) ? (IOC4_OTHER_IR_S0_MEMERR) : \
-                               (_n == 1) ? (IOC4_OTHER_IR_S1_MEMERR) : \
-                               (_n == 2) ? (IOC4_OTHER_IR_S2_MEMERR) : \
-                               (IOC4_OTHER_IR_S3_MEMERR)
-
-
-/*
- * All IOC4 registers are 32 bits wide.
- */
-
-/*
- * PCI Memory Space Map
- */
-#define IOC4_PCI_ERR_ADDR_L     0x000  /* Low Error Address */
-#define IOC4_PCI_ERR_ADDR_VLD          (0x1 << 0)
-#define IOC4_PCI_ERR_ADDR_MST_ID_MSK    (0xf << 1)
-#define IOC4_PCI_ERR_ADDR_MST_NUM_MSK   (0xe << 1)
-#define IOC4_PCI_ERR_ADDR_MST_TYP_MSK   (0x1 << 1)
-#define IOC4_PCI_ERR_ADDR_MUL_ERR       (0x1 << 5)
-#define IOC4_PCI_ERR_ADDR_ADDR_MSK      (0x3ffffff << 6)
-
-/* Interrupt types */
-#define        IOC4_SIO_INTR_TYPE      0
-#define        IOC4_OTHER_INTR_TYPE    1
-#define        IOC4_NUM_INTR_TYPES     2
-
-/* Bitmasks for IOC4_SIO_IR, IOC4_SIO_IEC, and IOC4_SIO_IES  */
-#define IOC4_SIO_IR_S0_TX_MT      0x00000001   /* Serial port 0 TX empty */
-#define IOC4_SIO_IR_S0_RX_FULL    0x00000002   /* Port 0 RX buf full */
-#define IOC4_SIO_IR_S0_RX_HIGH    0x00000004   /* Port 0 RX hiwat */
-#define IOC4_SIO_IR_S0_RX_TIMER           0x00000008   /* Port 0 RX timeout */
-#define IOC4_SIO_IR_S0_DELTA_DCD   0x00000010  /* Port 0 delta DCD */
-#define IOC4_SIO_IR_S0_DELTA_CTS   0x00000020  /* Port 0 delta CTS */
-#define IOC4_SIO_IR_S0_INT        0x00000040   /* Port 0 pass-thru intr */
-#define IOC4_SIO_IR_S0_TX_EXPLICIT 0x00000080  /* Port 0 explicit TX thru */
-#define IOC4_SIO_IR_S1_TX_MT      0x00000100   /* Serial port 1 */
-#define IOC4_SIO_IR_S1_RX_FULL    0x00000200   /* */
-#define IOC4_SIO_IR_S1_RX_HIGH    0x00000400   /* */
-#define IOC4_SIO_IR_S1_RX_TIMER           0x00000800   /* */
-#define IOC4_SIO_IR_S1_DELTA_DCD   0x00001000  /* */
-#define IOC4_SIO_IR_S1_DELTA_CTS   0x00002000  /* */
-#define IOC4_SIO_IR_S1_INT        0x00004000   /* */
-#define IOC4_SIO_IR_S1_TX_EXPLICIT 0x00008000  /* */
-#define IOC4_SIO_IR_S2_TX_MT      0x00010000   /* Serial port 2 */
-#define IOC4_SIO_IR_S2_RX_FULL    0x00020000   /* */
-#define IOC4_SIO_IR_S2_RX_HIGH    0x00040000   /* */
-#define IOC4_SIO_IR_S2_RX_TIMER           0x00080000   /* */
-#define IOC4_SIO_IR_S2_DELTA_DCD   0x00100000  /* */
-#define IOC4_SIO_IR_S2_DELTA_CTS   0x00200000  /* */
-#define IOC4_SIO_IR_S2_INT        0x00400000   /* */
-#define IOC4_SIO_IR_S2_TX_EXPLICIT 0x00800000  /* */
-#define IOC4_SIO_IR_S3_TX_MT      0x01000000   /* Serial port 3 */
-#define IOC4_SIO_IR_S3_RX_FULL    0x02000000   /* */
-#define IOC4_SIO_IR_S3_RX_HIGH    0x04000000   /* */
-#define IOC4_SIO_IR_S3_RX_TIMER           0x08000000   /* */
-#define IOC4_SIO_IR_S3_DELTA_DCD   0x10000000  /* */
-#define IOC4_SIO_IR_S3_DELTA_CTS   0x20000000  /* */
-#define IOC4_SIO_IR_S3_INT        0x40000000   /* */
-#define IOC4_SIO_IR_S3_TX_EXPLICIT 0x80000000  /* */
-
-/* Per device interrupt masks */
-#define IOC4_SIO_IR_S0         (IOC4_SIO_IR_S0_TX_MT | \
-                                IOC4_SIO_IR_S0_RX_FULL | \
-                                IOC4_SIO_IR_S0_RX_HIGH | \
-                                IOC4_SIO_IR_S0_RX_TIMER | \
-                                IOC4_SIO_IR_S0_DELTA_DCD | \
-                                IOC4_SIO_IR_S0_DELTA_CTS | \
-                                IOC4_SIO_IR_S0_INT | \
-                                IOC4_SIO_IR_S0_TX_EXPLICIT)
-#define IOC4_SIO_IR_S1         (IOC4_SIO_IR_S1_TX_MT | \
-                                IOC4_SIO_IR_S1_RX_FULL | \
-                                IOC4_SIO_IR_S1_RX_HIGH | \
-                                IOC4_SIO_IR_S1_RX_TIMER | \
-                                IOC4_SIO_IR_S1_DELTA_DCD | \
-                                IOC4_SIO_IR_S1_DELTA_CTS | \
-                                IOC4_SIO_IR_S1_INT | \
-                                IOC4_SIO_IR_S1_TX_EXPLICIT)
-#define IOC4_SIO_IR_S2         (IOC4_SIO_IR_S2_TX_MT | \
-                                IOC4_SIO_IR_S2_RX_FULL | \
-                                IOC4_SIO_IR_S2_RX_HIGH | \
-                                IOC4_SIO_IR_S2_RX_TIMER | \
-                                IOC4_SIO_IR_S2_DELTA_DCD | \
-                                IOC4_SIO_IR_S2_DELTA_CTS | \
-                                IOC4_SIO_IR_S2_INT | \
-                                IOC4_SIO_IR_S2_TX_EXPLICIT)
-#define IOC4_SIO_IR_S3         (IOC4_SIO_IR_S3_TX_MT | \
-                                IOC4_SIO_IR_S3_RX_FULL | \
-                                IOC4_SIO_IR_S3_RX_HIGH | \
-                                IOC4_SIO_IR_S3_RX_TIMER | \
-                                IOC4_SIO_IR_S3_DELTA_DCD | \
-                                IOC4_SIO_IR_S3_DELTA_CTS | \
-                                IOC4_SIO_IR_S3_INT | \
-                                IOC4_SIO_IR_S3_TX_EXPLICIT)
-
-/* Bitmasks for IOC4_OTHER_IR, IOC4_OTHER_IEC, and IOC4_OTHER_IES  */
-#define IOC4_OTHER_IR_ATA_INT          0x00000001  /* ATAPI intr pass-thru */
-#define IOC4_OTHER_IR_ATA_MEMERR       0x00000002  /* ATAPI DMA PCI error */
-#define IOC4_OTHER_IR_S0_MEMERR                0x00000004  /* Port 0 PCI error */
-#define IOC4_OTHER_IR_S1_MEMERR                0x00000008  /* Port 1 PCI error */
-#define IOC4_OTHER_IR_S2_MEMERR                0x00000010  /* Port 2 PCI error */
-#define IOC4_OTHER_IR_S3_MEMERR                0x00000020  /* Port 3 PCI error */
-#define IOC4_OTHER_IR_KBD_INT          0x00000040  /* Keyboard/mouse */
-#define IOC4_OTHER_IR_RESERVED         0x007fff80  /* Reserved */
-#define IOC4_OTHER_IR_RT_INT           0x00800000  /* INT_OUT section output */
-#define IOC4_OTHER_IR_GEN_INT          0xff000000  /* Generic pins */
-
-#define IOC4_OTHER_IR_SER_MEMERR (IOC4_OTHER_IR_S0_MEMERR | IOC4_OTHER_IR_S1_MEMERR | \
-                                 IOC4_OTHER_IR_S2_MEMERR | IOC4_OTHER_IR_S3_MEMERR)
-
-/* Bitmasks for IOC4_SIO_CR */
-#define IOC4_SIO_CR_CMD_PULSE_SHIFT              0  /* byte bus strobe shift */
-#define IOC4_SIO_CR_ARB_DIAG_TX0       0x00000000
-#define IOC4_SIO_CR_ARB_DIAG_RX0       0x00000010
-#define IOC4_SIO_CR_ARB_DIAG_TX1       0x00000020
-#define IOC4_SIO_CR_ARB_DIAG_RX1       0x00000030
-#define IOC4_SIO_CR_ARB_DIAG_TX2       0x00000040
-#define IOC4_SIO_CR_ARB_DIAG_RX2       0x00000050
-#define IOC4_SIO_CR_ARB_DIAG_TX3       0x00000060
-#define IOC4_SIO_CR_ARB_DIAG_RX3       0x00000070
-#define IOC4_SIO_CR_SIO_DIAG_IDLE      0x00000080  /* 0 -> active request among
-                                                          serial ports (ro) */
-/* Defs for some of the generic I/O pins */
-#define IOC4_GPCR_UART0_MODESEL           0x10 /* Pin is output to port 0
-                                                  mode sel */
-#define IOC4_GPCR_UART1_MODESEL           0x20 /* Pin is output to port 1
-                                                  mode sel */
-#define IOC4_GPCR_UART2_MODESEL           0x40 /* Pin is output to port 2
-                                                  mode sel */
-#define IOC4_GPCR_UART3_MODESEL           0x80 /* Pin is output to port 3
-                                                  mode sel */
-
-#define IOC4_GPPR_UART0_MODESEL_PIN   4        /* GIO pin controlling
-                                          uart 0 mode select */
-#define IOC4_GPPR_UART1_MODESEL_PIN   5        /* GIO pin controlling
-                                          uart 1 mode select */
-#define IOC4_GPPR_UART2_MODESEL_PIN   6        /* GIO pin controlling
-                                          uart 2 mode select */
-#define IOC4_GPPR_UART3_MODESEL_PIN   7        /* GIO pin controlling
-                                          uart 3 mode select */
-
-/* Bitmasks for serial RX status byte */
-#define IOC4_RXSB_OVERRUN       0x01   /* Char(s) lost */
-#define IOC4_RXSB_PAR_ERR      0x02    /* Parity error */
-#define IOC4_RXSB_FRAME_ERR    0x04    /* Framing error */
-#define IOC4_RXSB_BREAK                0x08    /* Break character */
-#define IOC4_RXSB_CTS          0x10    /* State of CTS */
-#define IOC4_RXSB_DCD          0x20    /* State of DCD */
-#define IOC4_RXSB_MODEM_VALID   0x40   /* DCD, CTS, and OVERRUN are valid */
-#define IOC4_RXSB_DATA_VALID    0x80   /* Data byte, FRAME_ERR PAR_ERR
-                                        * & BREAK valid */
-
-/* Bitmasks for serial TX control byte */
-#define IOC4_TXCB_INT_WHEN_DONE 0x20   /* Interrupt after this byte is sent */
-#define IOC4_TXCB_INVALID      0x00    /* Byte is invalid */
-#define IOC4_TXCB_VALID                0x40    /* Byte is valid */
-#define IOC4_TXCB_MCR          0x80    /* Data<7:0> to modem control reg */
-#define IOC4_TXCB_DELAY                0xc0    /* Delay data<7:0> mSec */
-
-/* Bitmasks for IOC4_SBBR_L */
-#define IOC4_SBBR_L_SIZE       0x00000001  /* 0 == 1KB rings, 1 == 4KB rings */
-
-/* Bitmasks for IOC4_SSCR_<3:0> */
-#define IOC4_SSCR_RX_THRESHOLD  0x000001ff  /* Hiwater mark */
-#define IOC4_SSCR_TX_TIMER_BUSY 0x00010000  /* TX timer in progress */
-#define IOC4_SSCR_HFC_EN       0x00020000  /* Hardware flow control enabled */
-#define IOC4_SSCR_RX_RING_DCD   0x00040000  /* Post RX record on delta-DCD */
-#define IOC4_SSCR_RX_RING_CTS   0x00080000  /* Post RX record on delta-CTS */
-#define IOC4_SSCR_DIAG         0x00200000  /* Bypass clock divider for sim */
-#define IOC4_SSCR_RX_DRAIN     0x08000000  /* Drain RX buffer to memory */
-#define IOC4_SSCR_DMA_EN       0x10000000  /* Enable ring buffer DMA */
-#define IOC4_SSCR_DMA_PAUSE    0x20000000  /* Pause DMA */
-#define IOC4_SSCR_PAUSE_STATE   0x40000000  /* Sets when PAUSE takes effect */
-#define IOC4_SSCR_RESET                0x80000000  /* Reset DMA channels */
-
-/* All producer/comsumer pointers are the same bitfield */
-#define IOC4_PROD_CONS_PTR_4K   0x00000ff8     /* For 4K buffers */
-#define IOC4_PROD_CONS_PTR_1K   0x000003f8     /* For 1K buffers */
-#define IOC4_PROD_CONS_PTR_OFF           3
-
-/* Bitmasks for IOC4_SRCIR_<3:0> */
-#define IOC4_SRCIR_ARM         0x80000000      /* Arm RX timer */
-
-/* Bitmasks for IOC4_SHADOW_<3:0> */
-#define IOC4_SHADOW_DR  0x00000001     /* Data ready */
-#define IOC4_SHADOW_OE  0x00000002     /* Overrun error */
-#define IOC4_SHADOW_PE  0x00000004     /* Parity error */
-#define IOC4_SHADOW_FE  0x00000008     /* Framing error */
-#define IOC4_SHADOW_BI  0x00000010     /* Break interrupt */
-#define IOC4_SHADOW_THRE 0x00000020    /* Xmit holding register empty */
-#define IOC4_SHADOW_TEMT 0x00000040    /* Xmit shift register empty */
-#define IOC4_SHADOW_RFCE 0x00000080    /* Char in RX fifo has an error */
-#define IOC4_SHADOW_DCTS 0x00010000    /* Delta clear to send */
-#define IOC4_SHADOW_DDCD 0x00080000    /* Delta data carrier detect */
-#define IOC4_SHADOW_CTS         0x00100000     /* Clear to send */
-#define IOC4_SHADOW_DCD         0x00800000     /* Data carrier detect */
-#define IOC4_SHADOW_DTR         0x01000000     /* Data terminal ready */
-#define IOC4_SHADOW_RTS         0x02000000     /* Request to send */
-#define IOC4_SHADOW_OUT1 0x04000000    /* 16550 OUT1 bit */
-#define IOC4_SHADOW_OUT2 0x08000000    /* 16550 OUT2 bit */
-#define IOC4_SHADOW_LOOP 0x10000000    /* Loopback enabled */
-
-/* Bitmasks for IOC4_SRTR_<3:0> */
-#define IOC4_SRTR_CNT          0x00000fff      /* Reload value for RX timer */
-#define IOC4_SRTR_CNT_VAL      0x0fff0000      /* Current value of RX timer */
-#define IOC4_SRTR_CNT_VAL_SHIFT         16
-#define IOC4_SRTR_HZ                 16000     /* SRTR clock frequency */
-
-/* Serial port register map used for DMA and PIO serial I/O */
-struct ioc4_serialregs {
-       uint32_t sscr;
-       uint32_t stpir;
-       uint32_t stcir;
-       uint32_t srpir;
-       uint32_t srcir;
-       uint32_t srtr;
-       uint32_t shadow;
-};
-
-/* IOC4 UART register map */
-struct ioc4_uartregs {
-       char i4u_lcr;
-       union {
-               char iir;       /* read only */
-               char fcr;       /* write only */
-       } u3;
-       union {
-               char ier;       /* DLAB == 0 */
-               char dlm;       /* DLAB == 1 */
-       } u2;
-       union {
-               char rbr;       /* read only, DLAB == 0 */
-               char thr;       /* write only, DLAB == 0 */
-               char dll;       /* DLAB == 1 */
-       } u1;
-       char i4u_scr;
-       char i4u_msr;
-       char i4u_lsr;
-       char i4u_mcr;
-};
-
-/* short names */
-#define i4u_dll u1.dll
-#define i4u_ier u2.ier
-#define i4u_dlm u2.dlm
-#define i4u_fcr u3.fcr
-
-/* Serial port registers used for DMA serial I/O */
-struct ioc4_serial {
-       uint32_t sbbr01_l;
-       uint32_t sbbr01_h;
-       uint32_t sbbr23_l;
-       uint32_t sbbr23_h;
-
-       struct ioc4_serialregs port_0;
-       struct ioc4_serialregs port_1;
-       struct ioc4_serialregs port_2;
-       struct ioc4_serialregs port_3;
-       struct ioc4_uartregs uart_0;
-       struct ioc4_uartregs uart_1;
-       struct ioc4_uartregs uart_2;
-       struct ioc4_uartregs uart_3;
-} ioc4_serial;
-
-/* UART clock speed */
-#define IOC4_SER_XIN_CLK_66     66666667
-#define IOC4_SER_XIN_CLK_33     33333333
-
-#define IOC4_W_IES             0
-#define IOC4_W_IEC             1
-
-typedef void ioc4_intr_func_f(void *, uint32_t);
-typedef ioc4_intr_func_f *ioc4_intr_func_t;
-
-static unsigned int Num_of_ioc4_cards;
-
-/* defining this will get you LOTS of great debug info */
-//#define DEBUG_INTERRUPTS
-#define DPRINT_CONFIG(_x...)   ;
-//#define DPRINT_CONFIG(_x...) printk _x
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS   256
-
-/* number of characters we want to transmit to the lower level at a time */
-#define IOC4_MAX_CHARS 256
-#define IOC4_FIFO_CHARS        255
-
-/* Device name we're using */
-#define DEVICE_NAME_RS232  "ttyIOC"
-#define DEVICE_NAME_RS422  "ttyAIOC"
-#define DEVICE_MAJOR      204
-#define DEVICE_MINOR_RS232 50
-#define DEVICE_MINOR_RS422 84
-
-
-/* register offsets */
-#define IOC4_SERIAL_OFFSET     0x300
-
-/* flags for next_char_state */
-#define NCS_BREAK      0x1
-#define NCS_PARITY     0x2
-#define NCS_FRAMING    0x4
-#define NCS_OVERRUN    0x8
-
-/* cause we need SOME parameters ... */
-#define MIN_BAUD_SUPPORTED     1200
-#define MAX_BAUD_SUPPORTED     115200
-
-/* protocol types supported */
-#define PROTO_RS232    3
-#define PROTO_RS422    7
-
-/* Notification types */
-#define N_DATA_READY   0x01
-#define N_OUTPUT_LOWAT 0x02
-#define N_BREAK                0x04
-#define N_PARITY_ERROR 0x08
-#define N_FRAMING_ERROR        0x10
-#define N_OVERRUN_ERROR        0x20
-#define N_DDCD         0x40
-#define N_DCTS         0x80
-
-#define N_ALL_INPUT    (N_DATA_READY | N_BREAK |                       \
-                        N_PARITY_ERROR | N_FRAMING_ERROR |             \
-                        N_OVERRUN_ERROR | N_DDCD | N_DCTS)
-
-#define N_ALL_OUTPUT   N_OUTPUT_LOWAT
-
-#define N_ALL_ERRORS   (N_PARITY_ERROR | N_FRAMING_ERROR | N_OVERRUN_ERROR)
-
-#define N_ALL          (N_DATA_READY | N_OUTPUT_LOWAT | N_BREAK |      \
-                        N_PARITY_ERROR | N_FRAMING_ERROR |             \
-                        N_OVERRUN_ERROR | N_DDCD | N_DCTS)
-
-#define SER_DIVISOR(_x, clk)           (((clk) + (_x) * 8) / ((_x) * 16))
-#define DIVISOR_TO_BAUD(div, clk)      ((clk) / 16 / (div))
-
-/* Some masks */
-#define LCR_MASK_BITS_CHAR     (UART_LCR_WLEN5 | UART_LCR_WLEN6 \
-                                       | UART_LCR_WLEN7 | UART_LCR_WLEN8)
-#define LCR_MASK_STOP_BITS     (UART_LCR_STOP)
-
-#define PENDING(_p)    (readl(&(_p)->ip_mem->sio_ir.raw) & _p->ip_ienb)
-#define READ_SIO_IR(_p) readl(&(_p)->ip_mem->sio_ir.raw)
-
-/* Default to 4k buffers */
-#ifdef IOC4_1K_BUFFERS
-#define RING_BUF_SIZE 1024
-#define IOC4_BUF_SIZE_BIT 0
-#define PROD_CONS_MASK IOC4_PROD_CONS_PTR_1K
-#else
-#define RING_BUF_SIZE 4096
-#define IOC4_BUF_SIZE_BIT IOC4_SBBR_L_SIZE
-#define PROD_CONS_MASK IOC4_PROD_CONS_PTR_4K
-#endif
-
-#define TOTAL_RING_BUF_SIZE (RING_BUF_SIZE * 4)
-
-/*
- * This is the entry saved by the driver - one per card
- */
-
-#define UART_PORT_MIN          0
-#define UART_PORT_RS232                UART_PORT_MIN
-#define UART_PORT_RS422                1
-#define UART_PORT_COUNT                2       /* one for each mode */
-
-struct ioc4_control {
-       int ic_irq;
-       struct {
-               /* uart ports are allocated here - 1 for rs232, 1 for rs422 */
-               struct uart_port icp_uart_port[UART_PORT_COUNT];
-               /* Handy reference material */
-               struct ioc4_port *icp_port;
-       } ic_port[IOC4_NUM_SERIAL_PORTS];
-       struct ioc4_soft *ic_soft;
-};
-
-/*
- * per-IOC4 data structure
- */
-#define MAX_IOC4_INTR_ENTS     (8 * sizeof(uint32_t))
-struct ioc4_soft {
-       struct ioc4_misc_regs __iomem *is_ioc4_misc_addr;
-       struct ioc4_serial __iomem *is_ioc4_serial_addr;
-
-       /* Each interrupt type has an entry in the array */
-       struct ioc4_intr_type {
-
-               /*
-                * Each in-use entry in this array contains at least
-                * one nonzero bit in sd_bits; no two entries in this
-                * array have overlapping sd_bits values.
-                */
-               struct ioc4_intr_info {
-                       uint32_t sd_bits;
-                       ioc4_intr_func_f *sd_intr;
-                       void *sd_info;
-               } is_intr_info[MAX_IOC4_INTR_ENTS];
-
-               /* Number of entries active in the above array */
-               atomic_t is_num_intrs;
-       } is_intr_type[IOC4_NUM_INTR_TYPES];
-
-       /* is_ir_lock must be held while
-        * modifying sio_ie values, so
-        * we can be sure that sio_ie is
-        * not changing when we read it
-        * along with sio_ir.
-        */
-       spinlock_t is_ir_lock;  /* SIO_IE[SC] mod lock */
-};
-
-/* Local port info for each IOC4 serial ports */
-struct ioc4_port {
-       struct uart_port *ip_port;      /* current active port ptr */
-       /* Ptrs for all ports */
-       struct uart_port *ip_all_ports[UART_PORT_COUNT];
-       /* Back ptrs for this port */
-       struct ioc4_control *ip_control;
-       struct pci_dev *ip_pdev;
-       struct ioc4_soft *ip_ioc4_soft;
-
-       /* pci mem addresses */
-       struct ioc4_misc_regs __iomem *ip_mem;
-       struct ioc4_serial __iomem *ip_serial;
-       struct ioc4_serialregs __iomem *ip_serial_regs;
-       struct ioc4_uartregs __iomem *ip_uart_regs;
-
-       /* Ring buffer page for this port */
-       dma_addr_t ip_dma_ringbuf;
-       /* vaddr of ring buffer */
-       struct ring_buffer *ip_cpu_ringbuf;
-
-       /* Rings for this port */
-       struct ring *ip_inring;
-       struct ring *ip_outring;
-
-       /* Hook to port specific values */
-       struct hooks *ip_hooks;
-
-       spinlock_t ip_lock;
-
-       /* Various rx/tx parameters */
-       int ip_baud;
-       int ip_tx_lowat;
-       int ip_rx_timeout;
-
-       /* Copy of notification bits */
-       int ip_notify;
-
-       /* Shadow copies of various registers so we don't need to PIO
-        * read them constantly
-        */
-       uint32_t ip_ienb;       /* Enabled interrupts */
-       uint32_t ip_sscr;
-       uint32_t ip_tx_prod;
-       uint32_t ip_rx_cons;
-       int ip_pci_bus_speed;
-       unsigned char ip_flags;
-};
-
-/* tx low water mark.  We need to notify the driver whenever tx is getting
- * close to empty so it can refill the tx buffer and keep things going.
- * Let's assume that if we interrupt 1 ms before the tx goes idle, we'll
- * have no trouble getting in more chars in time (I certainly hope so).
- */
-#define TX_LOWAT_LATENCY      1000
-#define TX_LOWAT_HZ          (1000000 / TX_LOWAT_LATENCY)
-#define TX_LOWAT_CHARS(baud) (baud / 10 / TX_LOWAT_HZ)
-
-/* Flags per port */
-#define INPUT_HIGH     0x01
-#define DCD_ON         0x02
-#define LOWAT_WRITTEN  0x04
-#define READ_ABORTED   0x08
-#define PORT_ACTIVE    0x10
-#define PORT_INACTIVE  0       /* This is the value when "off" */
-
-
-/* Since each port has different register offsets and bitmasks
- * for everything, we'll store those that we need in tables so we
- * don't have to be constantly checking the port we are dealing with.
- */
-struct hooks {
-       uint32_t intr_delta_dcd;
-       uint32_t intr_delta_cts;
-       uint32_t intr_tx_mt;
-       uint32_t intr_rx_timer;
-       uint32_t intr_rx_high;
-       uint32_t intr_tx_explicit;
-       uint32_t intr_dma_error;
-       uint32_t intr_clear;
-       uint32_t intr_all;
-       int rs422_select_pin;
-};
-
-static struct hooks hooks_array[IOC4_NUM_SERIAL_PORTS] = {
-       /* Values for port 0 */
-       {
-        IOC4_SIO_IR_S0_DELTA_DCD, IOC4_SIO_IR_S0_DELTA_CTS,
-        IOC4_SIO_IR_S0_TX_MT, IOC4_SIO_IR_S0_RX_TIMER,
-        IOC4_SIO_IR_S0_RX_HIGH, IOC4_SIO_IR_S0_TX_EXPLICIT,
-        IOC4_OTHER_IR_S0_MEMERR,
-        (IOC4_SIO_IR_S0_TX_MT | IOC4_SIO_IR_S0_RX_FULL |
-         IOC4_SIO_IR_S0_RX_HIGH | IOC4_SIO_IR_S0_RX_TIMER |
-         IOC4_SIO_IR_S0_DELTA_DCD | IOC4_SIO_IR_S0_DELTA_CTS |
-         IOC4_SIO_IR_S0_INT | IOC4_SIO_IR_S0_TX_EXPLICIT),
-        IOC4_SIO_IR_S0, IOC4_GPPR_UART0_MODESEL_PIN,
-        },
-
-       /* Values for port 1 */
-       {
-        IOC4_SIO_IR_S1_DELTA_DCD, IOC4_SIO_IR_S1_DELTA_CTS,
-        IOC4_SIO_IR_S1_TX_MT, IOC4_SIO_IR_S1_RX_TIMER,
-        IOC4_SIO_IR_S1_RX_HIGH, IOC4_SIO_IR_S1_TX_EXPLICIT,
-        IOC4_OTHER_IR_S1_MEMERR,
-        (IOC4_SIO_IR_S1_TX_MT | IOC4_SIO_IR_S1_RX_FULL |
-         IOC4_SIO_IR_S1_RX_HIGH | IOC4_SIO_IR_S1_RX_TIMER |
-         IOC4_SIO_IR_S1_DELTA_DCD | IOC4_SIO_IR_S1_DELTA_CTS |
-         IOC4_SIO_IR_S1_INT | IOC4_SIO_IR_S1_TX_EXPLICIT),
-        IOC4_SIO_IR_S1, IOC4_GPPR_UART1_MODESEL_PIN,
-        },
-
-       /* Values for port 2 */
-       {
-        IOC4_SIO_IR_S2_DELTA_DCD, IOC4_SIO_IR_S2_DELTA_CTS,
-        IOC4_SIO_IR_S2_TX_MT, IOC4_SIO_IR_S2_RX_TIMER,
-        IOC4_SIO_IR_S2_RX_HIGH, IOC4_SIO_IR_S2_TX_EXPLICIT,
-        IOC4_OTHER_IR_S2_MEMERR,
-        (IOC4_SIO_IR_S2_TX_MT | IOC4_SIO_IR_S2_RX_FULL |
-         IOC4_SIO_IR_S2_RX_HIGH | IOC4_SIO_IR_S2_RX_TIMER |
-         IOC4_SIO_IR_S2_DELTA_DCD | IOC4_SIO_IR_S2_DELTA_CTS |
-         IOC4_SIO_IR_S2_INT | IOC4_SIO_IR_S2_TX_EXPLICIT),
-        IOC4_SIO_IR_S2, IOC4_GPPR_UART2_MODESEL_PIN,
-        },
-
-       /* Values for port 3 */
-       {
-        IOC4_SIO_IR_S3_DELTA_DCD, IOC4_SIO_IR_S3_DELTA_CTS,
-        IOC4_SIO_IR_S3_TX_MT, IOC4_SIO_IR_S3_RX_TIMER,
-        IOC4_SIO_IR_S3_RX_HIGH, IOC4_SIO_IR_S3_TX_EXPLICIT,
-        IOC4_OTHER_IR_S3_MEMERR,
-        (IOC4_SIO_IR_S3_TX_MT | IOC4_SIO_IR_S3_RX_FULL |
-         IOC4_SIO_IR_S3_RX_HIGH | IOC4_SIO_IR_S3_RX_TIMER |
-         IOC4_SIO_IR_S3_DELTA_DCD | IOC4_SIO_IR_S3_DELTA_CTS |
-         IOC4_SIO_IR_S3_INT | IOC4_SIO_IR_S3_TX_EXPLICIT),
-        IOC4_SIO_IR_S3, IOC4_GPPR_UART3_MODESEL_PIN,
-        }
-};
-
-/* A ring buffer entry */
-struct ring_entry {
-       union {
-               struct {
-                       uint32_t alldata;
-                       uint32_t allsc;
-               } all;
-               struct {
-                       char data[4];   /* data bytes */
-                       char sc[4];     /* status/control */
-               } s;
-       } u;
-};
-
-/* Test the valid bits in any of the 4 sc chars using "allsc" member */
-#define RING_ANY_VALID \
-       ((uint32_t)(IOC4_RXSB_MODEM_VALID | IOC4_RXSB_DATA_VALID) * 0x01010101)
-
-#define ring_sc     u.s.sc
-#define ring_data   u.s.data
-#define ring_allsc  u.all.allsc
-
-/* Number of entries per ring buffer. */
-#define ENTRIES_PER_RING (RING_BUF_SIZE / (int) sizeof(struct ring_entry))
-
-/* An individual ring */
-struct ring {
-       struct ring_entry entries[ENTRIES_PER_RING];
-};
-
-/* The whole enchilada */
-struct ring_buffer {
-       struct ring TX_0_OR_2;
-       struct ring RX_0_OR_2;
-       struct ring TX_1_OR_3;
-       struct ring RX_1_OR_3;
-};
-
-/* Get a ring from a port struct */
-#define RING(_p, _wh)  &(((struct ring_buffer *)((_p)->ip_cpu_ringbuf))->_wh)
-
-/* Infinite loop detection.
- */
-#define MAXITER 10000000
-
-/* Prototypes */
-static void receive_chars(struct uart_port *);
-static void handle_intr(void *arg, uint32_t sio_ir);
-
-/*
- * port_is_active - determines if this port is currently active
- * @port: ptr to soft struct for this port
- * @uart_port: uart port to test for
- */
-static inline int port_is_active(struct ioc4_port *port,
-               struct uart_port *uart_port)
-{
-       if (port) {
-               if ((port->ip_flags & PORT_ACTIVE)
-                                       && (port->ip_port == uart_port))
-                       return 1;
-       }
-       return 0;
-}
-
-
-/**
- * write_ireg - write the interrupt regs
- * @ioc4_soft: ptr to soft struct for this port
- * @val: value to write
- * @which: which register
- * @type: which ireg set
- */
-static inline void
-write_ireg(struct ioc4_soft *ioc4_soft, uint32_t val, int which, int type)
-{
-       struct ioc4_misc_regs __iomem *mem = ioc4_soft->is_ioc4_misc_addr;
-       unsigned long flags;
-
-       spin_lock_irqsave(&ioc4_soft->is_ir_lock, flags);
-
-       switch (type) {
-       case IOC4_SIO_INTR_TYPE:
-               switch (which) {
-               case IOC4_W_IES:
-                       writel(val, &mem->sio_ies.raw);
-                       break;
-
-               case IOC4_W_IEC:
-                       writel(val, &mem->sio_iec.raw);
-                       break;
-               }
-               break;
-
-       case IOC4_OTHER_INTR_TYPE:
-               switch (which) {
-               case IOC4_W_IES:
-                       writel(val, &mem->other_ies.raw);
-                       break;
-
-               case IOC4_W_IEC:
-                       writel(val, &mem->other_iec.raw);
-                       break;
-               }
-               break;
-
-       default:
-               break;
-       }
-       spin_unlock_irqrestore(&ioc4_soft->is_ir_lock, flags);
-}
-
-/**
- * set_baud - Baud rate setting code
- * @port: port to set
- * @baud: baud rate to use
- */
-static int set_baud(struct ioc4_port *port, int baud)
-{
-       int actual_baud;
-       int diff;
-       int lcr;
-       unsigned short divisor;
-       struct ioc4_uartregs __iomem *uart;
-
-       divisor = SER_DIVISOR(baud, port->ip_pci_bus_speed);
-       if (!divisor)
-               return 1;
-       actual_baud = DIVISOR_TO_BAUD(divisor, port->ip_pci_bus_speed);
-
-       diff = actual_baud - baud;
-       if (diff < 0)
-               diff = -diff;
-
-       /* If we're within 1%, we've found a match */
-       if (diff * 100 > actual_baud)
-               return 1;
-
-       uart = port->ip_uart_regs;
-       lcr = readb(&uart->i4u_lcr);
-       writeb(lcr | UART_LCR_DLAB, &uart->i4u_lcr);
-       writeb((unsigned char)divisor, &uart->i4u_dll);
-       writeb((unsigned char)(divisor >> 8), &uart->i4u_dlm);
-       writeb(lcr, &uart->i4u_lcr);
-       return 0;
-}
-
-
-/**
- * get_ioc4_port - given a uart port, return the control structure
- * @port: uart port
- * @set: set this port as current
- */
-static struct ioc4_port *get_ioc4_port(struct uart_port *the_port, int set)
-{
-       struct ioc4_driver_data *idd = dev_get_drvdata(the_port->dev);
-       struct ioc4_control *control = idd->idd_serial_data;
-       struct ioc4_port *port;
-       int port_num, port_type;
-
-       if (control) {
-               for ( port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS;
-                                                       port_num++ ) {
-                       port = control->ic_port[port_num].icp_port;
-                       if (!port)
-                               continue;
-                       for (port_type = UART_PORT_MIN;
-                                               port_type < UART_PORT_COUNT;
-                                               port_type++) {
-                               if (the_port == port->ip_all_ports
-                                                       [port_type]) {
-                                       /* set local copy */
-                                       if (set) {
-                                               port->ip_port = the_port;
-                                       }
-                                       return port;
-                               }
-                       }
-               }
-       }
-       return NULL;
-}
-
-/* The IOC4 hardware provides no atomic way to determine if interrupts
- * are pending since two reads are required to do so.  The handler must
- * read the SIO_IR and the SIO_IES, and take the logical and of the
- * two.  When this value is zero, all interrupts have been serviced and
- * the handler may return.
- *
- * This has the unfortunate "hole" that, if some other CPU or
- * some other thread or some higher level interrupt manages to
- * modify SIO_IE between our reads of SIO_IR and SIO_IE, we may
- * think we have observed SIO_IR&SIO_IE==0 when in fact this
- * condition never really occurred.
- *
- * To solve this, we use a simple spinlock that must be held
- * whenever modifying SIO_IE; holding this lock while observing
- * both SIO_IR and SIO_IE guarantees that we do not falsely
- * conclude that no enabled interrupts are pending.
- */
-
-static inline uint32_t
-pending_intrs(struct ioc4_soft *soft, int type)
-{
-       struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr;
-       unsigned long flag;
-       uint32_t intrs = 0;
-
-       BUG_ON(!((type == IOC4_SIO_INTR_TYPE)
-              || (type == IOC4_OTHER_INTR_TYPE)));
-
-       spin_lock_irqsave(&soft->is_ir_lock, flag);
-
-       switch (type) {
-       case IOC4_SIO_INTR_TYPE:
-               intrs = readl(&mem->sio_ir.raw) & readl(&mem->sio_ies.raw);
-               break;
-
-       case IOC4_OTHER_INTR_TYPE:
-               intrs = readl(&mem->other_ir.raw) & readl(&mem->other_ies.raw);
-
-               /* Don't process any ATA interrupte */
-               intrs &= ~(IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR);
-               break;
-
-       default:
-               break;
-       }
-       spin_unlock_irqrestore(&soft->is_ir_lock, flag);
-       return intrs;
-}
-
-/**
- * port_init - Initialize the sio and ioc4 hardware for a given port
- *                     called per port from attach...
- * @port: port to initialize
- */
-static int inline port_init(struct ioc4_port *port)
-{
-       uint32_t sio_cr;
-       struct hooks *hooks = port->ip_hooks;
-       struct ioc4_uartregs __iomem *uart;
-
-       /* Idle the IOC4 serial interface */
-       writel(IOC4_SSCR_RESET, &port->ip_serial_regs->sscr);
-
-       /* Wait until any pending bus activity for this port has ceased */
-       do
-               sio_cr = readl(&port->ip_mem->sio_cr.raw);
-       while (!(sio_cr & IOC4_SIO_CR_SIO_DIAG_IDLE));
-
-       /* Finish reset sequence */
-       writel(0, &port->ip_serial_regs->sscr);
-
-       /* Once RESET is done, reload cached tx_prod and rx_cons values
-        * and set rings to empty by making prod == cons
-        */
-       port->ip_tx_prod = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
-       writel(port->ip_tx_prod, &port->ip_serial_regs->stpir);
-       port->ip_rx_cons = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
-       writel(port->ip_rx_cons | IOC4_SRCIR_ARM, &port->ip_serial_regs->srcir);
-
-       /* Disable interrupts for this 16550 */
-       uart = port->ip_uart_regs;
-       writeb(0, &uart->i4u_lcr);
-       writeb(0, &uart->i4u_ier);
-
-       /* Set the default baud */
-       set_baud(port, port->ip_baud);
-
-       /* Set line control to 8 bits no parity */
-       writeb(UART_LCR_WLEN8 | 0, &uart->i4u_lcr);
-                                       /* UART_LCR_STOP == 1 stop */
-
-       /* Enable the FIFOs */
-       writeb(UART_FCR_ENABLE_FIFO, &uart->i4u_fcr);
-       /* then reset 16550 FIFOs */
-       writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
-                       &uart->i4u_fcr);
-
-       /* Clear modem control register */
-       writeb(0, &uart->i4u_mcr);
-
-       /* Clear deltas in modem status register */
-       readb(&uart->i4u_msr);
-
-       /* Only do this once per port pair */
-       if (port->ip_hooks == &hooks_array[0]
-                           || port->ip_hooks == &hooks_array[2]) {
-               unsigned long ring_pci_addr;
-               uint32_t __iomem *sbbr_l;
-               uint32_t __iomem *sbbr_h;
-
-               if (port->ip_hooks == &hooks_array[0]) {
-                       sbbr_l = &port->ip_serial->sbbr01_l;
-                       sbbr_h = &port->ip_serial->sbbr01_h;
-               } else {
-                       sbbr_l = &port->ip_serial->sbbr23_l;
-                       sbbr_h = &port->ip_serial->sbbr23_h;
-               }
-
-               ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf;
-               DPRINT_CONFIG(("%s: ring_pci_addr 0x%lx\n",
-                                       __func__, ring_pci_addr));
-
-               writel((unsigned int)((uint64_t)ring_pci_addr >> 32), sbbr_h);
-               writel((unsigned int)ring_pci_addr | IOC4_BUF_SIZE_BIT, sbbr_l);
-       }
-
-       /* Set the receive timeout value to 10 msec */
-       writel(IOC4_SRTR_HZ / 100, &port->ip_serial_regs->srtr);
-
-       /* Set rx threshold, enable DMA */
-       /* Set high water mark at 3/4 of full ring */
-       port->ip_sscr = (ENTRIES_PER_RING * 3 / 4);
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-
-       /* Disable and clear all serial related interrupt bits */
-       write_ireg(port->ip_ioc4_soft, hooks->intr_clear,
-                      IOC4_W_IEC, IOC4_SIO_INTR_TYPE);
-       port->ip_ienb &= ~hooks->intr_clear;
-       writel(hooks->intr_clear, &port->ip_mem->sio_ir.raw);
-       return 0;
-}
-
-/**
- * handle_dma_error_intr - service any pending DMA error interrupts for the
- *                     given port - 2nd level called via sd_intr
- * @arg: handler arg
- * @other_ir: ioc4regs
- */
-static void handle_dma_error_intr(void *arg, uint32_t other_ir)
-{
-       struct ioc4_port *port = (struct ioc4_port *)arg;
-       struct hooks *hooks = port->ip_hooks;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->ip_lock, flags);
-
-       /* ACK the interrupt */
-       writel(hooks->intr_dma_error, &port->ip_mem->other_ir.raw);
-
-       if (readl(&port->ip_mem->pci_err_addr_l.raw) & IOC4_PCI_ERR_ADDR_VLD) {
-               printk(KERN_ERR
-                       "PCI error address is 0x%llx, "
-                               "master is serial port %c %s\n",
-                    (((uint64_t)readl(&port->ip_mem->pci_err_addr_h)
-                                                        << 32)
-                               | readl(&port->ip_mem->pci_err_addr_l.raw))
-                                       & IOC4_PCI_ERR_ADDR_ADDR_MSK, '1' +
-                    ((char)(readl(&port->ip_mem->pci_err_addr_l.raw) &
-                            IOC4_PCI_ERR_ADDR_MST_NUM_MSK) >> 1),
-                    (readl(&port->ip_mem->pci_err_addr_l.raw)
-                               & IOC4_PCI_ERR_ADDR_MST_TYP_MSK)
-                               ? "RX" : "TX");
-
-               if (readl(&port->ip_mem->pci_err_addr_l.raw)
-                                               & IOC4_PCI_ERR_ADDR_MUL_ERR) {
-                       printk(KERN_ERR
-                               "Multiple errors occurred\n");
-               }
-       }
-       spin_unlock_irqrestore(&port->ip_lock, flags);
-
-       /* Re-enable DMA error interrupts */
-       write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error, IOC4_W_IES,
-                                               IOC4_OTHER_INTR_TYPE);
-}
-
-/**
- * intr_connect - interrupt connect function
- * @soft: soft struct for this card
- * @type: interrupt type
- * @intrbits: bit pattern to set
- * @intr: handler function
- * @info: handler arg
- */
-static void
-intr_connect(struct ioc4_soft *soft, int type,
-                 uint32_t intrbits, ioc4_intr_func_f * intr, void *info)
-{
-       int i;
-       struct ioc4_intr_info *intr_ptr;
-
-       BUG_ON(!((type == IOC4_SIO_INTR_TYPE)
-              || (type == IOC4_OTHER_INTR_TYPE)));
-
-       i = atomic_inc(&soft-> is_intr_type[type].is_num_intrs) - 1;
-       BUG_ON(!(i < MAX_IOC4_INTR_ENTS || (printk("i %d\n", i), 0)));
-
-       /* Save off the lower level interrupt handler */
-       intr_ptr = &soft->is_intr_type[type].is_intr_info[i];
-       intr_ptr->sd_bits = intrbits;
-       intr_ptr->sd_intr = intr;
-       intr_ptr->sd_info = info;
-}
-
-/**
- * ioc4_intr - Top level IOC4 interrupt handler.
- * @irq: irq value
- * @arg: handler arg
- */
-
-static irqreturn_t ioc4_intr(int irq, void *arg)
-{
-       struct ioc4_soft *soft;
-       uint32_t this_ir, this_mir;
-       int xx, num_intrs = 0;
-       int intr_type;
-       int handled = 0;
-       struct ioc4_intr_info *intr_info;
-
-       soft = arg;
-       for (intr_type = 0; intr_type < IOC4_NUM_INTR_TYPES; intr_type++) {
-               num_intrs = (int)atomic_read(
-                               &soft->is_intr_type[intr_type].is_num_intrs);
-
-               this_mir = this_ir = pending_intrs(soft, intr_type);
-
-               /* Farm out the interrupt to the various drivers depending on
-                * which interrupt bits are set.
-                */
-               for (xx = 0; xx < num_intrs; xx++) {
-                       intr_info = &soft->is_intr_type[intr_type].is_intr_info[xx];
-                       if ((this_mir = this_ir & intr_info->sd_bits)) {
-                               /* Disable owned interrupts, call handler */
-                               handled++;
-                               write_ireg(soft, intr_info->sd_bits, IOC4_W_IEC,
-                                                               intr_type);
-                               intr_info->sd_intr(intr_info->sd_info, this_mir);
-                               this_ir &= ~this_mir;
-                       }
-               }
-       }
-#ifdef DEBUG_INTERRUPTS
-       {
-               struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr;
-               unsigned long flag;
-
-               spin_lock_irqsave(&soft->is_ir_lock, flag);
-               printk ("%s : %d : mem 0x%p sio_ir 0x%x sio_ies 0x%x "
-                               "other_ir 0x%x other_ies 0x%x mask 0x%x\n",
-                    __func__, __LINE__,
-                    (void *)mem, readl(&mem->sio_ir.raw),
-                    readl(&mem->sio_ies.raw),
-                    readl(&mem->other_ir.raw),
-                    readl(&mem->other_ies.raw),
-                    IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR);
-               spin_unlock_irqrestore(&soft->is_ir_lock, flag);
-       }
-#endif
-       return handled ? IRQ_HANDLED : IRQ_NONE;
-}
-
-/**
- * ioc4_attach_local - Device initialization.
- *                     Called at *_attach() time for each
- *                     IOC4 with serial ports in the system.
- * @idd: Master module data for this IOC4
- */
-static int inline ioc4_attach_local(struct ioc4_driver_data *idd)
-{
-       struct ioc4_port *port;
-       struct ioc4_port *ports[IOC4_NUM_SERIAL_PORTS];
-       int port_number;
-       uint16_t ioc4_revid_min = 62;
-       uint16_t ioc4_revid;
-       struct pci_dev *pdev = idd->idd_pdev;
-       struct ioc4_control* control = idd->idd_serial_data;
-       struct ioc4_soft *soft = control->ic_soft;
-       void __iomem *ioc4_misc = idd->idd_misc_regs;
-       void __iomem *ioc4_serial = soft->is_ioc4_serial_addr;
-
-       /* IOC4 firmware must be at least rev 62 */
-       pci_read_config_word(pdev, PCI_COMMAND_SPECIAL, &ioc4_revid);
-
-       printk(KERN_INFO "IOC4 firmware revision %d\n", ioc4_revid);
-       if (ioc4_revid < ioc4_revid_min) {
-               printk(KERN_WARNING
-                   "IOC4 serial not supported on firmware rev %d, "
-                               "please upgrade to rev %d or higher\n",
-                               ioc4_revid, ioc4_revid_min);
-               return -EPERM;
-       }
-       BUG_ON(ioc4_misc == NULL);
-       BUG_ON(ioc4_serial == NULL);
-
-       /* Create port structures for each port */
-       for (port_number = 0; port_number < IOC4_NUM_SERIAL_PORTS;
-                                                       port_number++) {
-               port = kzalloc(sizeof(struct ioc4_port), GFP_KERNEL);
-               if (!port) {
-                       printk(KERN_WARNING
-                               "IOC4 serial memory not available for port\n");
-                       return -ENOMEM;
-               }
-               spin_lock_init(&port->ip_lock);
-
-               /* we need to remember the previous ones, to point back to
-                * them farther down - setting up the ring buffers.
-                */
-               ports[port_number] = port;
-
-               /* Allocate buffers and jumpstart the hardware.  */
-               control->ic_port[port_number].icp_port = port;
-               port->ip_ioc4_soft = soft;
-               port->ip_pdev = pdev;
-               port->ip_ienb = 0;
-               /* Use baud rate calculations based on detected PCI
-                * bus speed.  Simply test whether the PCI clock is
-                * running closer to 66MHz or 33MHz.
-                */
-               if (idd->count_period/IOC4_EXTINT_COUNT_DIVISOR < 20) {
-                       port->ip_pci_bus_speed = IOC4_SER_XIN_CLK_66;
-               } else {
-                       port->ip_pci_bus_speed = IOC4_SER_XIN_CLK_33;
-               }
-               port->ip_baud = 9600;
-               port->ip_control = control;
-               port->ip_mem = ioc4_misc;
-               port->ip_serial = ioc4_serial;
-
-               /* point to the right hook */
-               port->ip_hooks = &hooks_array[port_number];
-
-               /* Get direct hooks to the serial regs and uart regs
-                * for this port
-                */
-               switch (port_number) {
-               case 0:
-                       port->ip_serial_regs = &(port->ip_serial->port_0);
-                       port->ip_uart_regs = &(port->ip_serial->uart_0);
-                       break;
-               case 1:
-                       port->ip_serial_regs = &(port->ip_serial->port_1);
-                       port->ip_uart_regs = &(port->ip_serial->uart_1);
-                       break;
-               case 2:
-                       port->ip_serial_regs = &(port->ip_serial->port_2);
-                       port->ip_uart_regs = &(port->ip_serial->uart_2);
-                       break;
-               default:
-               case 3:
-                       port->ip_serial_regs = &(port->ip_serial->port_3);
-                       port->ip_uart_regs = &(port->ip_serial->uart_3);
-                       break;
-               }
-
-               /* ring buffers are 1 to a pair of ports */
-               if (port_number && (port_number & 1)) {
-                       /* odd use the evens buffer */
-                       port->ip_dma_ringbuf =
-                                       ports[port_number - 1]->ip_dma_ringbuf;
-                       port->ip_cpu_ringbuf =
-                                       ports[port_number - 1]->ip_cpu_ringbuf;
-                       port->ip_inring = RING(port, RX_1_OR_3);
-                       port->ip_outring = RING(port, TX_1_OR_3);
-
-               } else {
-                       if (port->ip_dma_ringbuf == 0) {
-                               port->ip_cpu_ringbuf = pci_alloc_consistent
-                                       (pdev, TOTAL_RING_BUF_SIZE,
-                                       &port->ip_dma_ringbuf);
-
-                       }
-                       BUG_ON(!((((int64_t)port->ip_dma_ringbuf) &
-                               (TOTAL_RING_BUF_SIZE - 1)) == 0));
-                       DPRINT_CONFIG(("%s : ip_cpu_ringbuf 0x%p "
-                                               "ip_dma_ringbuf 0x%p\n",
-                                       __func__,
-                                       (void *)port->ip_cpu_ringbuf,
-                                       (void *)port->ip_dma_ringbuf));
-                       port->ip_inring = RING(port, RX_0_OR_2);
-                       port->ip_outring = RING(port, TX_0_OR_2);
-               }
-               DPRINT_CONFIG(("%s : port %d [addr 0x%p] control 0x%p",
-                               __func__,
-                               port_number, (void *)port, (void *)control));
-               DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n",
-                               (void *)port->ip_serial_regs,
-                               (void *)port->ip_uart_regs));
-
-               /* Initialize the hardware for IOC4 */
-               port_init(port);
-
-               DPRINT_CONFIG(("%s: port_number %d port 0x%p inring 0x%p "
-                                               "outring 0x%p\n",
-                               __func__,
-                               port_number, (void *)port,
-                               (void *)port->ip_inring,
-                               (void *)port->ip_outring));
-
-               /* Attach interrupt handlers */
-               intr_connect(soft, IOC4_SIO_INTR_TYPE,
-                               GET_SIO_IR(port_number),
-                               handle_intr, port);
-
-               intr_connect(soft, IOC4_OTHER_INTR_TYPE,
-                               GET_OTHER_IR(port_number),
-                               handle_dma_error_intr, port);
-       }
-       return 0;
-}
-
-/**
- * enable_intrs - enable interrupts
- * @port: port to enable
- * @mask: mask to use
- */
-static void enable_intrs(struct ioc4_port *port, uint32_t mask)
-{
-       struct hooks *hooks = port->ip_hooks;
-
-       if ((port->ip_ienb & mask) != mask) {
-               write_ireg(port->ip_ioc4_soft, mask, IOC4_W_IES,
-                                               IOC4_SIO_INTR_TYPE);
-               port->ip_ienb |= mask;
-       }
-
-       if (port->ip_ienb)
-               write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error,
-                               IOC4_W_IES, IOC4_OTHER_INTR_TYPE);
-}
-
-/**
- * local_open - local open a port
- * @port: port to open
- */
-static inline int local_open(struct ioc4_port *port)
-{
-       int spiniter = 0;
-
-       port->ip_flags = PORT_ACTIVE;
-
-       /* Pause the DMA interface if necessary */
-       if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
-               writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE,
-                       &port->ip_serial_regs->sscr);
-               while((readl(&port->ip_serial_regs-> sscr)
-                               & IOC4_SSCR_PAUSE_STATE) == 0) {
-                       spiniter++;
-                       if (spiniter > MAXITER) {
-                               port->ip_flags = PORT_INACTIVE;
-                               return -1;
-                       }
-               }
-       }
-
-       /* Reset the input fifo.  If the uart received chars while the port
-        * was closed and DMA is not enabled, the uart may have a bunch of
-        * chars hanging around in its rx fifo which will not be discarded
-        * by rclr in the upper layer. We must get rid of them here.
-        */
-       writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR,
-                               &port->ip_uart_regs->i4u_fcr);
-
-       writeb(UART_LCR_WLEN8, &port->ip_uart_regs->i4u_lcr);
-                                       /* UART_LCR_STOP == 1 stop */
-
-       /* Re-enable DMA, set default threshold to intr whenever there is
-        * data available.
-        */
-       port->ip_sscr &= ~IOC4_SSCR_RX_THRESHOLD;
-       port->ip_sscr |= 1;     /* default threshold */
-
-       /* Plug in the new sscr.  This implicitly clears the DMA_PAUSE
-        * flag if it was set above
-        */
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       port->ip_tx_lowat = 1;
-       return 0;
-}
-
-/**
- * set_rx_timeout - Set rx timeout and threshold values.
- * @port: port to use
- * @timeout: timeout value in ticks
- */
-static inline int set_rx_timeout(struct ioc4_port *port, int timeout)
-{
-       int threshold;
-
-       port->ip_rx_timeout = timeout;
-
-       /* Timeout is in ticks.  Let's figure out how many chars we
-        * can receive at the current baud rate in that interval
-        * and set the rx threshold to that amount.  There are 4 chars
-        * per ring entry, so we'll divide the number of chars that will
-        * arrive in timeout by 4.
-        * So .... timeout * baud / 10 / HZ / 4, with HZ = 100.
-        */
-       threshold = timeout * port->ip_baud / 4000;
-       if (threshold == 0)
-               threshold = 1;  /* otherwise we'll intr all the time! */
-
-       if ((unsigned)threshold > (unsigned)IOC4_SSCR_RX_THRESHOLD)
-               return 1;
-
-       port->ip_sscr &= ~IOC4_SSCR_RX_THRESHOLD;
-       port->ip_sscr |= threshold;
-
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-
-       /* Now set the rx timeout to the given value
-        * again timeout * IOC4_SRTR_HZ / HZ
-        */
-       timeout = timeout * IOC4_SRTR_HZ / 100;
-       if (timeout > IOC4_SRTR_CNT)
-               timeout = IOC4_SRTR_CNT;
-
-       writel(timeout, &port->ip_serial_regs->srtr);
-       return 0;
-}
-
-/**
- * config_port - config the hardware
- * @port: port to config
- * @baud: baud rate for the port
- * @byte_size: data size
- * @stop_bits: number of stop bits
- * @parenb: parity enable ?
- * @parodd: odd parity ?
- */
-static inline int
-config_port(struct ioc4_port *port,
-           int baud, int byte_size, int stop_bits, int parenb, int parodd)
-{
-       char lcr, sizebits;
-       int spiniter = 0;
-
-       DPRINT_CONFIG(("%s: baud %d byte_size %d stop %d parenb %d parodd %d\n",
-               __func__, baud, byte_size, stop_bits, parenb, parodd));
-
-       if (set_baud(port, baud))
-               return 1;
-
-       switch (byte_size) {
-       case 5:
-               sizebits = UART_LCR_WLEN5;
-               break;
-       case 6:
-               sizebits = UART_LCR_WLEN6;
-               break;
-       case 7:
-               sizebits = UART_LCR_WLEN7;
-               break;
-       case 8:
-               sizebits = UART_LCR_WLEN8;
-               break;
-       default:
-               return 1;
-       }
-
-       /* Pause the DMA interface if necessary */
-       if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
-               writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE,
-                       &port->ip_serial_regs->sscr);
-               while((readl(&port->ip_serial_regs->sscr)
-                                               & IOC4_SSCR_PAUSE_STATE) == 0) {
-                       spiniter++;
-                       if (spiniter > MAXITER)
-                               return -1;
-               }
-       }
-
-       /* Clear relevant fields in lcr */
-       lcr = readb(&port->ip_uart_regs->i4u_lcr);
-       lcr &= ~(LCR_MASK_BITS_CHAR | UART_LCR_EPAR |
-                UART_LCR_PARITY | LCR_MASK_STOP_BITS);
-
-       /* Set byte size in lcr */
-       lcr |= sizebits;
-
-       /* Set parity */
-       if (parenb) {
-               lcr |= UART_LCR_PARITY;
-               if (!parodd)
-                       lcr |= UART_LCR_EPAR;
-       }
-
-       /* Set stop bits */
-       if (stop_bits)
-               lcr |= UART_LCR_STOP /* 2 stop bits */ ;
-
-       writeb(lcr, &port->ip_uart_regs->i4u_lcr);
-
-       /* Re-enable the DMA interface if necessary */
-       if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
-               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       }
-       port->ip_baud = baud;
-
-       /* When we get within this number of ring entries of filling the
-        * entire ring on tx, place an EXPLICIT intr to generate a lowat
-        * notification when output has drained.
-        */
-       port->ip_tx_lowat = (TX_LOWAT_CHARS(baud) + 3) / 4;
-       if (port->ip_tx_lowat == 0)
-               port->ip_tx_lowat = 1;
-
-       set_rx_timeout(port, 2);
-
-       return 0;
-}
-
-/**
- * do_write - Write bytes to the port.  Returns the number of bytes
- *                     actually written. Called from transmit_chars
- * @port: port to use
- * @buf: the stuff to write
- * @len: how many bytes in 'buf'
- */
-static inline int do_write(struct ioc4_port *port, char *buf, int len)
-{
-       int prod_ptr, cons_ptr, total = 0;
-       struct ring *outring;
-       struct ring_entry *entry;
-       struct hooks *hooks = port->ip_hooks;
-
-       BUG_ON(!(len >= 0));
-
-       prod_ptr = port->ip_tx_prod;
-       cons_ptr = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
-       outring = port->ip_outring;
-
-       /* Maintain a 1-entry red-zone.  The ring buffer is full when
-        * (cons - prod) % ring_size is 1.  Rather than do this subtraction
-        * in the body of the loop, I'll do it now.
-        */
-       cons_ptr = (cons_ptr - (int)sizeof(struct ring_entry)) & PROD_CONS_MASK;
-
-       /* Stuff the bytes into the output */
-       while ((prod_ptr != cons_ptr) && (len > 0)) {
-               int xx;
-
-               /* Get 4 bytes (one ring entry) at a time */
-               entry = (struct ring_entry *)((caddr_t) outring + prod_ptr);
-
-               /* Invalidate all entries */
-               entry->ring_allsc = 0;
-
-               /* Copy in some bytes */
-               for (xx = 0; (xx < 4) && (len > 0); xx++) {
-                       entry->ring_data[xx] = *buf++;
-                       entry->ring_sc[xx] = IOC4_TXCB_VALID;
-                       len--;
-                       total++;
-               }
-
-               /* If we are within some small threshold of filling up the
-                * entire ring buffer, we must place an EXPLICIT intr here
-                * to generate a lowat interrupt in case we subsequently
-                * really do fill up the ring and the caller goes to sleep.
-                * No need to place more than one though.
-                */
-               if (!(port->ip_flags & LOWAT_WRITTEN) &&
-                       ((cons_ptr - prod_ptr) & PROD_CONS_MASK)
-                               <= port->ip_tx_lowat
-                                       * (int)sizeof(struct ring_entry)) {
-                       port->ip_flags |= LOWAT_WRITTEN;
-                       entry->ring_sc[0] |= IOC4_TXCB_INT_WHEN_DONE;
-               }
-
-               /* Go on to next entry */
-               prod_ptr += sizeof(struct ring_entry);
-               prod_ptr &= PROD_CONS_MASK;
-       }
-
-       /* If we sent something, start DMA if necessary */
-       if (total > 0 && !(port->ip_sscr & IOC4_SSCR_DMA_EN)) {
-               port->ip_sscr |= IOC4_SSCR_DMA_EN;
-               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       }
-
-       /* Store the new producer pointer.  If tx is disabled, we stuff the
-        * data into the ring buffer, but we don't actually start tx.
-        */
-       if (!uart_tx_stopped(port->ip_port)) {
-               writel(prod_ptr, &port->ip_serial_regs->stpir);
-
-               /* If we are now transmitting, enable tx_mt interrupt so we
-                * can disable DMA if necessary when the tx finishes.
-                */
-               if (total > 0)
-                       enable_intrs(port, hooks->intr_tx_mt);
-       }
-       port->ip_tx_prod = prod_ptr;
-       return total;
-}
-
-/**
- * disable_intrs - disable interrupts
- * @port: port to enable
- * @mask: mask to use
- */
-static void disable_intrs(struct ioc4_port *port, uint32_t mask)
-{
-       struct hooks *hooks = port->ip_hooks;
-
-       if (port->ip_ienb & mask) {
-               write_ireg(port->ip_ioc4_soft, mask, IOC4_W_IEC,
-                                       IOC4_SIO_INTR_TYPE);
-               port->ip_ienb &= ~mask;
-       }
-
-       if (!port->ip_ienb)
-               write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error,
-                               IOC4_W_IEC, IOC4_OTHER_INTR_TYPE);
-}
-
-/**
- * set_notification - Modify event notification
- * @port: port to use
- * @mask: events mask
- * @set_on: set ?
- */
-static int set_notification(struct ioc4_port *port, int mask, int set_on)
-{
-       struct hooks *hooks = port->ip_hooks;
-       uint32_t intrbits, sscrbits;
-
-       BUG_ON(!mask);
-
-       intrbits = sscrbits = 0;
-
-       if (mask & N_DATA_READY)
-               intrbits |= (hooks->intr_rx_timer | hooks->intr_rx_high);
-       if (mask & N_OUTPUT_LOWAT)
-               intrbits |= hooks->intr_tx_explicit;
-       if (mask & N_DDCD) {
-               intrbits |= hooks->intr_delta_dcd;
-               sscrbits |= IOC4_SSCR_RX_RING_DCD;
-       }
-       if (mask & N_DCTS)
-               intrbits |= hooks->intr_delta_cts;
-
-       if (set_on) {
-               enable_intrs(port, intrbits);
-               port->ip_notify |= mask;
-               port->ip_sscr |= sscrbits;
-       } else {
-               disable_intrs(port, intrbits);
-               port->ip_notify &= ~mask;
-               port->ip_sscr &= ~sscrbits;
-       }
-
-       /* We require DMA if either DATA_READY or DDCD notification is
-        * currently requested. If neither of these is requested and
-        * there is currently no tx in progress, DMA may be disabled.
-        */
-       if (port->ip_notify & (N_DATA_READY | N_DDCD))
-               port->ip_sscr |= IOC4_SSCR_DMA_EN;
-       else if (!(port->ip_ienb & hooks->intr_tx_mt))
-               port->ip_sscr &= ~IOC4_SSCR_DMA_EN;
-
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       return 0;
-}
-
-/**
- * set_mcr - set the master control reg
- * @the_port: port to use
- * @mask1: mcr mask
- * @mask2: shadow mask
- */
-static inline int set_mcr(struct uart_port *the_port,
-               int mask1, int mask2)
-{
-       struct ioc4_port *port = get_ioc4_port(the_port, 0);
-       uint32_t shadow;
-       int spiniter = 0;
-       char mcr;
-
-       if (!port)
-               return -1;
-
-       /* Pause the DMA interface if necessary */
-       if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
-               writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE,
-                       &port->ip_serial_regs->sscr);
-               while ((readl(&port->ip_serial_regs->sscr)
-                                       & IOC4_SSCR_PAUSE_STATE) == 0) {
-                       spiniter++;
-                       if (spiniter > MAXITER)
-                               return -1;
-               }
-       }
-       shadow = readl(&port->ip_serial_regs->shadow);
-       mcr = (shadow & 0xff000000) >> 24;
-
-       /* Set new value */
-       mcr |= mask1;
-       shadow |= mask2;
-
-       writeb(mcr, &port->ip_uart_regs->i4u_mcr);
-       writel(shadow, &port->ip_serial_regs->shadow);
-
-       /* Re-enable the DMA interface if necessary */
-       if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
-               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       }
-       return 0;
-}
-
-/**
- * ioc4_set_proto - set the protocol for the port
- * @port: port to use
- * @proto: protocol to use
- */
-static int ioc4_set_proto(struct ioc4_port *port, int proto)
-{
-       struct hooks *hooks = port->ip_hooks;
-
-       switch (proto) {
-       case PROTO_RS232:
-               /* Clear the appropriate GIO pin */
-               writel(0, (&port->ip_mem->gppr[hooks->rs422_select_pin].raw));
-               break;
-
-       case PROTO_RS422:
-               /* Set the appropriate GIO pin */
-               writel(1, (&port->ip_mem->gppr[hooks->rs422_select_pin].raw));
-               break;
-
-       default:
-               return 1;
-       }
-       return 0;
-}
-
-/**
- * transmit_chars - upper level write, called with ip_lock
- * @the_port: port to write
- */
-static void transmit_chars(struct uart_port *the_port)
-{
-       int xmit_count, tail, head;
-       int result;
-       char *start;
-       struct tty_struct *tty;
-       struct ioc4_port *port = get_ioc4_port(the_port, 0);
-       struct uart_state *state;
-
-       if (!the_port)
-               return;
-       if (!port)
-               return;
-
-       state = the_port->state;
-       tty = state->port.tty;
-
-       if (uart_circ_empty(&state->xmit) || uart_tx_stopped(the_port)) {
-               /* Nothing to do or hw stopped */
-               set_notification(port, N_ALL_OUTPUT, 0);
-               return;
-       }
-
-       head = state->xmit.head;
-       tail = state->xmit.tail;
-       start = (char *)&state->xmit.buf[tail];
-
-       /* write out all the data or until the end of the buffer */
-       xmit_count = (head < tail) ? (UART_XMIT_SIZE - tail) : (head - tail);
-       if (xmit_count > 0) {
-               result = do_write(port, start, xmit_count);
-               if (result > 0) {
-                       /* booking */
-                       xmit_count -= result;
-                       the_port->icount.tx += result;
-                       /* advance the pointers */
-                       tail += result;
-                       tail &= UART_XMIT_SIZE - 1;
-                       state->xmit.tail = tail;
-                       start = (char *)&state->xmit.buf[tail];
-               }
-       }
-       if (uart_circ_chars_pending(&state->xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(the_port);
-
-       if (uart_circ_empty(&state->xmit)) {
-               set_notification(port, N_OUTPUT_LOWAT, 0);
-       } else {
-               set_notification(port, N_OUTPUT_LOWAT, 1);
-       }
-}
-
-/**
- * ioc4_change_speed - change the speed of the port
- * @the_port: port to change
- * @new_termios: new termios settings
- * @old_termios: old termios settings
- */
-static void
-ioc4_change_speed(struct uart_port *the_port,
-                 struct ktermios *new_termios, struct ktermios *old_termios)
-{
-       struct ioc4_port *port = get_ioc4_port(the_port, 0);
-       int baud, bits;
-       unsigned cflag, iflag;
-       int new_parity = 0, new_parity_enable = 0, new_stop = 0, new_data = 8;
-       struct uart_state *state = the_port->state;
-
-       cflag = new_termios->c_cflag;
-       iflag = new_termios->c_iflag;
-
-       switch (cflag & CSIZE) {
-       case CS5:
-               new_data = 5;
-               bits = 7;
-               break;
-       case CS6:
-               new_data = 6;
-               bits = 8;
-               break;
-       case CS7:
-               new_data = 7;
-               bits = 9;
-               break;
-       case CS8:
-               new_data = 8;
-               bits = 10;
-               break;
-       default:
-               /* cuz we always need a default ... */
-               new_data = 5;
-               bits = 7;
-               break;
-       }
-       if (cflag & CSTOPB) {
-               bits++;
-               new_stop = 1;
-       }
-       if (cflag & PARENB) {
-               bits++;
-               new_parity_enable = 1;
-               if (cflag & PARODD)
-                       new_parity = 1;
-       }
-       baud = uart_get_baud_rate(the_port, new_termios, old_termios,
-                               MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED);
-       DPRINT_CONFIG(("%s: returned baud %d\n", __func__, baud));
-
-       /* default is 9600 */
-       if (!baud)
-               baud = 9600;
-
-       if (!the_port->fifosize)
-               the_port->fifosize = IOC4_FIFO_CHARS;
-       the_port->timeout = ((the_port->fifosize * HZ * bits) / (baud / 10));
-       the_port->timeout += HZ / 50;   /* Add .02 seconds of slop */
-
-       the_port->ignore_status_mask = N_ALL_INPUT;
-
-       state->port.tty->low_latency = 1;
-
-       if (iflag & IGNPAR)
-               the_port->ignore_status_mask &= ~(N_PARITY_ERROR
-                                               | N_FRAMING_ERROR);
-       if (iflag & IGNBRK) {
-               the_port->ignore_status_mask &= ~N_BREAK;
-               if (iflag & IGNPAR)
-                       the_port->ignore_status_mask &= ~N_OVERRUN_ERROR;
-       }
-       if (!(cflag & CREAD)) {
-               /* ignore everything */
-               the_port->ignore_status_mask &= ~N_DATA_READY;
-       }
-
-       if (cflag & CRTSCTS) {
-               port->ip_sscr |= IOC4_SSCR_HFC_EN;
-       }
-       else {
-               port->ip_sscr &= ~IOC4_SSCR_HFC_EN;
-       }
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-
-       /* Set the configuration and proper notification call */
-       DPRINT_CONFIG(("%s : port 0x%p cflag 0%o "
-               "config_port(baud %d data %d stop %d p enable %d parity %d),"
-               " notification 0x%x\n",
-            __func__, (void *)port, cflag, baud, new_data, new_stop,
-            new_parity_enable, new_parity, the_port->ignore_status_mask));
-
-       if ((config_port(port, baud,            /* baud */
-                        new_data,              /* byte size */
-                        new_stop,              /* stop bits */
-                        new_parity_enable,     /* set parity */
-                        new_parity)) >= 0) {   /* parity 1==odd */
-               set_notification(port, the_port->ignore_status_mask, 1);
-       }
-}
-
-/**
- * ic4_startup_local - Start up the serial port - returns >= 0 if no errors
- * @the_port: Port to operate on
- */
-static inline int ic4_startup_local(struct uart_port *the_port)
-{
-       struct ioc4_port *port;
-       struct uart_state *state;
-
-       if (!the_port)
-               return -1;
-
-       port = get_ioc4_port(the_port, 0);
-       if (!port)
-               return -1;
-
-       state = the_port->state;
-
-       local_open(port);
-
-       /* set the protocol - mapbase has the port type */
-       ioc4_set_proto(port, the_port->mapbase);
-
-       /* set the speed of the serial port */
-       ioc4_change_speed(the_port, state->port.tty->termios,
-                         (struct ktermios *)0);
-
-       return 0;
-}
-
-/*
- * ioc4_cb_output_lowat - called when the output low water mark is hit
- * @the_port: port to output
- */
-static void ioc4_cb_output_lowat(struct uart_port *the_port)
-{
-       unsigned long pflags;
-
-       /* ip_lock is set on the call here */
-       if (the_port) {
-               spin_lock_irqsave(&the_port->lock, pflags);
-               transmit_chars(the_port);
-               spin_unlock_irqrestore(&the_port->lock, pflags);
-       }
-}
-
-/**
- * handle_intr - service any interrupts for the given port - 2nd level
- *                     called via sd_intr
- * @arg: handler arg
- * @sio_ir: ioc4regs
- */
-static void handle_intr(void *arg, uint32_t sio_ir)
-{
-       struct ioc4_port *port = (struct ioc4_port *)arg;
-       struct hooks *hooks = port->ip_hooks;
-       unsigned int rx_high_rd_aborted = 0;
-       unsigned long flags;
-       struct uart_port *the_port;
-       int loop_counter;
-
-       /* Possible race condition here: The tx_mt interrupt bit may be
-        * cleared without the intervention of the interrupt handler,
-        * e.g. by a write.  If the top level interrupt handler reads a
-        * tx_mt, then some other processor does a write, starting up
-        * output, then we come in here, see the tx_mt and stop DMA, the
-        * output started by the other processor will hang.  Thus we can
-        * only rely on tx_mt being legitimate if it is read while the
-        * port lock is held.  Therefore this bit must be ignored in the
-        * passed in interrupt mask which was read by the top level
-        * interrupt handler since the port lock was not held at the time
-        * it was read.  We can only rely on this bit being accurate if it
-        * is read while the port lock is held.  So we'll clear it for now,
-        * and reload it later once we have the port lock.
-        */
-       sio_ir &= ~(hooks->intr_tx_mt);
-
-       spin_lock_irqsave(&port->ip_lock, flags);
-
-       loop_counter = MAXITER; /* to avoid hangs */
-
-       do {
-               uint32_t shadow;
-
-               if ( loop_counter-- <= 0 ) {
-                       printk(KERN_WARNING "IOC4 serial: "
-                                       "possible hang condition/"
-                                       "port stuck on interrupt.\n");
-                       break;
-               }
-
-               /* Handle a DCD change */
-               if (sio_ir & hooks->intr_delta_dcd) {
-                       /* ACK the interrupt */
-                       writel(hooks->intr_delta_dcd,
-                               &port->ip_mem->sio_ir.raw);
-
-                       shadow = readl(&port->ip_serial_regs->shadow);
-
-                       if ((port->ip_notify & N_DDCD)
-                                       && (shadow & IOC4_SHADOW_DCD)
-                                       && (port->ip_port)) {
-                               the_port = port->ip_port;
-                               the_port->icount.dcd = 1;
-                               wake_up_interruptible
-                                           (&the_port->state->port.delta_msr_wait);
-                       } else if ((port->ip_notify & N_DDCD)
-                                       && !(shadow & IOC4_SHADOW_DCD)) {
-                               /* Flag delta DCD/no DCD */
-                               port->ip_flags |= DCD_ON;
-                       }
-               }
-
-               /* Handle a CTS change */
-               if (sio_ir & hooks->intr_delta_cts) {
-                       /* ACK the interrupt */
-                       writel(hooks->intr_delta_cts,
-                                       &port->ip_mem->sio_ir.raw);
-
-                       shadow = readl(&port->ip_serial_regs->shadow);
-
-                       if ((port->ip_notify & N_DCTS)
-                                       && (port->ip_port)) {
-                               the_port = port->ip_port;
-                               the_port->icount.cts =
-                                       (shadow & IOC4_SHADOW_CTS) ? 1 : 0;
-                               wake_up_interruptible
-                                       (&the_port->state->port.delta_msr_wait);
-                       }
-               }
-
-               /* rx timeout interrupt.  Must be some data available.  Put this
-                * before the check for rx_high since servicing this condition
-                * may cause that condition to clear.
-                */
-               if (sio_ir & hooks->intr_rx_timer) {
-                       /* ACK the interrupt */
-                       writel(hooks->intr_rx_timer,
-                               &port->ip_mem->sio_ir.raw);
-
-                       if ((port->ip_notify & N_DATA_READY)
-                                       && (port->ip_port)) {
-                               /* ip_lock is set on call here */
-                               receive_chars(port->ip_port);
-                       }
-               }
-
-               /* rx high interrupt. Must be after rx_timer.  */
-               else if (sio_ir & hooks->intr_rx_high) {
-                       /* Data available, notify upper layer */
-                       if ((port->ip_notify & N_DATA_READY)
-                                               && port->ip_port) {
-                               /* ip_lock is set on call here */
-                               receive_chars(port->ip_port);
-                       }
-
-                       /* We can't ACK this interrupt.  If receive_chars didn't
-                        * cause the condition to clear, we'll have to disable
-                        * the interrupt until the data is drained.
-                        * If the read was aborted, don't disable the interrupt
-                        * as this may cause us to hang indefinitely.  An
-                        * aborted read generally means that this interrupt
-                        * hasn't been delivered to the cpu yet anyway, even
-                        * though we see it as asserted when we read the sio_ir.
-                        */
-                       if ((sio_ir = PENDING(port)) & hooks->intr_rx_high) {
-                               if ((port->ip_flags & READ_ABORTED) == 0) {
-                                       port->ip_ienb &= ~hooks->intr_rx_high;
-                                       port->ip_flags |= INPUT_HIGH;
-                               } else {
-                                       rx_high_rd_aborted++;
-                               }
-                       }
-               }
-
-               /* We got a low water interrupt: notify upper layer to
-                * send more data.  Must come before tx_mt since servicing
-                * this condition may cause that condition to clear.
-                */
-               if (sio_ir & hooks->intr_tx_explicit) {
-                       port->ip_flags &= ~LOWAT_WRITTEN;
-
-                       /* ACK the interrupt */
-                       writel(hooks->intr_tx_explicit,
-                                       &port->ip_mem->sio_ir.raw);
-
-                       if (port->ip_notify & N_OUTPUT_LOWAT)
-                               ioc4_cb_output_lowat(port->ip_port);
-               }
-
-               /* Handle tx_mt.  Must come after tx_explicit.  */
-               else if (sio_ir & hooks->intr_tx_mt) {
-                       /* If we are expecting a lowat notification
-                        * and we get to this point it probably means that for
-                        * some reason the tx_explicit didn't work as expected
-                        * (that can legitimately happen if the output buffer is
-                        * filled up in just the right way).
-                        * So send the notification now.
-                        */
-                       if (port->ip_notify & N_OUTPUT_LOWAT) {
-                               ioc4_cb_output_lowat(port->ip_port);
-
-                               /* We need to reload the sio_ir since the lowat
-                                * call may have caused another write to occur,
-                                * clearing the tx_mt condition.
-                                */
-                               sio_ir = PENDING(port);
-                       }
-
-                       /* If the tx_mt condition still persists even after the
-                        * lowat call, we've got some work to do.
-                        */
-                       if (sio_ir & hooks->intr_tx_mt) {
-
-                               /* If we are not currently expecting DMA input,
-                                * and the transmitter has just gone idle,
-                                * there is no longer any reason for DMA, so
-                                * disable it.
-                                */
-                               if (!(port->ip_notify
-                                               & (N_DATA_READY | N_DDCD))) {
-                                       BUG_ON(!(port->ip_sscr
-                                                       & IOC4_SSCR_DMA_EN));
-                                       port->ip_sscr &= ~IOC4_SSCR_DMA_EN;
-                                       writel(port->ip_sscr,
-                                          &port->ip_serial_regs->sscr);
-                               }
-
-                               /* Prevent infinite tx_mt interrupt */
-                               port->ip_ienb &= ~hooks->intr_tx_mt;
-                       }
-               }
-               sio_ir = PENDING(port);
-
-               /* if the read was aborted and only hooks->intr_rx_high,
-                * clear hooks->intr_rx_high, so we do not loop forever.
-                */
-
-               if (rx_high_rd_aborted && (sio_ir == hooks->intr_rx_high)) {
-                       sio_ir &= ~hooks->intr_rx_high;
-               }
-       } while (sio_ir & hooks->intr_all);
-
-       spin_unlock_irqrestore(&port->ip_lock, flags);
-
-       /* Re-enable interrupts before returning from interrupt handler.
-        * Getting interrupted here is okay.  It'll just v() our semaphore, and
-        * we'll come through the loop again.
-        */
-
-       write_ireg(port->ip_ioc4_soft, port->ip_ienb, IOC4_W_IES,
-                                                       IOC4_SIO_INTR_TYPE);
-}
-
-/*
- * ioc4_cb_post_ncs - called for some basic errors
- * @port: port to use
- * @ncs: event
- */
-static void ioc4_cb_post_ncs(struct uart_port *the_port, int ncs)
-{
-       struct uart_icount *icount;
-
-       icount = &the_port->icount;
-
-       if (ncs & NCS_BREAK)
-               icount->brk++;
-       if (ncs & NCS_FRAMING)
-               icount->frame++;
-       if (ncs & NCS_OVERRUN)
-               icount->overrun++;
-       if (ncs & NCS_PARITY)
-               icount->parity++;
-}
-
-/**
- * do_read - Read in bytes from the port.  Return the number of bytes
- *                     actually read.
- * @the_port: port to use
- * @buf: place to put the stuff we read
- * @len: how big 'buf' is
- */
-
-static inline int do_read(struct uart_port *the_port, unsigned char *buf,
-                               int len)
-{
-       int prod_ptr, cons_ptr, total;
-       struct ioc4_port *port = get_ioc4_port(the_port, 0);
-       struct ring *inring;
-       struct ring_entry *entry;
-       struct hooks *hooks = port->ip_hooks;
-       int byte_num;
-       char *sc;
-       int loop_counter;
-
-       BUG_ON(!(len >= 0));
-       BUG_ON(!port);
-
-       /* There is a nasty timing issue in the IOC4. When the rx_timer
-        * expires or the rx_high condition arises, we take an interrupt.
-        * At some point while servicing the interrupt, we read bytes from
-        * the ring buffer and re-arm the rx_timer.  However the rx_timer is
-        * not started until the first byte is received *after* it is armed,
-        * and any bytes pending in the rx construction buffers are not drained
-        * to memory until either there are 4 bytes available or the rx_timer
-        * expires.  This leads to a potential situation where data is left
-        * in the construction buffers forever - 1 to 3 bytes were received
-        * after the interrupt was generated but before the rx_timer was
-        * re-armed. At that point as long as no subsequent bytes are received
-        * the timer will never be started and the bytes will remain in the
-        * construction buffer forever.  The solution is to execute a DRAIN
-        * command after rearming the timer.  This way any bytes received before
-        * the DRAIN will be drained to memory, and any bytes received after
-        * the DRAIN will start the TIMER and be drained when it expires.
-        * Luckily, this only needs to be done when the DMA buffer is empty
-        * since there is no requirement that this function return all
-        * available data as long as it returns some.
-        */
-       /* Re-arm the timer */
-       writel(port->ip_rx_cons | IOC4_SRCIR_ARM, &port->ip_serial_regs->srcir);
-
-       prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
-       cons_ptr = port->ip_rx_cons;
-
-       if (prod_ptr == cons_ptr) {
-               int reset_dma = 0;
-
-               /* Input buffer appears empty, do a flush. */
-
-               /* DMA must be enabled for this to work. */
-               if (!(port->ip_sscr & IOC4_SSCR_DMA_EN)) {
-                       port->ip_sscr |= IOC4_SSCR_DMA_EN;
-                       reset_dma = 1;
-               }
-
-               /* Potential race condition: we must reload the srpir after
-                * issuing the drain command, otherwise we could think the rx
-                * buffer is empty, then take a very long interrupt, and when
-                * we come back it's full and we wait forever for the drain to
-                * complete.
-                */
-               writel(port->ip_sscr | IOC4_SSCR_RX_DRAIN,
-                               &port->ip_serial_regs->sscr);
-               prod_ptr = readl(&port->ip_serial_regs->srpir)
-                               & PROD_CONS_MASK;
-
-               /* We must not wait for the DRAIN to complete unless there are
-                * at least 8 bytes (2 ring entries) available to receive the
-                * data otherwise the DRAIN will never complete and we'll
-                * deadlock here.
-                * In fact, to make things easier, I'll just ignore the flush if
-                * there is any data at all now available.
-                */
-               if (prod_ptr == cons_ptr) {
-                       loop_counter = 0;
-                       while (readl(&port->ip_serial_regs->sscr) &
-                                               IOC4_SSCR_RX_DRAIN) {
-                               loop_counter++;
-                               if (loop_counter > MAXITER)
-                                       return -1;
-                       }
-
-                       /* SIGH. We have to reload the prod_ptr *again* since
-                        * the drain may have caused it to change
-                        */
-                       prod_ptr = readl(&port->ip_serial_regs->srpir)
-                                                       & PROD_CONS_MASK;
-               }
-               if (reset_dma) {
-                       port->ip_sscr &= ~IOC4_SSCR_DMA_EN;
-                       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-               }
-       }
-       inring = port->ip_inring;
-       port->ip_flags &= ~READ_ABORTED;
-
-       total = 0;
-       loop_counter = 0xfffff; /* to avoid hangs */
-
-       /* Grab bytes from the hardware */
-       while ((prod_ptr != cons_ptr) && (len > 0)) {
-               entry = (struct ring_entry *)((caddr_t)inring + cons_ptr);
-
-               if ( loop_counter-- <= 0 ) {
-                       printk(KERN_WARNING "IOC4 serial: "
-                                       "possible hang condition/"
-                                       "port stuck on read.\n");
-                       break;
-               }
-
-               /* According to the producer pointer, this ring entry
-                * must contain some data.  But if the PIO happened faster
-                * than the DMA, the data may not be available yet, so let's
-                * wait until it arrives.
-                */
-               if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
-                       /* Indicate the read is aborted so we don't disable
-                        * the interrupt thinking that the consumer is
-                        * congested.
-                        */
-                       port->ip_flags |= READ_ABORTED;
-                       len = 0;
-                       break;
-               }
-
-               /* Load the bytes/status out of the ring entry */
-               for (byte_num = 0; byte_num < 4 && len > 0; byte_num++) {
-                       sc = &(entry->ring_sc[byte_num]);
-
-                       /* Check for change in modem state or overrun */
-                       if ((*sc & IOC4_RXSB_MODEM_VALID)
-                                               && (port->ip_notify & N_DDCD)) {
-                               /* Notify upper layer if DCD dropped */
-
-                               if ((port->ip_flags & DCD_ON)
-                                               && !(*sc & IOC4_RXSB_DCD)) {
-
-                                       /* If we have already copied some data,
-                                        * return it.  We'll pick up the carrier
-                                        * drop on the next pass.  That way we
-                                        * don't throw away the data that has
-                                        * already been copied back to
-                                        * the caller's buffer.
-                                        */
-                                       if (total > 0) {
-                                               len = 0;
-                                               break;
-                                       }
-                                       port->ip_flags &= ~DCD_ON;
-
-                                       /* Turn off this notification so the
-                                        * carrier drop protocol won't see it
-                                        * again when it does a read.
-                                        */
-                                       *sc &= ~IOC4_RXSB_MODEM_VALID;
-
-                                       /* To keep things consistent, we need
-                                        * to update the consumer pointer so
-                                        * the next reader won't come in and
-                                        * try to read the same ring entries
-                                        * again. This must be done here before
-                                        * the dcd change.
-                                        */
-
-                                       if ((entry->ring_allsc & RING_ANY_VALID)
-                                                                       == 0) {
-                                               cons_ptr += (int)sizeof
-                                                       (struct ring_entry);
-                                               cons_ptr &= PROD_CONS_MASK;
-                                       }
-                                       writel(cons_ptr,
-                                               &port->ip_serial_regs->srcir);
-                                       port->ip_rx_cons = cons_ptr;
-
-                                       /* Notify upper layer of carrier drop */
-                                       if ((port->ip_notify & N_DDCD)
-                                                  && port->ip_port) {
-                                               the_port->icount.dcd = 0;
-                                               wake_up_interruptible
-                                                   (&the_port->state->
-                                                       port.delta_msr_wait);
-                                       }
-
-                                       /* If we had any data to return, we
-                                        * would have returned it above.
-                                        */
-                                       return 0;
-                               }
-                       }
-                       if (*sc & IOC4_RXSB_MODEM_VALID) {
-                               /* Notify that an input overrun occurred */
-                               if ((*sc & IOC4_RXSB_OVERRUN)
-                                   && (port->ip_notify & N_OVERRUN_ERROR)) {
-                                       ioc4_cb_post_ncs(the_port, NCS_OVERRUN);
-                               }
-                               /* Don't look at this byte again */
-                               *sc &= ~IOC4_RXSB_MODEM_VALID;
-                       }
-
-                       /* Check for valid data or RX errors */
-                       if ((*sc & IOC4_RXSB_DATA_VALID) &&
-                                       ((*sc & (IOC4_RXSB_PAR_ERR
-                                                       | IOC4_RXSB_FRAME_ERR
-                                                       | IOC4_RXSB_BREAK))
-                                       && (port->ip_notify & (N_PARITY_ERROR
-                                                       | N_FRAMING_ERROR
-                                                       | N_BREAK)))) {
-                               /* There is an error condition on the next byte.
-                                * If we have already transferred some bytes,
-                                * we'll stop here. Otherwise if this is the
-                                * first byte to be read, we'll just transfer
-                                * it alone after notifying the
-                                * upper layer of its status.
-                                */
-                               if (total > 0) {
-                                       len = 0;
-                                       break;
-                               } else {
-                                       if ((*sc & IOC4_RXSB_PAR_ERR) &&
-                                          (port->ip_notify & N_PARITY_ERROR)) {
-                                               ioc4_cb_post_ncs(the_port,
-                                                               NCS_PARITY);
-                                       }
-                                       if ((*sc & IOC4_RXSB_FRAME_ERR) &&
-                                          (port->ip_notify & N_FRAMING_ERROR)){
-                                               ioc4_cb_post_ncs(the_port,
-                                                               NCS_FRAMING);
-                                       }
-                                       if ((*sc & IOC4_RXSB_BREAK)
-                                           && (port->ip_notify & N_BREAK)) {
-                                                       ioc4_cb_post_ncs
-                                                                   (the_port,
-                                                                    NCS_BREAK);
-                                       }
-                                       len = 1;
-                               }
-                       }
-                       if (*sc & IOC4_RXSB_DATA_VALID) {
-                               *sc &= ~IOC4_RXSB_DATA_VALID;
-                               *buf = entry->ring_data[byte_num];
-                               buf++;
-                               len--;
-                               total++;
-                       }
-               }
-
-               /* If we used up this entry entirely, go on to the next one,
-                * otherwise we must have run out of buffer space, so
-                * leave the consumer pointer here for the next read in case
-                * there are still unread bytes in this entry.
-                */
-               if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
-                       cons_ptr += (int)sizeof(struct ring_entry);
-                       cons_ptr &= PROD_CONS_MASK;
-               }
-       }
-
-       /* Update consumer pointer and re-arm rx timer interrupt */
-       writel(cons_ptr, &port->ip_serial_regs->srcir);
-       port->ip_rx_cons = cons_ptr;
-
-       /* If we have now dipped below the rx high water mark and we have
-        * rx_high interrupt turned off, we can now turn it back on again.
-        */
-       if ((port->ip_flags & INPUT_HIGH) && (((prod_ptr - cons_ptr)
-                       & PROD_CONS_MASK) < ((port->ip_sscr &
-                               IOC4_SSCR_RX_THRESHOLD)
-                                       << IOC4_PROD_CONS_PTR_OFF))) {
-               port->ip_flags &= ~INPUT_HIGH;
-               enable_intrs(port, hooks->intr_rx_high);
-       }
-       return total;
-}
-
-/**
- * receive_chars - upper level read. Called with ip_lock.
- * @the_port: port to read from
- */
-static void receive_chars(struct uart_port *the_port)
-{
-       struct tty_struct *tty;
-       unsigned char ch[IOC4_MAX_CHARS];
-       int read_count, request_count = IOC4_MAX_CHARS;
-       struct uart_icount *icount;
-       struct uart_state *state = the_port->state;
-       unsigned long pflags;
-
-       /* Make sure all the pointers are "good" ones */
-       if (!state)
-               return;
-       if (!state->port.tty)
-               return;
-
-       spin_lock_irqsave(&the_port->lock, pflags);
-       tty = state->port.tty;
-
-       request_count = tty_buffer_request_room(tty, IOC4_MAX_CHARS);
-
-       if (request_count > 0) {
-               icount = &the_port->icount;
-               read_count = do_read(the_port, ch, request_count);
-               if (read_count > 0) {
-                       tty_insert_flip_string(tty, ch, read_count);
-                       icount->rx += read_count;
-               }
-       }
-
-       spin_unlock_irqrestore(&the_port->lock, pflags);
-
-       tty_flip_buffer_push(tty);
-}
-
-/**
- * ic4_type - What type of console are we?
- * @port: Port to operate with (we ignore since we only have one port)
- *
- */
-static const char *ic4_type(struct uart_port *the_port)
-{
-       if (the_port->mapbase == PROTO_RS232)
-               return "SGI IOC4 Serial [rs232]";
-       else
-               return "SGI IOC4 Serial [rs422]";
-}
-
-/**
- * ic4_tx_empty - Is the transmitter empty?
- * @port: Port to operate on
- *
- */
-static unsigned int ic4_tx_empty(struct uart_port *the_port)
-{
-       struct ioc4_port *port = get_ioc4_port(the_port, 0);
-       unsigned int ret = 0;
-
-       if (port_is_active(port, the_port)) {
-               if (readl(&port->ip_serial_regs->shadow) & IOC4_SHADOW_TEMT)
-                       ret = TIOCSER_TEMT;
-       }
-       return ret;
-}
-
-/**
- * ic4_stop_tx - stop the transmitter
- * @port: Port to operate on
- *
- */
-static void ic4_stop_tx(struct uart_port *the_port)
-{
-       struct ioc4_port *port = get_ioc4_port(the_port, 0);
-
-       if (port_is_active(port, the_port))
-               set_notification(port, N_OUTPUT_LOWAT, 0);
-}
-
-/**
- * null_void_function -
- * @port: Port to operate on
- *
- */
-static void null_void_function(struct uart_port *the_port)
-{
-}
-
-/**
- * ic4_shutdown - shut down the port - free irq and disable
- * @port: Port to shut down
- *
- */
-static void ic4_shutdown(struct uart_port *the_port)
-{
-       unsigned long port_flags;
-       struct ioc4_port *port;
-       struct uart_state *state;
-
-       port = get_ioc4_port(the_port, 0);
-       if (!port)
-               return;
-
-       state = the_port->state;
-       port->ip_port = NULL;
-
-       wake_up_interruptible(&state->port.delta_msr_wait);
-
-       if (state->port.tty)
-               set_bit(TTY_IO_ERROR, &state->port.tty->flags);
-
-       spin_lock_irqsave(&the_port->lock, port_flags);
-       set_notification(port, N_ALL, 0);
-       port->ip_flags = PORT_INACTIVE;
-       spin_unlock_irqrestore(&the_port->lock, port_flags);
-}
-
-/**
- * ic4_set_mctrl - set control lines (dtr, rts, etc)
- * @port: Port to operate on
- * @mctrl: Lines to set/unset
- *
- */
-static void ic4_set_mctrl(struct uart_port *the_port, unsigned int mctrl)
-{
-       unsigned char mcr = 0;
-       struct ioc4_port *port;
-
-       port = get_ioc4_port(the_port, 0);
-       if (!port_is_active(port, the_port))
-               return;
-
-       if (mctrl & TIOCM_RTS)
-               mcr |= UART_MCR_RTS;
-       if (mctrl & TIOCM_DTR)
-               mcr |= UART_MCR_DTR;
-       if (mctrl & TIOCM_OUT1)
-               mcr |= UART_MCR_OUT1;
-       if (mctrl & TIOCM_OUT2)
-               mcr |= UART_MCR_OUT2;
-       if (mctrl & TIOCM_LOOP)
-               mcr |= UART_MCR_LOOP;
-
-       set_mcr(the_port, mcr, IOC4_SHADOW_DTR);
-}
-
-/**
- * ic4_get_mctrl - get control line info
- * @port: port to operate on
- *
- */
-static unsigned int ic4_get_mctrl(struct uart_port *the_port)
-{
-       struct ioc4_port *port = get_ioc4_port(the_port, 0);
-       uint32_t shadow;
-       unsigned int ret = 0;
-
-       if (!port_is_active(port, the_port))
-               return 0;
-
-       shadow = readl(&port->ip_serial_regs->shadow);
-       if (shadow & IOC4_SHADOW_DCD)
-               ret |= TIOCM_CAR;
-       if (shadow & IOC4_SHADOW_DR)
-               ret |= TIOCM_DSR;
-       if (shadow & IOC4_SHADOW_CTS)
-               ret |= TIOCM_CTS;
-       return ret;
-}
-
-/**
- * ic4_start_tx - Start transmitter, flush any output
- * @port: Port to operate on
- *
- */
-static void ic4_start_tx(struct uart_port *the_port)
-{
-       struct ioc4_port *port = get_ioc4_port(the_port, 0);
-
-       if (port_is_active(port, the_port)) {
-               set_notification(port, N_OUTPUT_LOWAT, 1);
-               enable_intrs(port, port->ip_hooks->intr_tx_mt);
-       }
-}
-
-/**
- * ic4_break_ctl - handle breaks
- * @port: Port to operate on
- * @break_state: Break state
- *
- */
-static void ic4_break_ctl(struct uart_port *the_port, int break_state)
-{
-}
-
-/**
- * ic4_startup - Start up the serial port
- * @port: Port to operate on
- *
- */
-static int ic4_startup(struct uart_port *the_port)
-{
-       int retval;
-       struct ioc4_port *port;
-       struct ioc4_control *control;
-       struct uart_state *state;
-       unsigned long port_flags;
-
-       if (!the_port)
-               return -ENODEV;
-       port = get_ioc4_port(the_port, 1);
-       if (!port)
-               return -ENODEV;
-       state = the_port->state;
-
-       control = port->ip_control;
-       if (!control) {
-               port->ip_port = NULL;
-               return -ENODEV;
-       }
-
-       /* Start up the serial port */
-       spin_lock_irqsave(&the_port->lock, port_flags);
-       retval = ic4_startup_local(the_port);
-       spin_unlock_irqrestore(&the_port->lock, port_flags);
-       return retval;
-}
-
-/**
- * ic4_set_termios - set termios stuff
- * @port: port to operate on
- * @termios: New settings
- * @termios: Old
- *
- */
-static void
-ic4_set_termios(struct uart_port *the_port,
-               struct ktermios *termios, struct ktermios *old_termios)
-{
-       unsigned long port_flags;
-
-       spin_lock_irqsave(&the_port->lock, port_flags);
-       ioc4_change_speed(the_port, termios, old_termios);
-       spin_unlock_irqrestore(&the_port->lock, port_flags);
-}
-
-/**
- * ic4_request_port - allocate resources for port - no op....
- * @port: port to operate on
- *
- */
-static int ic4_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-/* Associate the uart functions above - given to serial core */
-
-static struct uart_ops ioc4_ops = {
-       .tx_empty       = ic4_tx_empty,
-       .set_mctrl      = ic4_set_mctrl,
-       .get_mctrl      = ic4_get_mctrl,
-       .stop_tx        = ic4_stop_tx,
-       .start_tx       = ic4_start_tx,
-       .stop_rx        = null_void_function,
-       .enable_ms      = null_void_function,
-       .break_ctl      = ic4_break_ctl,
-       .startup        = ic4_startup,
-       .shutdown       = ic4_shutdown,
-       .set_termios    = ic4_set_termios,
-       .type           = ic4_type,
-       .release_port   = null_void_function,
-       .request_port   = ic4_request_port,
-};
-
-/*
- * Boot-time initialization code
- */
-
-static struct uart_driver ioc4_uart_rs232 = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "ioc4_serial_rs232",
-       .dev_name       = DEVICE_NAME_RS232,
-       .major          = DEVICE_MAJOR,
-       .minor          = DEVICE_MINOR_RS232,
-       .nr             = IOC4_NUM_CARDS * IOC4_NUM_SERIAL_PORTS,
-};
-
-static struct uart_driver ioc4_uart_rs422 = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "ioc4_serial_rs422",
-       .dev_name       = DEVICE_NAME_RS422,
-       .major          = DEVICE_MAJOR,
-       .minor          = DEVICE_MINOR_RS422,
-       .nr             = IOC4_NUM_CARDS * IOC4_NUM_SERIAL_PORTS,
-};
-
-
-/**
- * ioc4_serial_remove_one - detach function
- *
- * @idd: IOC4 master module data for this IOC4
- */
-
-static int ioc4_serial_remove_one(struct ioc4_driver_data *idd)
-{
-       int port_num, port_type;
-       struct ioc4_control *control;
-       struct uart_port *the_port;
-       struct ioc4_port *port;
-       struct ioc4_soft *soft;
-
-       /* If serial driver did not attach, don't try to detach */
-       control = idd->idd_serial_data;
-       if (!control)
-               return 0;
-
-       for (port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; port_num++) {
-               for (port_type = UART_PORT_MIN;
-                                       port_type < UART_PORT_COUNT;
-                                       port_type++) {
-                       the_port = &control->ic_port[port_num].icp_uart_port
-                                                       [port_type];
-                       if (the_port) {
-                               switch (port_type) {
-                               case UART_PORT_RS422:
-                                       uart_remove_one_port(&ioc4_uart_rs422,
-                                                       the_port);
-                                       break;
-                               default:
-                               case UART_PORT_RS232:
-                                       uart_remove_one_port(&ioc4_uart_rs232,
-                                                       the_port);
-                                       break;
-                               }
-                       }
-               }
-               port = control->ic_port[port_num].icp_port;
-               /* we allocate in pairs */
-               if (!(port_num & 1) && port) {
-                       pci_free_consistent(port->ip_pdev,
-                                       TOTAL_RING_BUF_SIZE,
-                                       port->ip_cpu_ringbuf,
-                                       port->ip_dma_ringbuf);
-                       kfree(port);
-               }
-       }
-       soft = control->ic_soft;
-       if (soft) {
-               free_irq(control->ic_irq, soft);
-               if (soft->is_ioc4_serial_addr) {
-                       iounmap(soft->is_ioc4_serial_addr);
-                       release_mem_region((unsigned long)
-                            soft->is_ioc4_serial_addr,
-                               sizeof(struct ioc4_serial));
-               }
-               kfree(soft);
-       }
-       kfree(control);
-       idd->idd_serial_data = NULL;
-
-       return 0;
-}
-
-
-/**
- * ioc4_serial_core_attach_rs232 - register with serial core
- *             This is done during pci probing
- * @pdev: handle for this card
- */
-static inline int
-ioc4_serial_core_attach(struct pci_dev *pdev, int port_type)
-{
-       struct ioc4_port *port;
-       struct uart_port *the_port;
-       struct ioc4_driver_data *idd = pci_get_drvdata(pdev);
-       struct ioc4_control *control = idd->idd_serial_data;
-       int port_num;
-       int port_type_idx;
-       struct uart_driver *u_driver;
-
-
-       DPRINT_CONFIG(("%s: attach pdev 0x%p - control 0x%p\n",
-                       __func__, pdev, (void *)control));
-
-       if (!control)
-               return -ENODEV;
-
-       port_type_idx = (port_type == PROTO_RS232) ? UART_PORT_RS232
-                                               : UART_PORT_RS422;
-
-       u_driver = (port_type == PROTO_RS232)   ? &ioc4_uart_rs232
-                                               : &ioc4_uart_rs422;
-
-       /* once around for each port on this card */
-       for (port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; port_num++) {
-               the_port = &control->ic_port[port_num].icp_uart_port
-                                                       [port_type_idx];
-               port = control->ic_port[port_num].icp_port;
-               port->ip_all_ports[port_type_idx] = the_port;
-
-               DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p : type %s\n",
-                               __func__, (void *)the_port,
-                               (void *)port,
-                               port_type == PROTO_RS232 ? "rs232" : "rs422"));
-
-               /* membase, iobase and mapbase just need to be non-0 */
-               the_port->membase = (unsigned char __iomem *)1;
-               the_port->iobase = (pdev->bus->number << 16) |  port_num;
-               the_port->line = (Num_of_ioc4_cards << 2) | port_num;
-               the_port->mapbase = port_type;
-               the_port->type = PORT_16550A;
-               the_port->fifosize = IOC4_FIFO_CHARS;
-               the_port->ops = &ioc4_ops;
-               the_port->irq = control->ic_irq;
-               the_port->dev = &pdev->dev;
-               spin_lock_init(&the_port->lock);
-               if (uart_add_one_port(u_driver, the_port) < 0) {
-                       printk(KERN_WARNING
-                          "%s: unable to add port %d bus %d\n",
-                              __func__, the_port->line, pdev->bus->number);
-               } else {
-                       DPRINT_CONFIG(
-                           ("IOC4 serial port %d irq = %d, bus %d\n",
-                              the_port->line, the_port->irq, pdev->bus->number));
-               }
-       }
-       return 0;
-}
-
-/**
- * ioc4_serial_attach_one - register attach function
- *             called per card found from IOC4 master module.
- * @idd: Master module data for this IOC4
- */
-int
-ioc4_serial_attach_one(struct ioc4_driver_data *idd)
-{
-       unsigned long tmp_addr1;
-       struct ioc4_serial __iomem *serial;
-       struct ioc4_soft *soft;
-       struct ioc4_control *control;
-       int ret = 0;
-
-
-       DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, idd->idd_pdev,
-                                                       idd->idd_pci_id));
-
-       /* PCI-RT does not bring out serial connections.
-        * Do not attach to this particular IOC4.
-        */
-       if (idd->idd_variant == IOC4_VARIANT_PCI_RT)
-               return 0;
-
-       /* request serial registers */
-       tmp_addr1 = idd->idd_bar0 + IOC4_SERIAL_OFFSET;
-
-       if (!request_mem_region(tmp_addr1, sizeof(struct ioc4_serial),
-                                       "sioc4_uart")) {
-               printk(KERN_WARNING
-                       "ioc4 (%p): unable to get request region for "
-                               "uart space\n", (void *)idd->idd_pdev);
-               ret = -ENODEV;
-               goto out1;
-       }
-       serial = ioremap(tmp_addr1, sizeof(struct ioc4_serial));
-       if (!serial) {
-               printk(KERN_WARNING
-                        "ioc4 (%p) : unable to remap ioc4 serial register\n",
-                               (void *)idd->idd_pdev);
-               ret = -ENODEV;
-               goto out2;
-       }
-       DPRINT_CONFIG(("%s : mem 0x%p, serial 0x%p\n",
-                               __func__, (void *)idd->idd_misc_regs,
-                               (void *)serial));
-
-       /* Get memory for the new card */
-       control = kzalloc(sizeof(struct ioc4_control), GFP_KERNEL);
-
-       if (!control) {
-               printk(KERN_WARNING "ioc4_attach_one"
-                      ": unable to get memory for the IOC4\n");
-               ret = -ENOMEM;
-               goto out2;
-       }
-       idd->idd_serial_data = control;
-
-       /* Allocate the soft structure */
-       soft = kzalloc(sizeof(struct ioc4_soft), GFP_KERNEL);
-       if (!soft) {
-               printk(KERN_WARNING
-                      "ioc4 (%p): unable to get memory for the soft struct\n",
-                      (void *)idd->idd_pdev);
-               ret = -ENOMEM;
-               goto out3;
-       }
-
-       spin_lock_init(&soft->is_ir_lock);
-       soft->is_ioc4_misc_addr = idd->idd_misc_regs;
-       soft->is_ioc4_serial_addr = serial;
-
-       /* Init the IOC4 */
-       writel(0xf << IOC4_SIO_CR_CMD_PULSE_SHIFT,
-              &idd->idd_misc_regs->sio_cr.raw);
-
-       /* Enable serial port mode select generic PIO pins as outputs */
-       writel(IOC4_GPCR_UART0_MODESEL | IOC4_GPCR_UART1_MODESEL
-               | IOC4_GPCR_UART2_MODESEL | IOC4_GPCR_UART3_MODESEL,
-               &idd->idd_misc_regs->gpcr_s.raw);
-
-       /* Clear and disable all serial interrupts */
-       write_ireg(soft, ~0, IOC4_W_IEC, IOC4_SIO_INTR_TYPE);
-       writel(~0, &idd->idd_misc_regs->sio_ir.raw);
-       write_ireg(soft, IOC4_OTHER_IR_SER_MEMERR, IOC4_W_IEC,
-                  IOC4_OTHER_INTR_TYPE);
-       writel(IOC4_OTHER_IR_SER_MEMERR, &idd->idd_misc_regs->other_ir.raw);
-       control->ic_soft = soft;
-
-       /* Hook up interrupt handler */
-       if (!request_irq(idd->idd_pdev->irq, ioc4_intr, IRQF_SHARED,
-                               "sgi-ioc4serial", soft)) {
-               control->ic_irq = idd->idd_pdev->irq;
-       } else {
-               printk(KERN_WARNING
-                   "%s : request_irq fails for IRQ 0x%x\n ",
-                       __func__, idd->idd_pdev->irq);
-       }
-       ret = ioc4_attach_local(idd);
-       if (ret)
-               goto out4;
-
-       /* register port with the serial core - 1 rs232, 1 rs422 */
-
-       if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS232)))
-               goto out4;
-
-       if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS422)))
-               goto out5;
-
-       Num_of_ioc4_cards++;
-
-       return ret;
-
-       /* error exits that give back resources */
-out5:
-       ioc4_serial_remove_one(idd);
-out4:
-       kfree(soft);
-out3:
-       kfree(control);
-out2:
-       if (serial)
-               iounmap(serial);
-       release_mem_region(tmp_addr1, sizeof(struct ioc4_serial));
-out1:
-
-       return ret;
-}
-
-
-static struct ioc4_submodule ioc4_serial_submodule = {
-       .is_name = "IOC4_serial",
-       .is_owner = THIS_MODULE,
-       .is_probe = ioc4_serial_attach_one,
-       .is_remove = ioc4_serial_remove_one,
-};
-
-/**
- * ioc4_serial_init - module init
- */
-static int __init ioc4_serial_init(void)
-{
-       int ret;
-
-       /* register with serial core */
-       if ((ret = uart_register_driver(&ioc4_uart_rs232)) < 0) {
-               printk(KERN_WARNING
-                       "%s: Couldn't register rs232 IOC4 serial driver\n",
-                       __func__);
-               goto out;
-       }
-       if ((ret = uart_register_driver(&ioc4_uart_rs422)) < 0) {
-               printk(KERN_WARNING
-                       "%s: Couldn't register rs422 IOC4 serial driver\n",
-                       __func__);
-               goto out_uart_rs232;
-       }
-
-       /* register with IOC4 main module */
-       ret = ioc4_register_submodule(&ioc4_serial_submodule);
-       if (ret)
-               goto out_uart_rs422;
-       return 0;
-
-out_uart_rs422:
-       uart_unregister_driver(&ioc4_uart_rs422);
-out_uart_rs232:
-       uart_unregister_driver(&ioc4_uart_rs232);
-out:
-       return ret;
-}
-
-static void __exit ioc4_serial_exit(void)
-{
-       ioc4_unregister_submodule(&ioc4_serial_submodule);
-       uart_unregister_driver(&ioc4_uart_rs232);
-       uart_unregister_driver(&ioc4_uart_rs422);
-}
-
-late_initcall(ioc4_serial_init); /* Call only after tty init is done */
-module_exit(ioc4_serial_exit);
-
-MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) <pfg@sgi.com>");
-MODULE_DESCRIPTION("Serial PCI driver module for SGI IOC4 Base-IO Card");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/ip22zilog.c b/drivers/serial/ip22zilog.c
deleted file mode 100644 (file)
index ebff4a1..0000000
+++ /dev/null
@@ -1,1221 +0,0 @@
-/*
- * Driver for Zilog serial chips found on SGI workstations and
- * servers.  This driver could actually be made more generic.
- *
- * This is based on the drivers/serial/sunzilog.c code as of 2.6.0-test7 and the
- * old drivers/sgi/char/sgiserial.c code which itself is based of the original
- * drivers/sbus/char/zs.c code.  A lot of code has been simply moved over
- * directly from there but much has been rewritten.  Credits therefore go out
- * to David S. Miller, Eddie C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell
- * for their work there.
- *
- *  Copyright (C) 2002 Ralf Baechle (ralf@linux-mips.org)
- *  Copyright (C) 2002 David S. Miller (davem@redhat.com)
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/circ_buf.h>
-#include <linux/serial.h>
-#include <linux/sysrq.h>
-#include <linux/console.h>
-#include <linux/spinlock.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/sgialib.h>
-#include <asm/sgi/ioc.h>
-#include <asm/sgi/hpc3.h>
-#include <asm/sgi/ip22.h>
-
-#if defined(CONFIG_SERIAL_IP22_ZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
-#include "ip22zilog.h"
-
-/*
- * On IP22 we need to delay after register accesses but we do not need to
- * flush writes.
- */
-#define ZSDELAY()              udelay(5)
-#define ZSDELAY_LONG()         udelay(20)
-#define ZS_WSYNC(channel)      do { } while (0)
-
-#define NUM_IP22ZILOG          1
-#define NUM_CHANNELS           (NUM_IP22ZILOG * 2)
-
-#define ZS_CLOCK               3672000 /* Zilog input clock rate. */
-#define ZS_CLOCK_DIVISOR       16      /* Divisor this driver uses. */
-
-/*
- * We wrap our port structure around the generic uart_port.
- */
-struct uart_ip22zilog_port {
-       struct uart_port                port;
-
-       /* IRQ servicing chain.  */
-       struct uart_ip22zilog_port      *next;
-
-       /* Current values of Zilog write registers.  */
-       unsigned char                   curregs[NUM_ZSREGS];
-
-       unsigned int                    flags;
-#define IP22ZILOG_FLAG_IS_CONS         0x00000004
-#define IP22ZILOG_FLAG_IS_KGDB         0x00000008
-#define IP22ZILOG_FLAG_MODEM_STATUS    0x00000010
-#define IP22ZILOG_FLAG_IS_CHANNEL_A    0x00000020
-#define IP22ZILOG_FLAG_REGS_HELD       0x00000040
-#define IP22ZILOG_FLAG_TX_STOPPED      0x00000080
-#define IP22ZILOG_FLAG_TX_ACTIVE       0x00000100
-#define IP22ZILOG_FLAG_RESET_DONE      0x00000200
-
-       unsigned int                    tty_break;
-
-       unsigned char                   parity_mask;
-       unsigned char                   prev_status;
-};
-
-#define ZILOG_CHANNEL_FROM_PORT(PORT)  ((struct zilog_channel *)((PORT)->membase))
-#define UART_ZILOG(PORT)               ((struct uart_ip22zilog_port *)(PORT))
-#define IP22ZILOG_GET_CURR_REG(PORT, REGNUM)           \
-       (UART_ZILOG(PORT)->curregs[REGNUM])
-#define IP22ZILOG_SET_CURR_REG(PORT, REGNUM, REGVAL)   \
-       ((UART_ZILOG(PORT)->curregs[REGNUM]) = (REGVAL))
-#define ZS_IS_CONS(UP) ((UP)->flags & IP22ZILOG_FLAG_IS_CONS)
-#define ZS_IS_KGDB(UP) ((UP)->flags & IP22ZILOG_FLAG_IS_KGDB)
-#define ZS_WANTS_MODEM_STATUS(UP)      ((UP)->flags & IP22ZILOG_FLAG_MODEM_STATUS)
-#define ZS_IS_CHANNEL_A(UP)    ((UP)->flags & IP22ZILOG_FLAG_IS_CHANNEL_A)
-#define ZS_REGS_HELD(UP)       ((UP)->flags & IP22ZILOG_FLAG_REGS_HELD)
-#define ZS_TX_STOPPED(UP)      ((UP)->flags & IP22ZILOG_FLAG_TX_STOPPED)
-#define ZS_TX_ACTIVE(UP)       ((UP)->flags & IP22ZILOG_FLAG_TX_ACTIVE)
-
-/* Reading and writing Zilog8530 registers.  The delays are to make this
- * driver work on the IP22 which needs a settling delay after each chip
- * register access, other machines handle this in hardware via auxiliary
- * flip-flops which implement the settle time we do in software.
- *
- * The port lock must be held and local IRQs must be disabled
- * when {read,write}_zsreg is invoked.
- */
-static unsigned char read_zsreg(struct zilog_channel *channel,
-                               unsigned char reg)
-{
-       unsigned char retval;
-
-       writeb(reg, &channel->control);
-       ZSDELAY();
-       retval = readb(&channel->control);
-       ZSDELAY();
-
-       return retval;
-}
-
-static void write_zsreg(struct zilog_channel *channel,
-                       unsigned char reg, unsigned char value)
-{
-       writeb(reg, &channel->control);
-       ZSDELAY();
-       writeb(value, &channel->control);
-       ZSDELAY();
-}
-
-static void ip22zilog_clear_fifo(struct zilog_channel *channel)
-{
-       int i;
-
-       for (i = 0; i < 32; i++) {
-               unsigned char regval;
-
-               regval = readb(&channel->control);
-               ZSDELAY();
-               if (regval & Rx_CH_AV)
-                       break;
-
-               regval = read_zsreg(channel, R1);
-               readb(&channel->data);
-               ZSDELAY();
-
-               if (regval & (PAR_ERR | Rx_OVR | CRC_ERR)) {
-                       writeb(ERR_RES, &channel->control);
-                       ZSDELAY();
-                       ZS_WSYNC(channel);
-               }
-       }
-}
-
-/* This function must only be called when the TX is not busy.  The UART
- * port lock must be held and local interrupts disabled.
- */
-static void __load_zsregs(struct zilog_channel *channel, unsigned char *regs)
-{
-       int i;
-
-       /* Let pending transmits finish.  */
-       for (i = 0; i < 1000; i++) {
-               unsigned char stat = read_zsreg(channel, R1);
-               if (stat & ALL_SNT)
-                       break;
-               udelay(100);
-       }
-
-       writeb(ERR_RES, &channel->control);
-       ZSDELAY();
-       ZS_WSYNC(channel);
-
-       ip22zilog_clear_fifo(channel);
-
-       /* Disable all interrupts.  */
-       write_zsreg(channel, R1,
-                   regs[R1] & ~(RxINT_MASK | TxINT_ENAB | EXT_INT_ENAB));
-
-       /* Set parity, sync config, stop bits, and clock divisor.  */
-       write_zsreg(channel, R4, regs[R4]);
-
-       /* Set misc. TX/RX control bits.  */
-       write_zsreg(channel, R10, regs[R10]);
-
-       /* Set TX/RX controls sans the enable bits.  */
-       write_zsreg(channel, R3, regs[R3] & ~RxENAB);
-       write_zsreg(channel, R5, regs[R5] & ~TxENAB);
-
-       /* Synchronous mode config.  */
-       write_zsreg(channel, R6, regs[R6]);
-       write_zsreg(channel, R7, regs[R7]);
-
-       /* Don't mess with the interrupt vector (R2, unused by us) and
-        * master interrupt control (R9).  We make sure this is setup
-        * properly at probe time then never touch it again.
-        */
-
-       /* Disable baud generator.  */
-       write_zsreg(channel, R14, regs[R14] & ~BRENAB);
-
-       /* Clock mode control.  */
-       write_zsreg(channel, R11, regs[R11]);
-
-       /* Lower and upper byte of baud rate generator divisor.  */
-       write_zsreg(channel, R12, regs[R12]);
-       write_zsreg(channel, R13, regs[R13]);
-
-       /* Now rewrite R14, with BRENAB (if set).  */
-       write_zsreg(channel, R14, regs[R14]);
-
-       /* External status interrupt control.  */
-       write_zsreg(channel, R15, regs[R15]);
-
-       /* Reset external status interrupts.  */
-       write_zsreg(channel, R0, RES_EXT_INT);
-       write_zsreg(channel, R0, RES_EXT_INT);
-
-       /* Rewrite R3/R5, this time without enables masked.  */
-       write_zsreg(channel, R3, regs[R3]);
-       write_zsreg(channel, R5, regs[R5]);
-
-       /* Rewrite R1, this time without IRQ enabled masked.  */
-       write_zsreg(channel, R1, regs[R1]);
-}
-
-/* Reprogram the Zilog channel HW registers with the copies found in the
- * software state struct.  If the transmitter is busy, we defer this update
- * until the next TX complete interrupt.  Else, we do it right now.
- *
- * The UART port lock must be held and local interrupts disabled.
- */
-static void ip22zilog_maybe_update_regs(struct uart_ip22zilog_port *up,
-                                      struct zilog_channel *channel)
-{
-       if (!ZS_REGS_HELD(up)) {
-               if (ZS_TX_ACTIVE(up)) {
-                       up->flags |= IP22ZILOG_FLAG_REGS_HELD;
-               } else {
-                       __load_zsregs(channel, up->curregs);
-               }
-       }
-}
-
-#define Rx_BRK 0x0100                   /* BREAK event software flag.  */
-#define Rx_SYS 0x0200                   /* SysRq event software flag.  */
-
-static struct tty_struct *ip22zilog_receive_chars(struct uart_ip22zilog_port *up,
-                                                 struct zilog_channel *channel)
-{
-       struct tty_struct *tty;
-       unsigned char ch, flag;
-       unsigned int r1;
-
-       tty = NULL;
-       if (up->port.state != NULL &&
-           up->port.state->port.tty != NULL)
-               tty = up->port.state->port.tty;
-
-       for (;;) {
-               ch = readb(&channel->control);
-               ZSDELAY();
-               if (!(ch & Rx_CH_AV))
-                       break;
-
-               r1 = read_zsreg(channel, R1);
-               if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
-                       writeb(ERR_RES, &channel->control);
-                       ZSDELAY();
-                       ZS_WSYNC(channel);
-               }
-
-               ch = readb(&channel->data);
-               ZSDELAY();
-
-               ch &= up->parity_mask;
-
-               /* Handle the null char got when BREAK is removed.  */
-               if (!ch)
-                       r1 |= up->tty_break;
-
-               /* A real serial line, record the character and status.  */
-               flag = TTY_NORMAL;
-               up->port.icount.rx++;
-               if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | Rx_SYS | Rx_BRK)) {
-                       up->tty_break = 0;
-
-                       if (r1 & (Rx_SYS | Rx_BRK)) {
-                               up->port.icount.brk++;
-                               if (r1 & Rx_SYS)
-                                       continue;
-                               r1 &= ~(PAR_ERR | CRC_ERR);
-                       }
-                       else if (r1 & PAR_ERR)
-                               up->port.icount.parity++;
-                       else if (r1 & CRC_ERR)
-                               up->port.icount.frame++;
-                       if (r1 & Rx_OVR)
-                               up->port.icount.overrun++;
-                       r1 &= up->port.read_status_mask;
-                       if (r1 & Rx_BRK)
-                               flag = TTY_BREAK;
-                       else if (r1 & PAR_ERR)
-                               flag = TTY_PARITY;
-                       else if (r1 & CRC_ERR)
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(&up->port, ch))
-                       continue;
-
-               if (tty)
-                       uart_insert_char(&up->port, r1, Rx_OVR, ch, flag);
-       }
-       return tty;
-}
-
-static void ip22zilog_status_handle(struct uart_ip22zilog_port *up,
-                                  struct zilog_channel *channel)
-{
-       unsigned char status;
-
-       status = readb(&channel->control);
-       ZSDELAY();
-
-       writeb(RES_EXT_INT, &channel->control);
-       ZSDELAY();
-       ZS_WSYNC(channel);
-
-       if (up->curregs[R15] & BRKIE) {
-               if ((status & BRK_ABRT) && !(up->prev_status & BRK_ABRT)) {
-                       if (uart_handle_break(&up->port))
-                               up->tty_break = Rx_SYS;
-                       else
-                               up->tty_break = Rx_BRK;
-               }
-       }
-
-       if (ZS_WANTS_MODEM_STATUS(up)) {
-               if (status & SYNC)
-                       up->port.icount.dsr++;
-
-               /* The Zilog just gives us an interrupt when DCD/CTS/etc. change.
-                * But it does not tell us which bit has changed, we have to keep
-                * track of this ourselves.
-                */
-               if ((status ^ up->prev_status) ^ DCD)
-                       uart_handle_dcd_change(&up->port,
-                                              (status & DCD));
-               if ((status ^ up->prev_status) ^ CTS)
-                       uart_handle_cts_change(&up->port,
-                                              (status & CTS));
-
-               wake_up_interruptible(&up->port.state->port.delta_msr_wait);
-       }
-
-       up->prev_status = status;
-}
-
-static void ip22zilog_transmit_chars(struct uart_ip22zilog_port *up,
-                                   struct zilog_channel *channel)
-{
-       struct circ_buf *xmit;
-
-       if (ZS_IS_CONS(up)) {
-               unsigned char status = readb(&channel->control);
-               ZSDELAY();
-
-               /* TX still busy?  Just wait for the next TX done interrupt.
-                *
-                * It can occur because of how we do serial console writes.  It would
-                * be nice to transmit console writes just like we normally would for
-                * a TTY line. (ie. buffered and TX interrupt driven).  That is not
-                * easy because console writes cannot sleep.  One solution might be
-                * to poll on enough port->xmit space becomming free.  -DaveM
-                */
-               if (!(status & Tx_BUF_EMP))
-                       return;
-       }
-
-       up->flags &= ~IP22ZILOG_FLAG_TX_ACTIVE;
-
-       if (ZS_REGS_HELD(up)) {
-               __load_zsregs(channel, up->curregs);
-               up->flags &= ~IP22ZILOG_FLAG_REGS_HELD;
-       }
-
-       if (ZS_TX_STOPPED(up)) {
-               up->flags &= ~IP22ZILOG_FLAG_TX_STOPPED;
-               goto ack_tx_int;
-       }
-
-       if (up->port.x_char) {
-               up->flags |= IP22ZILOG_FLAG_TX_ACTIVE;
-               writeb(up->port.x_char, &channel->data);
-               ZSDELAY();
-               ZS_WSYNC(channel);
-
-               up->port.icount.tx++;
-               up->port.x_char = 0;
-               return;
-       }
-
-       if (up->port.state == NULL)
-               goto ack_tx_int;
-       xmit = &up->port.state->xmit;
-       if (uart_circ_empty(xmit))
-               goto ack_tx_int;
-       if (uart_tx_stopped(&up->port))
-               goto ack_tx_int;
-
-       up->flags |= IP22ZILOG_FLAG_TX_ACTIVE;
-       writeb(xmit->buf[xmit->tail], &channel->data);
-       ZSDELAY();
-       ZS_WSYNC(channel);
-
-       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-       up->port.icount.tx++;
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&up->port);
-
-       return;
-
-ack_tx_int:
-       writeb(RES_Tx_P, &channel->control);
-       ZSDELAY();
-       ZS_WSYNC(channel);
-}
-
-static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id)
-{
-       struct uart_ip22zilog_port *up = dev_id;
-
-       while (up) {
-               struct zilog_channel *channel
-                       = ZILOG_CHANNEL_FROM_PORT(&up->port);
-               struct tty_struct *tty;
-               unsigned char r3;
-
-               spin_lock(&up->port.lock);
-               r3 = read_zsreg(channel, R3);
-
-               /* Channel A */
-               tty = NULL;
-               if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
-                       writeb(RES_H_IUS, &channel->control);
-                       ZSDELAY();
-                       ZS_WSYNC(channel);
-
-                       if (r3 & CHARxIP)
-                               tty = ip22zilog_receive_chars(up, channel);
-                       if (r3 & CHAEXT)
-                               ip22zilog_status_handle(up, channel);
-                       if (r3 & CHATxIP)
-                               ip22zilog_transmit_chars(up, channel);
-               }
-               spin_unlock(&up->port.lock);
-
-               if (tty)
-                       tty_flip_buffer_push(tty);
-
-               /* Channel B */
-               up = up->next;
-               channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
-
-               spin_lock(&up->port.lock);
-               tty = NULL;
-               if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
-                       writeb(RES_H_IUS, &channel->control);
-                       ZSDELAY();
-                       ZS_WSYNC(channel);
-
-                       if (r3 & CHBRxIP)
-                               tty = ip22zilog_receive_chars(up, channel);
-                       if (r3 & CHBEXT)
-                               ip22zilog_status_handle(up, channel);
-                       if (r3 & CHBTxIP)
-                               ip22zilog_transmit_chars(up, channel);
-               }
-               spin_unlock(&up->port.lock);
-
-               if (tty)
-                       tty_flip_buffer_push(tty);
-
-               up = up->next;
-       }
-
-       return IRQ_HANDLED;
-}
-
-/* A convenient way to quickly get R0 status.  The caller must _not_ hold the
- * port lock, it is acquired here.
- */
-static __inline__ unsigned char ip22zilog_read_channel_status(struct uart_port *port)
-{
-       struct zilog_channel *channel;
-       unsigned char status;
-
-       channel = ZILOG_CHANNEL_FROM_PORT(port);
-       status = readb(&channel->control);
-       ZSDELAY();
-
-       return status;
-}
-
-/* The port lock is not held.  */
-static unsigned int ip22zilog_tx_empty(struct uart_port *port)
-{
-       unsigned long flags;
-       unsigned char status;
-       unsigned int ret;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       status = ip22zilog_read_channel_status(port);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       if (status & Tx_BUF_EMP)
-               ret = TIOCSER_TEMT;
-       else
-               ret = 0;
-
-       return ret;
-}
-
-/* The port lock is held and interrupts are disabled.  */
-static unsigned int ip22zilog_get_mctrl(struct uart_port *port)
-{
-       unsigned char status;
-       unsigned int ret;
-
-       status = ip22zilog_read_channel_status(port);
-
-       ret = 0;
-       if (status & DCD)
-               ret |= TIOCM_CAR;
-       if (status & SYNC)
-               ret |= TIOCM_DSR;
-       if (status & CTS)
-               ret |= TIOCM_CTS;
-
-       return ret;
-}
-
-/* The port lock is held and interrupts are disabled.  */
-static void ip22zilog_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
-       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
-       unsigned char set_bits, clear_bits;
-
-       set_bits = clear_bits = 0;
-
-       if (mctrl & TIOCM_RTS)
-               set_bits |= RTS;
-       else
-               clear_bits |= RTS;
-       if (mctrl & TIOCM_DTR)
-               set_bits |= DTR;
-       else
-               clear_bits |= DTR;
-
-       /* NOTE: Not subject to 'transmitter active' rule.  */
-       up->curregs[R5] |= set_bits;
-       up->curregs[R5] &= ~clear_bits;
-       write_zsreg(channel, R5, up->curregs[R5]);
-}
-
-/* The port lock is held and interrupts are disabled.  */
-static void ip22zilog_stop_tx(struct uart_port *port)
-{
-       struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
-
-       up->flags |= IP22ZILOG_FLAG_TX_STOPPED;
-}
-
-/* The port lock is held and interrupts are disabled.  */
-static void ip22zilog_start_tx(struct uart_port *port)
-{
-       struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
-       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
-       unsigned char status;
-
-       up->flags |= IP22ZILOG_FLAG_TX_ACTIVE;
-       up->flags &= ~IP22ZILOG_FLAG_TX_STOPPED;
-
-       status = readb(&channel->control);
-       ZSDELAY();
-
-       /* TX busy?  Just wait for the TX done interrupt.  */
-       if (!(status & Tx_BUF_EMP))
-               return;
-
-       /* Send the first character to jump-start the TX done
-        * IRQ sending engine.
-        */
-       if (port->x_char) {
-               writeb(port->x_char, &channel->data);
-               ZSDELAY();
-               ZS_WSYNC(channel);
-
-               port->icount.tx++;
-               port->x_char = 0;
-       } else {
-               struct circ_buf *xmit = &port->state->xmit;
-
-               writeb(xmit->buf[xmit->tail], &channel->data);
-               ZSDELAY();
-               ZS_WSYNC(channel);
-
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-
-               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-                       uart_write_wakeup(&up->port);
-       }
-}
-
-/* The port lock is held and interrupts are disabled.  */
-static void ip22zilog_stop_rx(struct uart_port *port)
-{
-       struct uart_ip22zilog_port *up = UART_ZILOG(port);
-       struct zilog_channel *channel;
-
-       if (ZS_IS_CONS(up))
-               return;
-
-       channel = ZILOG_CHANNEL_FROM_PORT(port);
-
-       /* Disable all RX interrupts.  */
-       up->curregs[R1] &= ~RxINT_MASK;
-       ip22zilog_maybe_update_regs(up, channel);
-}
-
-/* The port lock is held.  */
-static void ip22zilog_enable_ms(struct uart_port *port)
-{
-       struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
-       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
-       unsigned char new_reg;
-
-       new_reg = up->curregs[R15] | (DCDIE | SYNCIE | CTSIE);
-       if (new_reg != up->curregs[R15]) {
-               up->curregs[R15] = new_reg;
-
-               /* NOTE: Not subject to 'transmitter active' rule.  */
-               write_zsreg(channel, R15, up->curregs[R15]);
-       }
-}
-
-/* The port lock is not held.  */
-static void ip22zilog_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
-       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
-       unsigned char set_bits, clear_bits, new_reg;
-       unsigned long flags;
-
-       set_bits = clear_bits = 0;
-
-       if (break_state)
-               set_bits |= SND_BRK;
-       else
-               clear_bits |= SND_BRK;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       new_reg = (up->curregs[R5] | set_bits) & ~clear_bits;
-       if (new_reg != up->curregs[R5]) {
-               up->curregs[R5] = new_reg;
-
-               /* NOTE: Not subject to 'transmitter active' rule.  */
-               write_zsreg(channel, R5, up->curregs[R5]);
-       }
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void __ip22zilog_reset(struct uart_ip22zilog_port *up)
-{
-       struct zilog_channel *channel;
-       int i;
-
-       if (up->flags & IP22ZILOG_FLAG_RESET_DONE)
-               return;
-
-       /* Let pending transmits finish.  */
-       channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
-       for (i = 0; i < 1000; i++) {
-               unsigned char stat = read_zsreg(channel, R1);
-               if (stat & ALL_SNT)
-                       break;
-               udelay(100);
-       }
-
-       if (!ZS_IS_CHANNEL_A(up)) {
-               up++;
-               channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
-       }
-       write_zsreg(channel, R9, FHWRES);
-       ZSDELAY_LONG();
-       (void) read_zsreg(channel, R0);
-
-       up->flags |= IP22ZILOG_FLAG_RESET_DONE;
-       up->next->flags |= IP22ZILOG_FLAG_RESET_DONE;
-}
-
-static void __ip22zilog_startup(struct uart_ip22zilog_port *up)
-{
-       struct zilog_channel *channel;
-
-       channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
-
-       __ip22zilog_reset(up);
-
-       __load_zsregs(channel, up->curregs);
-       /* set master interrupt enable */
-       write_zsreg(channel, R9, up->curregs[R9]);
-       up->prev_status = readb(&channel->control);
-
-       /* Enable receiver and transmitter.  */
-       up->curregs[R3] |= RxENAB;
-       up->curregs[R5] |= TxENAB;
-
-       up->curregs[R1] |= EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
-       ip22zilog_maybe_update_regs(up, channel);
-}
-
-static int ip22zilog_startup(struct uart_port *port)
-{
-       struct uart_ip22zilog_port *up = UART_ZILOG(port);
-       unsigned long flags;
-
-       if (ZS_IS_CONS(up))
-               return 0;
-
-       spin_lock_irqsave(&port->lock, flags);
-       __ip22zilog_startup(up);
-       spin_unlock_irqrestore(&port->lock, flags);
-       return 0;
-}
-
-/*
- * The test for ZS_IS_CONS is explained by the following e-mail:
- *****
- * From: Russell King <rmk@arm.linux.org.uk>
- * Date: Sun, 8 Dec 2002 10:18:38 +0000
- *
- * On Sun, Dec 08, 2002 at 02:43:36AM -0500, Pete Zaitcev wrote:
- * > I boot my 2.5 boxes using "console=ttyS0,9600" argument,
- * > and I noticed that something is not right with reference
- * > counting in this case. It seems that when the console
- * > is open by kernel initially, this is not accounted
- * > as an open, and uart_startup is not called.
- *
- * That is correct.  We are unable to call uart_startup when the serial
- * console is initialised because it may need to allocate memory (as
- * request_irq does) and the memory allocators may not have been
- * initialised.
- *
- * 1. initialise the port into a state where it can send characters in the
- *    console write method.
- *
- * 2. don't do the actual hardware shutdown in your shutdown() method (but
- *    do the normal software shutdown - ie, free irqs etc)
- *****
- */
-static void ip22zilog_shutdown(struct uart_port *port)
-{
-       struct uart_ip22zilog_port *up = UART_ZILOG(port);
-       struct zilog_channel *channel;
-       unsigned long flags;
-
-       if (ZS_IS_CONS(up))
-               return;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       channel = ZILOG_CHANNEL_FROM_PORT(port);
-
-       /* Disable receiver and transmitter.  */
-       up->curregs[R3] &= ~RxENAB;
-       up->curregs[R5] &= ~TxENAB;
-
-       /* Disable all interrupts and BRK assertion.  */
-       up->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
-       up->curregs[R5] &= ~SND_BRK;
-       ip22zilog_maybe_update_regs(up, channel);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/* Shared by TTY driver and serial console setup.  The port lock is held
- * and local interrupts are disabled.
- */
-static void
-ip22zilog_convert_to_zs(struct uart_ip22zilog_port *up, unsigned int cflag,
-                      unsigned int iflag, int brg)
-{
-
-       up->curregs[R10] = NRZ;
-       up->curregs[R11] = TCBR | RCBR;
-
-       /* Program BAUD and clock source. */
-       up->curregs[R4] &= ~XCLK_MASK;
-       up->curregs[R4] |= X16CLK;
-       up->curregs[R12] = brg & 0xff;
-       up->curregs[R13] = (brg >> 8) & 0xff;
-       up->curregs[R14] = BRENAB;
-
-       /* Character size, stop bits, and parity. */
-       up->curregs[3] &= ~RxN_MASK;
-       up->curregs[5] &= ~TxN_MASK;
-       switch (cflag & CSIZE) {
-       case CS5:
-               up->curregs[3] |= Rx5;
-               up->curregs[5] |= Tx5;
-               up->parity_mask = 0x1f;
-               break;
-       case CS6:
-               up->curregs[3] |= Rx6;
-               up->curregs[5] |= Tx6;
-               up->parity_mask = 0x3f;
-               break;
-       case CS7:
-               up->curregs[3] |= Rx7;
-               up->curregs[5] |= Tx7;
-               up->parity_mask = 0x7f;
-               break;
-       case CS8:
-       default:
-               up->curregs[3] |= Rx8;
-               up->curregs[5] |= Tx8;
-               up->parity_mask = 0xff;
-               break;
-       };
-       up->curregs[4] &= ~0x0c;
-       if (cflag & CSTOPB)
-               up->curregs[4] |= SB2;
-       else
-               up->curregs[4] |= SB1;
-       if (cflag & PARENB)
-               up->curregs[4] |= PAR_ENAB;
-       else
-               up->curregs[4] &= ~PAR_ENAB;
-       if (!(cflag & PARODD))
-               up->curregs[4] |= PAR_EVEN;
-       else
-               up->curregs[4] &= ~PAR_EVEN;
-
-       up->port.read_status_mask = Rx_OVR;
-       if (iflag & INPCK)
-               up->port.read_status_mask |= CRC_ERR | PAR_ERR;
-       if (iflag & (BRKINT | PARMRK))
-               up->port.read_status_mask |= BRK_ABRT;
-
-       up->port.ignore_status_mask = 0;
-       if (iflag & IGNPAR)
-               up->port.ignore_status_mask |= CRC_ERR | PAR_ERR;
-       if (iflag & IGNBRK) {
-               up->port.ignore_status_mask |= BRK_ABRT;
-               if (iflag & IGNPAR)
-                       up->port.ignore_status_mask |= Rx_OVR;
-       }
-
-       if ((cflag & CREAD) == 0)
-               up->port.ignore_status_mask = 0xff;
-}
-
-/* The port lock is not held.  */
-static void
-ip22zilog_set_termios(struct uart_port *port, struct ktermios *termios,
-                     struct ktermios *old)
-{
-       struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
-       unsigned long flags;
-       int baud, brg;
-
-       baud = uart_get_baud_rate(port, termios, old, 1200, 76800);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
-
-       ip22zilog_convert_to_zs(up, termios->c_cflag, termios->c_iflag, brg);
-
-       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
-               up->flags |= IP22ZILOG_FLAG_MODEM_STATUS;
-       else
-               up->flags &= ~IP22ZILOG_FLAG_MODEM_STATUS;
-
-       ip22zilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port));
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static const char *ip22zilog_type(struct uart_port *port)
-{
-       return "IP22-Zilog";
-}
-
-/* We do not request/release mappings of the registers here, this
- * happens at early serial probe time.
- */
-static void ip22zilog_release_port(struct uart_port *port)
-{
-}
-
-static int ip22zilog_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-/* These do not need to do anything interesting either.  */
-static void ip22zilog_config_port(struct uart_port *port, int flags)
-{
-}
-
-/* We do not support letting the user mess with the divisor, IRQ, etc. */
-static int ip22zilog_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       return -EINVAL;
-}
-
-static struct uart_ops ip22zilog_pops = {
-       .tx_empty       =       ip22zilog_tx_empty,
-       .set_mctrl      =       ip22zilog_set_mctrl,
-       .get_mctrl      =       ip22zilog_get_mctrl,
-       .stop_tx        =       ip22zilog_stop_tx,
-       .start_tx       =       ip22zilog_start_tx,
-       .stop_rx        =       ip22zilog_stop_rx,
-       .enable_ms      =       ip22zilog_enable_ms,
-       .break_ctl      =       ip22zilog_break_ctl,
-       .startup        =       ip22zilog_startup,
-       .shutdown       =       ip22zilog_shutdown,
-       .set_termios    =       ip22zilog_set_termios,
-       .type           =       ip22zilog_type,
-       .release_port   =       ip22zilog_release_port,
-       .request_port   =       ip22zilog_request_port,
-       .config_port    =       ip22zilog_config_port,
-       .verify_port    =       ip22zilog_verify_port,
-};
-
-static struct uart_ip22zilog_port *ip22zilog_port_table;
-static struct zilog_layout **ip22zilog_chip_regs;
-
-static struct uart_ip22zilog_port *ip22zilog_irq_chain;
-static int zilog_irq = -1;
-
-static void * __init alloc_one_table(unsigned long size)
-{
-       return kzalloc(size, GFP_KERNEL);
-}
-
-static void __init ip22zilog_alloc_tables(void)
-{
-       ip22zilog_port_table = (struct uart_ip22zilog_port *)
-               alloc_one_table(NUM_CHANNELS * sizeof(struct uart_ip22zilog_port));
-       ip22zilog_chip_regs = (struct zilog_layout **)
-               alloc_one_table(NUM_IP22ZILOG * sizeof(struct zilog_layout *));
-
-       if (ip22zilog_port_table == NULL || ip22zilog_chip_regs == NULL) {
-               panic("IP22-Zilog: Cannot allocate IP22-Zilog tables.");
-       }
-}
-
-/* Get the address of the registers for IP22-Zilog instance CHIP.  */
-static struct zilog_layout * __init get_zs(int chip)
-{
-       unsigned long base;
-
-       if (chip < 0 || chip >= NUM_IP22ZILOG) {
-               panic("IP22-Zilog: Illegal chip number %d in get_zs.", chip);
-       }
-
-       /* Not probe-able, hard code it. */
-       base = (unsigned long) &sgioc->uart;
-
-       zilog_irq = SGI_SERIAL_IRQ;
-       request_mem_region(base, 8, "IP22-Zilog");
-
-       return (struct zilog_layout *) base;
-}
-
-#define ZS_PUT_CHAR_MAX_DELAY  2000    /* 10 ms */
-
-#ifdef CONFIG_SERIAL_IP22_ZILOG_CONSOLE
-static void ip22zilog_put_char(struct uart_port *port, int ch)
-{
-       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
-       int loops = ZS_PUT_CHAR_MAX_DELAY;
-
-       /* This is a timed polling loop so do not switch the explicit
-        * udelay with ZSDELAY as that is a NOP on some platforms.  -DaveM
-        */
-       do {
-               unsigned char val = readb(&channel->control);
-               if (val & Tx_BUF_EMP) {
-                       ZSDELAY();
-                       break;
-               }
-               udelay(5);
-       } while (--loops);
-
-       writeb(ch, &channel->data);
-       ZSDELAY();
-       ZS_WSYNC(channel);
-}
-
-static void
-ip22zilog_console_write(struct console *con, const char *s, unsigned int count)
-{
-       struct uart_ip22zilog_port *up = &ip22zilog_port_table[con->index];
-       unsigned long flags;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       uart_console_write(&up->port, s, count, ip22zilog_put_char);
-       udelay(2);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static int __init ip22zilog_console_setup(struct console *con, char *options)
-{
-       struct uart_ip22zilog_port *up = &ip22zilog_port_table[con->index];
-       unsigned long flags;
-       int baud = 9600, bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       up->flags |= IP22ZILOG_FLAG_IS_CONS;
-
-       printk(KERN_INFO "Console: ttyS%d (IP22-Zilog)\n", con->index);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       up->curregs[R15] |= BRKIE;
-
-       __ip22zilog_startup(up);
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       return uart_set_options(&up->port, con, baud, parity, bits, flow);
-}
-
-static struct uart_driver ip22zilog_reg;
-
-static struct console ip22zilog_console = {
-       .name   =       "ttyS",
-       .write  =       ip22zilog_console_write,
-       .device =       uart_console_device,
-       .setup  =       ip22zilog_console_setup,
-       .flags  =       CON_PRINTBUFFER,
-       .index  =       -1,
-       .data   =       &ip22zilog_reg,
-};
-#endif /* CONFIG_SERIAL_IP22_ZILOG_CONSOLE */
-
-static struct uart_driver ip22zilog_reg = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "serial",
-       .dev_name       = "ttyS",
-       .major          = TTY_MAJOR,
-       .minor          = 64,
-       .nr             = NUM_CHANNELS,
-#ifdef CONFIG_SERIAL_IP22_ZILOG_CONSOLE
-       .cons           = &ip22zilog_console,
-#endif
-};
-
-static void __init ip22zilog_prepare(void)
-{
-       struct uart_ip22zilog_port *up;
-       struct zilog_layout *rp;
-       int channel, chip;
-
-       /*
-        * Temporary fix.
-        */
-       for (channel = 0; channel < NUM_CHANNELS; channel++)
-               spin_lock_init(&ip22zilog_port_table[channel].port.lock);
-
-       ip22zilog_irq_chain = &ip22zilog_port_table[NUM_CHANNELS - 1];
-        up = &ip22zilog_port_table[0];
-       for (channel = NUM_CHANNELS - 1 ; channel > 0; channel--)
-               up[channel].next = &up[channel - 1];
-       up[channel].next = NULL;
-
-       for (chip = 0; chip < NUM_IP22ZILOG; chip++) {
-               if (!ip22zilog_chip_regs[chip]) {
-                       ip22zilog_chip_regs[chip] = rp = get_zs(chip);
-
-                       up[(chip * 2) + 0].port.membase = (char *) &rp->channelB;
-                       up[(chip * 2) + 1].port.membase = (char *) &rp->channelA;
-
-                       /* In theory mapbase is the physical address ...  */
-                       up[(chip * 2) + 0].port.mapbase =
-                               (unsigned long) ioremap((unsigned long) &rp->channelB, 8);
-                       up[(chip * 2) + 1].port.mapbase =
-                               (unsigned long) ioremap((unsigned long) &rp->channelA, 8);
-               }
-
-               /* Channel A */
-               up[(chip * 2) + 0].port.iotype = UPIO_MEM;
-               up[(chip * 2) + 0].port.irq = zilog_irq;
-               up[(chip * 2) + 0].port.uartclk = ZS_CLOCK;
-               up[(chip * 2) + 0].port.fifosize = 1;
-               up[(chip * 2) + 0].port.ops = &ip22zilog_pops;
-               up[(chip * 2) + 0].port.type = PORT_IP22ZILOG;
-               up[(chip * 2) + 0].port.flags = 0;
-               up[(chip * 2) + 0].port.line = (chip * 2) + 0;
-               up[(chip * 2) + 0].flags = 0;
-
-               /* Channel B */
-               up[(chip * 2) + 1].port.iotype = UPIO_MEM;
-               up[(chip * 2) + 1].port.irq = zilog_irq;
-               up[(chip * 2) + 1].port.uartclk = ZS_CLOCK;
-               up[(chip * 2) + 1].port.fifosize = 1;
-               up[(chip * 2) + 1].port.ops = &ip22zilog_pops;
-               up[(chip * 2) + 1].port.type = PORT_IP22ZILOG;
-               up[(chip * 2) + 1].port.line = (chip * 2) + 1;
-               up[(chip * 2) + 1].flags |= IP22ZILOG_FLAG_IS_CHANNEL_A;
-       }
-
-       for (channel = 0; channel < NUM_CHANNELS; channel++) {
-               struct uart_ip22zilog_port *up = &ip22zilog_port_table[channel];
-               int brg;
-
-               /* Normal serial TTY. */
-               up->parity_mask = 0xff;
-               up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
-               up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
-               up->curregs[R3] = RxENAB | Rx8;
-               up->curregs[R5] = TxENAB | Tx8;
-               up->curregs[R9] = NV | MIE;
-               up->curregs[R10] = NRZ;
-               up->curregs[R11] = TCBR | RCBR;
-               brg = BPS_TO_BRG(9600, ZS_CLOCK / ZS_CLOCK_DIVISOR);
-               up->curregs[R12] = (brg & 0xff);
-               up->curregs[R13] = (brg >> 8) & 0xff;
-               up->curregs[R14] = BRENAB;
-       }
-}
-
-static int __init ip22zilog_ports_init(void)
-{
-       int ret;
-
-       printk(KERN_INFO "Serial: IP22 Zilog driver (%d chips).\n", NUM_IP22ZILOG);
-
-       ip22zilog_prepare();
-
-       if (request_irq(zilog_irq, ip22zilog_interrupt, 0,
-                       "IP22-Zilog", ip22zilog_irq_chain)) {
-               panic("IP22-Zilog: Unable to register zs interrupt handler.\n");
-       }
-
-       ret = uart_register_driver(&ip22zilog_reg);
-       if (ret == 0) {
-               int i;
-
-               for (i = 0; i < NUM_CHANNELS; i++) {
-                       struct uart_ip22zilog_port *up = &ip22zilog_port_table[i];
-
-                       uart_add_one_port(&ip22zilog_reg, &up->port);
-               }
-       }
-
-       return ret;
-}
-
-static int __init ip22zilog_init(void)
-{
-       /* IP22 Zilog setup is hard coded, no probing to do.  */
-       ip22zilog_alloc_tables();
-       ip22zilog_ports_init();
-
-       return 0;
-}
-
-static void __exit ip22zilog_exit(void)
-{
-       int i;
-       struct uart_ip22zilog_port *up;
-
-       for (i = 0; i < NUM_CHANNELS; i++) {
-               up = &ip22zilog_port_table[i];
-
-               uart_remove_one_port(&ip22zilog_reg, &up->port);
-       }
-
-       /* Free IO mem */
-       up = &ip22zilog_port_table[0];
-       for (i = 0; i < NUM_IP22ZILOG; i++) {
-               if (up[(i * 2) + 0].port.mapbase) {
-                  iounmap((void*)up[(i * 2) + 0].port.mapbase);
-                  up[(i * 2) + 0].port.mapbase = 0;
-               }
-               if (up[(i * 2) + 1].port.mapbase) {
-                       iounmap((void*)up[(i * 2) + 1].port.mapbase);
-                       up[(i * 2) + 1].port.mapbase = 0;
-               }
-       }
-
-       uart_unregister_driver(&ip22zilog_reg);
-}
-
-module_init(ip22zilog_init);
-module_exit(ip22zilog_exit);
-
-/* David wrote it but I'm to blame for the bugs ...  */
-MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
-MODULE_DESCRIPTION("SGI Zilog serial port driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/ip22zilog.h b/drivers/serial/ip22zilog.h
deleted file mode 100644 (file)
index a59a9a8..0000000
+++ /dev/null
@@ -1,281 +0,0 @@
-#ifndef _IP22_ZILOG_H
-#define _IP22_ZILOG_H
-
-#include <asm/byteorder.h>
-
-struct zilog_channel {
-#ifdef __BIG_ENDIAN
-       volatile unsigned char unused0[3];
-       volatile unsigned char control;
-       volatile unsigned char unused1[3];
-       volatile unsigned char data;
-#else /* __LITTLE_ENDIAN */
-       volatile unsigned char control;
-       volatile unsigned char unused0[3];
-       volatile unsigned char data;
-       volatile unsigned char unused1[3];
-#endif
-};
-
-struct zilog_layout {
-       struct zilog_channel channelB;
-       struct zilog_channel channelA;
-};
-
-#define NUM_ZSREGS    16
-
-/* Conversion routines to/from brg time constants from/to bits
- * per second.
- */
-#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
-#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
-
-/* The Zilog register set */
-
-#define        FLAG    0x7e
-
-/* Write Register 0 */
-#define        R0      0               /* Register selects */
-#define        R1      1
-#define        R2      2
-#define        R3      3
-#define        R4      4
-#define        R5      5
-#define        R6      6
-#define        R7      7
-#define        R8      8
-#define        R9      9
-#define        R10     10
-#define        R11     11
-#define        R12     12
-#define        R13     13
-#define        R14     14
-#define        R15     15
-
-#define        NULLCODE        0       /* Null Code */
-#define        POINT_HIGH      0x8     /* Select upper half of registers */
-#define        RES_EXT_INT     0x10    /* Reset Ext. Status Interrupts */
-#define        SEND_ABORT      0x18    /* HDLC Abort */
-#define        RES_RxINT_FC    0x20    /* Reset RxINT on First Character */
-#define        RES_Tx_P        0x28    /* Reset TxINT Pending */
-#define        ERR_RES         0x30    /* Error Reset */
-#define        RES_H_IUS       0x38    /* Reset highest IUS */
-
-#define        RES_Rx_CRC      0x40    /* Reset Rx CRC Checker */
-#define        RES_Tx_CRC      0x80    /* Reset Tx CRC Checker */
-#define        RES_EOM_L       0xC0    /* Reset EOM latch */
-
-/* Write Register 1 */
-
-#define        EXT_INT_ENAB    0x1     /* Ext Int Enable */
-#define        TxINT_ENAB      0x2     /* Tx Int Enable */
-#define        PAR_SPEC        0x4     /* Parity is special condition */
-
-#define        RxINT_DISAB     0       /* Rx Int Disable */
-#define        RxINT_FCERR     0x8     /* Rx Int on First Character Only or Error */
-#define        INT_ALL_Rx      0x10    /* Int on all Rx Characters or error */
-#define        INT_ERR_Rx      0x18    /* Int on error only */
-#define RxINT_MASK     0x18
-
-#define        WT_RDY_RT       0x20    /* Wait/Ready on R/T */
-#define        WT_FN_RDYFN     0x40    /* Wait/FN/Ready FN */
-#define        WT_RDY_ENAB     0x80    /* Wait/Ready Enable */
-
-/* Write Register #2 (Interrupt Vector) */
-
-/* Write Register 3 */
-
-#define        RxENAB          0x1     /* Rx Enable */
-#define        SYNC_L_INH      0x2     /* Sync Character Load Inhibit */
-#define        ADD_SM          0x4     /* Address Search Mode (SDLC) */
-#define        RxCRC_ENAB      0x8     /* Rx CRC Enable */
-#define        ENT_HM          0x10    /* Enter Hunt Mode */
-#define        AUTO_ENAB       0x20    /* Auto Enables */
-#define        Rx5             0x0     /* Rx 5 Bits/Character */
-#define        Rx7             0x40    /* Rx 7 Bits/Character */
-#define        Rx6             0x80    /* Rx 6 Bits/Character */
-#define        Rx8             0xc0    /* Rx 8 Bits/Character */
-#define RxN_MASK       0xc0
-
-/* Write Register 4 */
-
-#define        PAR_ENAB        0x1     /* Parity Enable */
-#define        PAR_EVEN        0x2     /* Parity Even/Odd* */
-
-#define        SYNC_ENAB       0       /* Sync Modes Enable */
-#define        SB1             0x4     /* 1 stop bit/char */
-#define        SB15            0x8     /* 1.5 stop bits/char */
-#define        SB2             0xc     /* 2 stop bits/char */
-
-#define        MONSYNC         0       /* 8 Bit Sync character */
-#define        BISYNC          0x10    /* 16 bit sync character */
-#define        SDLC            0x20    /* SDLC Mode (01111110 Sync Flag) */
-#define        EXTSYNC         0x30    /* External Sync Mode */
-
-#define        X1CLK           0x0     /* x1 clock mode */
-#define        X16CLK          0x40    /* x16 clock mode */
-#define        X32CLK          0x80    /* x32 clock mode */
-#define        X64CLK          0xC0    /* x64 clock mode */
-#define XCLK_MASK      0xC0
-
-/* Write Register 5 */
-
-#define        TxCRC_ENAB      0x1     /* Tx CRC Enable */
-#define        RTS             0x2     /* RTS */
-#define        SDLC_CRC        0x4     /* SDLC/CRC-16 */
-#define        TxENAB          0x8     /* Tx Enable */
-#define        SND_BRK         0x10    /* Send Break */
-#define        Tx5             0x0     /* Tx 5 bits (or less)/character */
-#define        Tx7             0x20    /* Tx 7 bits/character */
-#define        Tx6             0x40    /* Tx 6 bits/character */
-#define        Tx8             0x60    /* Tx 8 bits/character */
-#define TxN_MASK       0x60
-#define        DTR             0x80    /* DTR */
-
-/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
-
-/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
-
-/* Write Register 8 (transmit buffer) */
-
-/* Write Register 9 (Master interrupt control) */
-#define        VIS     1       /* Vector Includes Status */
-#define        NV      2       /* No Vector */
-#define        DLC     4       /* Disable Lower Chain */
-#define        MIE     8       /* Master Interrupt Enable */
-#define        STATHI  0x10    /* Status high */
-#define        NORESET 0       /* No reset on write to R9 */
-#define        CHRB    0x40    /* Reset channel B */
-#define        CHRA    0x80    /* Reset channel A */
-#define        FHWRES  0xc0    /* Force hardware reset */
-
-/* Write Register 10 (misc control bits) */
-#define        BIT6    1       /* 6 bit/8bit sync */
-#define        LOOPMODE 2      /* SDLC Loop mode */
-#define        ABUNDER 4       /* Abort/flag on SDLC xmit underrun */
-#define        MARKIDLE 8      /* Mark/flag on idle */
-#define        GAOP    0x10    /* Go active on poll */
-#define        NRZ     0       /* NRZ mode */
-#define        NRZI    0x20    /* NRZI mode */
-#define        FM1     0x40    /* FM1 (transition = 1) */
-#define        FM0     0x60    /* FM0 (transition = 0) */
-#define        CRCPS   0x80    /* CRC Preset I/O */
-
-/* Write Register 11 (Clock Mode control) */
-#define        TRxCXT  0       /* TRxC = Xtal output */
-#define        TRxCTC  1       /* TRxC = Transmit clock */
-#define        TRxCBR  2       /* TRxC = BR Generator Output */
-#define        TRxCDP  3       /* TRxC = DPLL output */
-#define        TRxCOI  4       /* TRxC O/I */
-#define        TCRTxCP 0       /* Transmit clock = RTxC pin */
-#define        TCTRxCP 8       /* Transmit clock = TRxC pin */
-#define        TCBR    0x10    /* Transmit clock = BR Generator output */
-#define        TCDPLL  0x18    /* Transmit clock = DPLL output */
-#define        RCRTxCP 0       /* Receive clock = RTxC pin */
-#define        RCTRxCP 0x20    /* Receive clock = TRxC pin */
-#define        RCBR    0x40    /* Receive clock = BR Generator output */
-#define        RCDPLL  0x60    /* Receive clock = DPLL output */
-#define        RTxCX   0x80    /* RTxC Xtal/No Xtal */
-
-/* Write Register 12 (lower byte of baud rate generator time constant) */
-
-/* Write Register 13 (upper byte of baud rate generator time constant) */
-
-/* Write Register 14 (Misc control bits) */
-#define        BRENAB  1       /* Baud rate generator enable */
-#define        BRSRC   2       /* Baud rate generator source */
-#define        DTRREQ  4       /* DTR/Request function */
-#define        AUTOECHO 8      /* Auto Echo */
-#define        LOOPBAK 0x10    /* Local loopback */
-#define        SEARCH  0x20    /* Enter search mode */
-#define        RMC     0x40    /* Reset missing clock */
-#define        DISDPLL 0x60    /* Disable DPLL */
-#define        SSBR    0x80    /* Set DPLL source = BR generator */
-#define        SSRTxC  0xa0    /* Set DPLL source = RTxC */
-#define        SFMM    0xc0    /* Set FM mode */
-#define        SNRZI   0xe0    /* Set NRZI mode */
-
-/* Write Register 15 (external/status interrupt control) */
-#define        ZCIE    2       /* Zero count IE */
-#define        DCDIE   8       /* DCD IE */
-#define        SYNCIE  0x10    /* Sync/hunt IE */
-#define        CTSIE   0x20    /* CTS IE */
-#define        TxUIE   0x40    /* Tx Underrun/EOM IE */
-#define        BRKIE   0x80    /* Break/Abort IE */
-
-
-/* Read Register 0 */
-#define        Rx_CH_AV        0x1     /* Rx Character Available */
-#define        ZCOUNT          0x2     /* Zero count */
-#define        Tx_BUF_EMP      0x4     /* Tx Buffer empty */
-#define        DCD             0x8     /* DCD */
-#define        SYNC            0x10    /* Sync/hunt */
-#define        CTS             0x20    /* CTS */
-#define        TxEOM           0x40    /* Tx underrun */
-#define        BRK_ABRT        0x80    /* Break/Abort */
-
-/* Read Register 1 */
-#define        ALL_SNT         0x1     /* All sent */
-/* Residue Data for 8 Rx bits/char programmed */
-#define        RES3            0x8     /* 0/3 */
-#define        RES4            0x4     /* 0/4 */
-#define        RES5            0xc     /* 0/5 */
-#define        RES6            0x2     /* 0/6 */
-#define        RES7            0xa     /* 0/7 */
-#define        RES8            0x6     /* 0/8 */
-#define        RES18           0xe     /* 1/8 */
-#define        RES28           0x0     /* 2/8 */
-/* Special Rx Condition Interrupts */
-#define        PAR_ERR         0x10    /* Parity error */
-#define        Rx_OVR          0x20    /* Rx Overrun Error */
-#define        CRC_ERR         0x40    /* CRC/Framing Error */
-#define        END_FR          0x80    /* End of Frame (SDLC) */
-
-/* Read Register 2 (channel b only) - Interrupt vector */
-#define CHB_Tx_EMPTY   0x00
-#define CHB_EXT_STAT   0x02
-#define CHB_Rx_AVAIL   0x04
-#define CHB_SPECIAL    0x06
-#define CHA_Tx_EMPTY   0x08
-#define CHA_EXT_STAT   0x0a
-#define CHA_Rx_AVAIL   0x0c
-#define CHA_SPECIAL    0x0e
-#define STATUS_MASK    0x0e
-
-/* Read Register 3 (interrupt pending register) ch a only */
-#define        CHBEXT  0x1             /* Channel B Ext/Stat IP */
-#define        CHBTxIP 0x2             /* Channel B Tx IP */
-#define        CHBRxIP 0x4             /* Channel B Rx IP */
-#define        CHAEXT  0x8             /* Channel A Ext/Stat IP */
-#define        CHATxIP 0x10            /* Channel A Tx IP */
-#define        CHARxIP 0x20            /* Channel A Rx IP */
-
-/* Read Register 8 (receive data register) */
-
-/* Read Register 10  (misc status bits) */
-#define        ONLOOP  2               /* On loop */
-#define        LOOPSEND 0x10           /* Loop sending */
-#define        CLK2MIS 0x40            /* Two clocks missing */
-#define        CLK1MIS 0x80            /* One clock missing */
-
-/* Read Register 12 (lower byte of baud rate generator constant) */
-
-/* Read Register 13 (upper byte of baud rate generator constant) */
-
-/* Read Register 15 (value of WR 15) */
-
-/* Misc macros */
-#define ZS_CLEARERR(channel)    do { writeb(ERR_RES, &channel->control); \
-                                    udelay(5); } while(0)
-
-#define ZS_CLEARSTAT(channel)   do { writeb(RES_EXT_INT, &channel->control); \
-                                    udelay(5); } while(0)
-
-#define ZS_CLEARFIFO(channel)   do { readb(&channel->data); \
-                                    udelay(2); \
-                                    readb(&channel->data); \
-                                    udelay(2); \
-                                    readb(&channel->data); \
-                                    udelay(2); } while(0)
-
-#endif /* _IP22_ZILOG_H */
diff --git a/drivers/serial/jsm/Makefile b/drivers/serial/jsm/Makefile
deleted file mode 100644 (file)
index e46b6e0..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# Makefile for Jasmine adapter
-#
-
-obj-$(CONFIG_SERIAL_JSM) += jsm.o
-
-jsm-objs :=    jsm_driver.o jsm_neo.o jsm_tty.o
-
diff --git a/drivers/serial/jsm/jsm.h b/drivers/serial/jsm/jsm.h
deleted file mode 100644 (file)
index 38a509c..0000000
+++ /dev/null
@@ -1,388 +0,0 @@
-/************************************************************************
- * Copyright 2003 Digi International (www.digi.com)
- *
- * Copyright (C) 2004 IBM Corporation. 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, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
- *
- * Contact Information:
- * Scott H Kilau <Scott_Kilau@digi.com>
- * Wendy Xiong   <wendyx@us.ibm.com>
- *
- ***********************************************************************/
-
-#ifndef __JSM_DRIVER_H
-#define __JSM_DRIVER_H
-
-#include <linux/kernel.h>
-#include <linux/types.h>       /* To pick up the varions Linux types */
-#include <linux/tty.h>
-#include <linux/serial_core.h>
-#include <linux/device.h>
-
-/*
- * Debugging levels can be set using debug insmod variable
- * They can also be compiled out completely.
- */
-enum {
-       DBG_INIT        = 0x01,
-       DBG_BASIC       = 0x02,
-       DBG_CORE        = 0x04,
-       DBG_OPEN        = 0x08,
-       DBG_CLOSE       = 0x10,
-       DBG_READ        = 0x20,
-       DBG_WRITE       = 0x40,
-       DBG_IOCTL       = 0x80,
-       DBG_PROC        = 0x100,
-       DBG_PARAM       = 0x200,
-       DBG_PSCAN       = 0x400,
-       DBG_EVENT       = 0x800,
-       DBG_DRAIN       = 0x1000,
-       DBG_MSIGS       = 0x2000,
-       DBG_MGMT        = 0x4000,
-       DBG_INTR        = 0x8000,
-       DBG_CARR        = 0x10000,
-};
-
-#define jsm_printk(nlevel, klevel, pdev, fmt, args...) \
-       if ((DBG_##nlevel & jsm_debug))                 \
-       dev_printk(KERN_##klevel, pdev->dev, fmt, ## args)
-
-#define        MAXLINES        256
-#define MAXPORTS       8
-#define MAX_STOPS_SENT 5
-
-/* Board type definitions */
-
-#define T_NEO          0000
-#define T_CLASSIC      0001
-#define T_PCIBUS       0400
-
-/* Board State Definitions */
-
-#define BD_RUNNING     0x0
-#define BD_REASON      0x7f
-#define BD_NOTFOUND    0x1
-#define BD_NOIOPORT    0x2
-#define BD_NOMEM       0x3
-#define BD_NOBIOS      0x4
-#define BD_NOFEP       0x5
-#define BD_FAILED      0x6
-#define BD_ALLOCATED   0x7
-#define BD_TRIBOOT     0x8
-#define BD_BADKME      0x80
-
-
-/* 4 extra for alignment play space */
-#define WRITEBUFLEN    ((4096) + 4)
-#define MYFLIPLEN      N_TTY_BUF_SIZE
-
-#define JSM_VERSION    "jsm: 1.2-1-INKERNEL"
-#define JSM_PARTNUM    "40002438_A-INKERNEL"
-
-struct jsm_board;
-struct jsm_channel;
-
-/************************************************************************
- * Per board operations structure                                      *
- ************************************************************************/
-struct board_ops {
-       irq_handler_t intr;
-       void (*uart_init) (struct jsm_channel *ch);
-       void (*uart_off) (struct jsm_channel *ch);
-       void (*param) (struct jsm_channel *ch);
-       void (*assert_modem_signals) (struct jsm_channel *ch);
-       void (*flush_uart_write) (struct jsm_channel *ch);
-       void (*flush_uart_read) (struct jsm_channel *ch);
-       void (*disable_receiver) (struct jsm_channel *ch);
-       void (*enable_receiver) (struct jsm_channel *ch);
-       void (*send_break) (struct jsm_channel *ch);
-       void (*clear_break) (struct jsm_channel *ch, int);
-       void (*send_start_character) (struct jsm_channel *ch);
-       void (*send_stop_character) (struct jsm_channel *ch);
-       void (*copy_data_from_queue_to_uart) (struct jsm_channel *ch);
-       u32 (*get_uart_bytes_left) (struct jsm_channel *ch);
-       void (*send_immediate_char) (struct jsm_channel *ch, unsigned char);
-};
-
-
-/*
- *     Per-board information
- */
-struct jsm_board
-{
-       int             boardnum;       /* Board number: 0-32 */
-
-       int             type;           /* Type of board */
-       u8              rev;            /* PCI revision ID */
-       struct pci_dev  *pci_dev;
-       u32             maxports;       /* MAX ports this board can handle */
-
-       spinlock_t      bd_intr_lock;   /* Used to protect the poller tasklet and
-                                        * the interrupt routine from each other.
-                                        */
-
-       u32             nasync;         /* Number of ports on card */
-
-       u32             irq;            /* Interrupt request number */
-
-       u64             membase;        /* Start of base memory of the card */
-       u64             membase_end;    /* End of base memory of the card */
-
-       u8      __iomem *re_map_membase;/* Remapped memory of the card */
-
-       u64             iobase;         /* Start of io base of the card */
-       u64             iobase_end;     /* End of io base of the card */
-
-       u32             bd_uart_offset; /* Space between each UART */
-
-       struct jsm_channel *channels[MAXPORTS]; /* array of pointers to our channels. */
-       char            *flipbuf;       /* Our flip buffer, alloced if board is found */
-
-       u32             bd_dividend;    /* Board/UARTs specific dividend */
-
-       struct board_ops *bd_ops;
-
-       struct list_head jsm_board_entry;
-};
-
-/************************************************************************
- * Device flag definitions for ch_flags.
- ************************************************************************/
-#define CH_PRON                0x0001          /* Printer on string            */
-#define CH_STOP                0x0002          /* Output is stopped            */
-#define CH_STOPI       0x0004          /* Input is stopped             */
-#define CH_CD          0x0008          /* Carrier is present           */
-#define CH_FCAR                0x0010          /* Carrier forced on            */
-#define CH_HANGUP      0x0020          /* Hangup received              */
-
-#define CH_RECEIVER_OFF        0x0040          /* Receiver is off              */
-#define CH_OPENING     0x0080          /* Port in fragile open state   */
-#define CH_CLOSING     0x0100          /* Port in fragile close state  */
-#define CH_FIFO_ENABLED 0x0200         /* Port has FIFOs enabled       */
-#define CH_TX_FIFO_EMPTY 0x0400                /* TX Fifo is completely empty  */
-#define CH_TX_FIFO_LWM 0x0800          /* TX Fifo is below Low Water   */
-#define CH_BREAK_SENDING 0x1000                /* Break is being sent          */
-#define CH_LOOPBACK 0x2000             /* Channel is in lookback mode  */
-#define CH_FLIPBUF_IN_USE 0x4000       /* Channel's flipbuf is in use  */
-#define CH_BAUD0       0x08000         /* Used for checking B0 transitions */
-
-/* Our Read/Error/Write queue sizes */
-#define RQUEUEMASK     0x1FFF          /* 8 K - 1 */
-#define EQUEUEMASK     0x1FFF          /* 8 K - 1 */
-#define WQUEUEMASK     0x0FFF          /* 4 K - 1 */
-#define RQUEUESIZE     (RQUEUEMASK + 1)
-#define EQUEUESIZE     RQUEUESIZE
-#define WQUEUESIZE     (WQUEUEMASK + 1)
-
-
-/************************************************************************
- * Channel information structure.
- ************************************************************************/
-struct jsm_channel {
-       struct uart_port uart_port;
-       struct jsm_board        *ch_bd;         /* Board structure pointer      */
-
-       spinlock_t      ch_lock;        /* provide for serialization */
-       wait_queue_head_t ch_flags_wait;
-
-       u32             ch_portnum;     /* Port number, 0 offset.       */
-       u32             ch_open_count;  /* open count                   */
-       u32             ch_flags;       /* Channel flags                */
-
-       u64             ch_close_delay; /* How long we should drop RTS/DTR for */
-
-       tcflag_t        ch_c_iflag;     /* channel iflags               */
-       tcflag_t        ch_c_cflag;     /* channel cflags               */
-       tcflag_t        ch_c_oflag;     /* channel oflags               */
-       tcflag_t        ch_c_lflag;     /* channel lflags               */
-       u8              ch_stopc;       /* Stop character               */
-       u8              ch_startc;      /* Start character              */
-
-       u8              ch_mostat;      /* FEP output modem status      */
-       u8              ch_mistat;      /* FEP input modem status       */
-
-       struct neo_uart_struct __iomem *ch_neo_uart;    /* Pointer to the "mapped" UART struct */
-       u8              ch_cached_lsr;  /* Cached value of the LSR register */
-
-       u8              *ch_rqueue;     /* Our read queue buffer - malloc'ed */
-       u16             ch_r_head;      /* Head location of the read queue */
-       u16             ch_r_tail;      /* Tail location of the read queue */
-
-       u8              *ch_equeue;     /* Our error queue buffer - malloc'ed */
-       u16             ch_e_head;      /* Head location of the error queue */
-       u16             ch_e_tail;      /* Tail location of the error queue */
-
-       u8              *ch_wqueue;     /* Our write queue buffer - malloc'ed */
-       u16             ch_w_head;      /* Head location of the write queue */
-       u16             ch_w_tail;      /* Tail location of the write queue */
-
-       u64             ch_rxcount;     /* total of data received so far */
-       u64             ch_txcount;     /* total of data transmitted so far */
-
-       u8              ch_r_tlevel;    /* Receive Trigger level */
-       u8              ch_t_tlevel;    /* Transmit Trigger level */
-
-       u8              ch_r_watermark; /* Receive Watermark */
-
-
-       u32             ch_stops_sent;  /* How many times I have sent a stop character
-                                        * to try to stop the other guy sending.
-                                        */
-       u64             ch_err_parity;  /* Count of parity errors on channel */
-       u64             ch_err_frame;   /* Count of framing errors on channel */
-       u64             ch_err_break;   /* Count of breaks on channel */
-       u64             ch_err_overrun; /* Count of overruns on channel */
-
-       u64             ch_xon_sends;   /* Count of xons transmitted */
-       u64             ch_xoff_sends;  /* Count of xoffs transmitted */
-};
-
-
-/************************************************************************
- * Per channel/port NEO UART structure                                 *
- ************************************************************************
- *             Base Structure Entries Usage Meanings to Host           *
- *                                                                     *
- *     W = read write          R = read only                           *
- *                     U = Unused.                                     *
- ************************************************************************/
-
-struct neo_uart_struct {
-        u8 txrx;               /* WR   RHR/THR - Holding Reg */
-        u8 ier;                /* WR   IER - Interrupt Enable Reg */
-        u8 isr_fcr;            /* WR   ISR/FCR - Interrupt Status Reg/Fifo Control Reg */
-        u8 lcr;                /* WR   LCR - Line Control Reg */
-        u8 mcr;                /* WR   MCR - Modem Control Reg */
-        u8 lsr;                /* WR   LSR - Line Status Reg */
-        u8 msr;                /* WR   MSR - Modem Status Reg */
-        u8 spr;                /* WR   SPR - Scratch Pad Reg */
-        u8 fctr;               /* WR   FCTR - Feature Control Reg */
-        u8 efr;                /* WR   EFR - Enhanced Function Reg */
-        u8 tfifo;              /* WR   TXCNT/TXTRG - Transmit FIFO Reg */
-        u8 rfifo;              /* WR   RXCNT/RXTRG - Recieve FIFO Reg */
-        u8 xoffchar1;  /* WR   XOFF 1 - XOff Character 1 Reg */
-        u8 xoffchar2;  /* WR   XOFF 2 - XOff Character 2 Reg */
-        u8 xonchar1;   /* WR   XON 1 - Xon Character 1 Reg */
-        u8 xonchar2;   /* WR   XON 2 - XOn Character 2 Reg */
-
-        u8 reserved1[0x2ff - 0x200]; /* U      Reserved by Exar */
-        u8 txrxburst[64];      /* RW   64 bytes of RX/TX FIFO Data */
-        u8 reserved2[0x37f - 0x340]; /* U      Reserved by Exar */
-        u8 rxburst_with_errors[64];    /* R    64 bytes of RX FIFO Data + LSR */
-};
-
-/* Where to read the extended interrupt register (32bits instead of 8bits) */
-#define        UART_17158_POLL_ADDR_OFFSET     0x80
-
-/*
- * These are the redefinitions for the FCTR on the XR17C158, since
- * Exar made them different than their earlier design. (XR16C854)
- */
-
-/* These are only applicable when table D is selected */
-#define UART_17158_FCTR_RTS_NODELAY    0x00
-#define UART_17158_FCTR_RTS_4DELAY     0x01
-#define UART_17158_FCTR_RTS_6DELAY     0x02
-#define UART_17158_FCTR_RTS_8DELAY     0x03
-#define UART_17158_FCTR_RTS_12DELAY    0x12
-#define UART_17158_FCTR_RTS_16DELAY    0x05
-#define UART_17158_FCTR_RTS_20DELAY    0x13
-#define UART_17158_FCTR_RTS_24DELAY    0x06
-#define UART_17158_FCTR_RTS_28DELAY    0x14
-#define UART_17158_FCTR_RTS_32DELAY    0x07
-#define UART_17158_FCTR_RTS_36DELAY    0x16
-#define UART_17158_FCTR_RTS_40DELAY    0x08
-#define UART_17158_FCTR_RTS_44DELAY    0x09
-#define UART_17158_FCTR_RTS_48DELAY    0x10
-#define UART_17158_FCTR_RTS_52DELAY    0x11
-
-#define UART_17158_FCTR_RTS_IRDA       0x10
-#define UART_17158_FCTR_RS485          0x20
-#define UART_17158_FCTR_TRGA           0x00
-#define UART_17158_FCTR_TRGB           0x40
-#define UART_17158_FCTR_TRGC           0x80
-#define UART_17158_FCTR_TRGD           0xC0
-
-/* 17158 trigger table selects.. */
-#define UART_17158_FCTR_BIT6           0x40
-#define UART_17158_FCTR_BIT7           0x80
-
-/* 17158 TX/RX memmapped buffer offsets */
-#define UART_17158_RX_FIFOSIZE         64
-#define UART_17158_TX_FIFOSIZE         64
-
-/* 17158 Extended IIR's */
-#define UART_17158_IIR_RDI_TIMEOUT     0x0C    /* Receiver data TIMEOUT */
-#define UART_17158_IIR_XONXOFF         0x10    /* Received an XON/XOFF char */
-#define UART_17158_IIR_HWFLOW_STATE_CHANGE 0x20        /* CTS/DSR or RTS/DTR state change */
-#define UART_17158_IIR_FIFO_ENABLED    0xC0    /* 16550 FIFOs are Enabled */
-
-/*
- * These are the extended interrupts that get sent
- * back to us from the UART's 32bit interrupt register
- */
-#define UART_17158_RX_LINE_STATUS      0x1     /* RX Ready */
-#define UART_17158_RXRDY_TIMEOUT       0x2     /* RX Ready Timeout */
-#define UART_17158_TXRDY               0x3     /* TX Ready */
-#define UART_17158_MSR                 0x4     /* Modem State Change */
-#define UART_17158_TX_AND_FIFO_CLR     0x40    /* Transmitter Holding Reg Empty */
-#define UART_17158_RX_FIFO_DATA_ERROR  0x80    /* UART detected an RX FIFO Data error */
-
-/*
- * These are the EXTENDED definitions for the 17C158's Interrupt
- * Enable Register.
- */
-#define UART_17158_EFR_ECB     0x10    /* Enhanced control bit */
-#define UART_17158_EFR_IXON    0x2     /* Receiver compares Xon1/Xoff1 */
-#define UART_17158_EFR_IXOFF   0x8     /* Transmit Xon1/Xoff1 */
-#define UART_17158_EFR_RTSDTR  0x40    /* Auto RTS/DTR Flow Control Enable */
-#define UART_17158_EFR_CTSDSR  0x80    /* Auto CTS/DSR Flow COntrol Enable */
-
-#define UART_17158_XOFF_DETECT 0x1     /* Indicates whether chip saw an incoming XOFF char */
-#define UART_17158_XON_DETECT  0x2     /* Indicates whether chip saw an incoming XON char */
-
-#define UART_17158_IER_RSVD1   0x10    /* Reserved by Exar */
-#define UART_17158_IER_XOFF    0x20    /* Xoff Interrupt Enable */
-#define UART_17158_IER_RTSDTR  0x40    /* Output Interrupt Enable */
-#define UART_17158_IER_CTSDSR  0x80    /* Input Interrupt Enable */
-
-#define PCI_DEVICE_NEO_2DB9_PCI_NAME           "Neo 2 - DB9 Universal PCI"
-#define PCI_DEVICE_NEO_2DB9PRI_PCI_NAME                "Neo 2 - DB9 Universal PCI - Powered Ring Indicator"
-#define PCI_DEVICE_NEO_2RJ45_PCI_NAME          "Neo 2 - RJ45 Universal PCI"
-#define PCI_DEVICE_NEO_2RJ45PRI_PCI_NAME       "Neo 2 - RJ45 Universal PCI - Powered Ring Indicator"
-#define PCIE_DEVICE_NEO_IBM_PCI_NAME           "Neo 4 - PCI Express - IBM"
-
-/*
- * Our Global Variables.
- */
-extern struct  uart_driver jsm_uart_driver;
-extern struct  board_ops jsm_neo_ops;
-extern int     jsm_debug;
-
-/*************************************************************************
- *
- * Prototypes for non-static functions used in more than one module
- *
- *************************************************************************/
-int jsm_tty_write(struct uart_port *port);
-int jsm_tty_init(struct jsm_board *);
-int jsm_uart_port_init(struct jsm_board *);
-int jsm_remove_uart_port(struct jsm_board *);
-void jsm_input(struct jsm_channel *ch);
-void jsm_check_queue_flow_control(struct jsm_channel *ch);
-
-#endif
diff --git a/drivers/serial/jsm/jsm_driver.c b/drivers/serial/jsm/jsm_driver.c
deleted file mode 100644 (file)
index 18f5484..0000000
+++ /dev/null
@@ -1,297 +0,0 @@
-/************************************************************************
- * Copyright 2003 Digi International (www.digi.com)
- *
- * Copyright (C) 2004 IBM Corporation. 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, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
- *
- * Contact Information:
- * Scott H Kilau <Scott_Kilau@digi.com>
- * Wendy Xiong   <wendyx@us.ibm.com>
- *
- *
- ***********************************************************************/
-#include <linux/moduleparam.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-#include "jsm.h"
-
-MODULE_AUTHOR("Digi International, http://www.digi.com");
-MODULE_DESCRIPTION("Driver for the Digi International "
-                  "Neo PCI based product line");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("jsm");
-
-#define JSM_DRIVER_NAME "jsm"
-#define NR_PORTS       32
-#define JSM_MINOR_START        0
-
-struct uart_driver jsm_uart_driver = {
-       .owner          = THIS_MODULE,
-       .driver_name    = JSM_DRIVER_NAME,
-       .dev_name       = "ttyn",
-       .major          = 0,
-       .minor          = JSM_MINOR_START,
-       .nr             = NR_PORTS,
-};
-
-static pci_ers_result_t jsm_io_error_detected(struct pci_dev *pdev,
-                                       pci_channel_state_t state);
-static pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev);
-static void jsm_io_resume(struct pci_dev *pdev);
-
-static struct pci_error_handlers jsm_err_handler = {
-       .error_detected = jsm_io_error_detected,
-       .slot_reset = jsm_io_slot_reset,
-       .resume = jsm_io_resume,
-};
-
-int jsm_debug;
-module_param(jsm_debug, int, 0);
-MODULE_PARM_DESC(jsm_debug, "Driver debugging level");
-
-static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
-       int rc = 0;
-       struct jsm_board *brd;
-       static int adapter_count = 0;
-
-       rc = pci_enable_device(pdev);
-       if (rc) {
-               dev_err(&pdev->dev, "Device enable FAILED\n");
-               goto out;
-       }
-
-       rc = pci_request_regions(pdev, "jsm");
-       if (rc) {
-               dev_err(&pdev->dev, "pci_request_region FAILED\n");
-               goto out_disable_device;
-       }
-
-       brd = kzalloc(sizeof(struct jsm_board), GFP_KERNEL);
-       if (!brd) {
-               dev_err(&pdev->dev,
-                       "memory allocation for board structure failed\n");
-               rc = -ENOMEM;
-               goto out_release_regions;
-       }
-
-       /* store the info for the board we've found */
-       brd->boardnum = adapter_count++;
-       brd->pci_dev = pdev;
-       if (pdev->device == PCIE_DEVICE_ID_NEO_4_IBM)
-               brd->maxports = 4;
-       else if (pdev->device == PCI_DEVICE_ID_DIGI_NEO_8)
-               brd->maxports = 8;
-       else
-               brd->maxports = 2;
-
-       spin_lock_init(&brd->bd_intr_lock);
-
-       /* store which revision we have */
-       brd->rev = pdev->revision;
-
-       brd->irq = pdev->irq;
-
-       jsm_printk(INIT, INFO, &brd->pci_dev,
-               "jsm_found_board - NEO adapter\n");
-
-       /* get the PCI Base Address Registers */
-       brd->membase    = pci_resource_start(pdev, 0);
-       brd->membase_end = pci_resource_end(pdev, 0);
-
-       if (brd->membase & 1)
-               brd->membase &= ~3;
-       else
-               brd->membase &= ~15;
-
-       /* Assign the board_ops struct */
-       brd->bd_ops = &jsm_neo_ops;
-
-       brd->bd_uart_offset = 0x200;
-       brd->bd_dividend = 921600;
-
-       brd->re_map_membase = ioremap(brd->membase, 0x1000);
-       if (!brd->re_map_membase) {
-               dev_err(&pdev->dev,
-                       "card has no PCI Memory resources, "
-                       "failing board.\n");
-               rc = -ENOMEM;
-               goto out_kfree_brd;
-       }
-
-       rc = request_irq(brd->irq, brd->bd_ops->intr,
-                       IRQF_SHARED, "JSM", brd);
-       if (rc) {
-               printk(KERN_WARNING "Failed to hook IRQ %d\n",brd->irq);
-               goto out_iounmap;
-       }
-
-       rc = jsm_tty_init(brd);
-       if (rc < 0) {
-               dev_err(&pdev->dev, "Can't init tty devices (%d)\n", rc);
-               rc = -ENXIO;
-               goto out_free_irq;
-       }
-
-       rc = jsm_uart_port_init(brd);
-       if (rc < 0) {
-               /* XXX: leaking all resources from jsm_tty_init here! */
-               dev_err(&pdev->dev, "Can't init uart port (%d)\n", rc);
-               rc = -ENXIO;
-               goto out_free_irq;
-       }
-
-       /* Log the information about the board */
-       dev_info(&pdev->dev, "board %d: Digi Neo (rev %d), irq %d\n",
-                       adapter_count, brd->rev, brd->irq);
-
-       /*
-        * allocate flip buffer for board.
-        *
-        * Okay to malloc with GFP_KERNEL, we are not at interrupt
-        * context, and there are no locks held.
-        */
-       brd->flipbuf = kzalloc(MYFLIPLEN, GFP_KERNEL);
-       if (!brd->flipbuf) {
-               /* XXX: leaking all resources from jsm_tty_init and
-                       jsm_uart_port_init here! */
-               dev_err(&pdev->dev, "memory allocation for flipbuf failed\n");
-               rc = -ENOMEM;
-               goto out_free_uart;
-       }
-
-       pci_set_drvdata(pdev, brd);
-       pci_save_state(pdev);
-
-       return 0;
- out_free_uart:
-       jsm_remove_uart_port(brd);
- out_free_irq:
-       jsm_remove_uart_port(brd);
-       free_irq(brd->irq, brd);
- out_iounmap:
-       iounmap(brd->re_map_membase);
- out_kfree_brd:
-       kfree(brd);
- out_release_regions:
-       pci_release_regions(pdev);
- out_disable_device:
-       pci_disable_device(pdev);
- out:
-       return rc;
-}
-
-static void __devexit jsm_remove_one(struct pci_dev *pdev)
-{
-       struct jsm_board *brd = pci_get_drvdata(pdev);
-       int i = 0;
-
-       jsm_remove_uart_port(brd);
-
-       free_irq(brd->irq, brd);
-       iounmap(brd->re_map_membase);
-
-       /* Free all allocated channels structs */
-       for (i = 0; i < brd->maxports; i++) {
-               if (brd->channels[i]) {
-                       kfree(brd->channels[i]->ch_rqueue);
-                       kfree(brd->channels[i]->ch_equeue);
-                       kfree(brd->channels[i]->ch_wqueue);
-                       kfree(brd->channels[i]);
-               }
-       }
-
-       pci_release_regions(pdev);
-       pci_disable_device(pdev);
-       kfree(brd->flipbuf);
-       kfree(brd);
-}
-
-static struct pci_device_id jsm_pci_tbl[] = {
-       { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9), 0, 0, 0 },
-       { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9PRI), 0, 0, 1 },
-       { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45), 0, 0, 2 },
-       { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45PRI), 0, 0, 3 },
-       { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4_IBM), 0, 0, 4 },
-       { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_NEO_8), 0, 0, 5 },
-       { 0, }
-};
-MODULE_DEVICE_TABLE(pci, jsm_pci_tbl);
-
-static struct pci_driver jsm_driver = {
-       .name           = "jsm",
-       .id_table       = jsm_pci_tbl,
-       .probe          = jsm_probe_one,
-       .remove         = __devexit_p(jsm_remove_one),
-       .err_handler    = &jsm_err_handler,
-};
-
-static pci_ers_result_t jsm_io_error_detected(struct pci_dev *pdev,
-                                       pci_channel_state_t state)
-{
-       struct jsm_board *brd = pci_get_drvdata(pdev);
-
-       jsm_remove_uart_port(brd);
-
-       return PCI_ERS_RESULT_NEED_RESET;
-}
-
-static pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev)
-{
-       int rc;
-
-       rc = pci_enable_device(pdev);
-
-       if (rc)
-               return PCI_ERS_RESULT_DISCONNECT;
-
-       pci_set_master(pdev);
-
-       return PCI_ERS_RESULT_RECOVERED;
-}
-
-static void jsm_io_resume(struct pci_dev *pdev)
-{
-       struct jsm_board *brd = pci_get_drvdata(pdev);
-
-       pci_restore_state(pdev);
-
-       jsm_uart_port_init(brd);
-}
-
-static int __init jsm_init_module(void)
-{
-       int rc;
-
-       rc = uart_register_driver(&jsm_uart_driver);
-       if (!rc) {
-               rc = pci_register_driver(&jsm_driver);
-               if (rc)
-                       uart_unregister_driver(&jsm_uart_driver);
-       }
-       return rc;
-}
-
-static void __exit jsm_exit_module(void)
-{
-       pci_unregister_driver(&jsm_driver);
-       uart_unregister_driver(&jsm_uart_driver);
-}
-
-module_init(jsm_init_module);
-module_exit(jsm_exit_module);
diff --git a/drivers/serial/jsm/jsm_neo.c b/drivers/serial/jsm/jsm_neo.c
deleted file mode 100644 (file)
index 7960d96..0000000
+++ /dev/null
@@ -1,1412 +0,0 @@
-/************************************************************************
- * Copyright 2003 Digi International (www.digi.com)
- *
- * Copyright (C) 2004 IBM Corporation. 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, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
- *
- * Contact Information:
- * Scott H Kilau <Scott_Kilau@digi.com>
- * Wendy Xiong   <wendyx@us.ibm.com>
- *
- ***********************************************************************/
-#include <linux/delay.h>       /* For udelay */
-#include <linux/serial_reg.h>  /* For the various UART offsets */
-#include <linux/tty.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-
-#include "jsm.h"               /* Driver main header file */
-
-static u32 jsm_offset_table[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
-
-/*
- * This function allows calls to ensure that all outstanding
- * PCI writes have been completed, by doing a PCI read against
- * a non-destructive, read-only location on the Neo card.
- *
- * In this case, we are reading the DVID (Read-only Device Identification)
- * value of the Neo card.
- */
-static inline void neo_pci_posting_flush(struct jsm_board *bd)
-{
-      readb(bd->re_map_membase + 0x8D);
-}
-
-static void neo_set_cts_flow_control(struct jsm_channel *ch)
-{
-       u8 ier, efr;
-       ier = readb(&ch->ch_neo_uart->ier);
-       efr = readb(&ch->ch_neo_uart->efr);
-
-       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting CTSFLOW\n");
-
-       /* Turn on auto CTS flow control */
-       ier |= (UART_17158_IER_CTSDSR);
-       efr |= (UART_17158_EFR_ECB | UART_17158_EFR_CTSDSR);
-
-       /* Turn off auto Xon flow control */
-       efr &= ~(UART_17158_EFR_IXON);
-
-       /* Why? Becuz Exar's spec says we have to zero it out before setting it */
-       writeb(0, &ch->ch_neo_uart->efr);
-
-       /* Turn on UART enhanced bits */
-       writeb(efr, &ch->ch_neo_uart->efr);
-
-       /* Turn on table D, with 8 char hi/low watermarks */
-       writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_4DELAY), &ch->ch_neo_uart->fctr);
-
-       /* Feed the UART our trigger levels */
-       writeb(8, &ch->ch_neo_uart->tfifo);
-       ch->ch_t_tlevel = 8;
-
-       writeb(ier, &ch->ch_neo_uart->ier);
-}
-
-static void neo_set_rts_flow_control(struct jsm_channel *ch)
-{
-       u8 ier, efr;
-       ier = readb(&ch->ch_neo_uart->ier);
-       efr = readb(&ch->ch_neo_uart->efr);
-
-       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting RTSFLOW\n");
-
-       /* Turn on auto RTS flow control */
-       ier |= (UART_17158_IER_RTSDTR);
-       efr |= (UART_17158_EFR_ECB | UART_17158_EFR_RTSDTR);
-
-       /* Turn off auto Xoff flow control */
-       ier &= ~(UART_17158_IER_XOFF);
-       efr &= ~(UART_17158_EFR_IXOFF);
-
-       /* Why? Becuz Exar's spec says we have to zero it out before setting it */
-       writeb(0, &ch->ch_neo_uart->efr);
-
-       /* Turn on UART enhanced bits */
-       writeb(efr, &ch->ch_neo_uart->efr);
-
-       writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_4DELAY), &ch->ch_neo_uart->fctr);
-       ch->ch_r_watermark = 4;
-
-       writeb(56, &ch->ch_neo_uart->rfifo);
-       ch->ch_r_tlevel = 56;
-
-       writeb(ier, &ch->ch_neo_uart->ier);
-
-       /*
-        * From the Neo UART spec sheet:
-        * The auto RTS/DTR function must be started by asserting
-        * RTS/DTR# output pin (MCR bit-0 or 1 to logic 1 after
-        * it is enabled.
-        */
-       ch->ch_mostat |= (UART_MCR_RTS);
-}
-
-
-static void neo_set_ixon_flow_control(struct jsm_channel *ch)
-{
-       u8 ier, efr;
-       ier = readb(&ch->ch_neo_uart->ier);
-       efr = readb(&ch->ch_neo_uart->efr);
-
-       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting IXON FLOW\n");
-
-       /* Turn off auto CTS flow control */
-       ier &= ~(UART_17158_IER_CTSDSR);
-       efr &= ~(UART_17158_EFR_CTSDSR);
-
-       /* Turn on auto Xon flow control */
-       efr |= (UART_17158_EFR_ECB | UART_17158_EFR_IXON);
-
-       /* Why? Becuz Exar's spec says we have to zero it out before setting it */
-       writeb(0, &ch->ch_neo_uart->efr);
-
-       /* Turn on UART enhanced bits */
-       writeb(efr, &ch->ch_neo_uart->efr);
-
-       writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
-       ch->ch_r_watermark = 4;
-
-       writeb(32, &ch->ch_neo_uart->rfifo);
-       ch->ch_r_tlevel = 32;
-
-       /* Tell UART what start/stop chars it should be looking for */
-       writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1);
-       writeb(0, &ch->ch_neo_uart->xonchar2);
-
-       writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1);
-       writeb(0, &ch->ch_neo_uart->xoffchar2);
-
-       writeb(ier, &ch->ch_neo_uart->ier);
-}
-
-static void neo_set_ixoff_flow_control(struct jsm_channel *ch)
-{
-       u8 ier, efr;
-       ier = readb(&ch->ch_neo_uart->ier);
-       efr = readb(&ch->ch_neo_uart->efr);
-
-       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting IXOFF FLOW\n");
-
-       /* Turn off auto RTS flow control */
-       ier &= ~(UART_17158_IER_RTSDTR);
-       efr &= ~(UART_17158_EFR_RTSDTR);
-
-       /* Turn on auto Xoff flow control */
-       ier |= (UART_17158_IER_XOFF);
-       efr |= (UART_17158_EFR_ECB | UART_17158_EFR_IXOFF);
-
-       /* Why? Becuz Exar's spec says we have to zero it out before setting it */
-       writeb(0, &ch->ch_neo_uart->efr);
-
-       /* Turn on UART enhanced bits */
-       writeb(efr, &ch->ch_neo_uart->efr);
-
-       /* Turn on table D, with 8 char hi/low watermarks */
-       writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
-
-       writeb(8, &ch->ch_neo_uart->tfifo);
-       ch->ch_t_tlevel = 8;
-
-       /* Tell UART what start/stop chars it should be looking for */
-       writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1);
-       writeb(0, &ch->ch_neo_uart->xonchar2);
-
-       writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1);
-       writeb(0, &ch->ch_neo_uart->xoffchar2);
-
-       writeb(ier, &ch->ch_neo_uart->ier);
-}
-
-static void neo_set_no_input_flow_control(struct jsm_channel *ch)
-{
-       u8 ier, efr;
-       ier = readb(&ch->ch_neo_uart->ier);
-       efr = readb(&ch->ch_neo_uart->efr);
-
-       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Unsetting Input FLOW\n");
-
-       /* Turn off auto RTS flow control */
-       ier &= ~(UART_17158_IER_RTSDTR);
-       efr &= ~(UART_17158_EFR_RTSDTR);
-
-       /* Turn off auto Xoff flow control */
-       ier &= ~(UART_17158_IER_XOFF);
-       if (ch->ch_c_iflag & IXON)
-               efr &= ~(UART_17158_EFR_IXOFF);
-       else
-               efr &= ~(UART_17158_EFR_ECB | UART_17158_EFR_IXOFF);
-
-       /* Why? Becuz Exar's spec says we have to zero it out before setting it */
-       writeb(0, &ch->ch_neo_uart->efr);
-
-       /* Turn on UART enhanced bits */
-       writeb(efr, &ch->ch_neo_uart->efr);
-
-       /* Turn on table D, with 8 char hi/low watermarks */
-       writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
-
-       ch->ch_r_watermark = 0;
-
-       writeb(16, &ch->ch_neo_uart->tfifo);
-       ch->ch_t_tlevel = 16;
-
-       writeb(16, &ch->ch_neo_uart->rfifo);
-       ch->ch_r_tlevel = 16;
-
-       writeb(ier, &ch->ch_neo_uart->ier);
-}
-
-static void neo_set_no_output_flow_control(struct jsm_channel *ch)
-{
-       u8 ier, efr;
-       ier = readb(&ch->ch_neo_uart->ier);
-       efr = readb(&ch->ch_neo_uart->efr);
-
-       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Unsetting Output FLOW\n");
-
-       /* Turn off auto CTS flow control */
-       ier &= ~(UART_17158_IER_CTSDSR);
-       efr &= ~(UART_17158_EFR_CTSDSR);
-
-       /* Turn off auto Xon flow control */
-       if (ch->ch_c_iflag & IXOFF)
-               efr &= ~(UART_17158_EFR_IXON);
-       else
-               efr &= ~(UART_17158_EFR_ECB | UART_17158_EFR_IXON);
-
-       /* Why? Becuz Exar's spec says we have to zero it out before setting it */
-       writeb(0, &ch->ch_neo_uart->efr);
-
-       /* Turn on UART enhanced bits */
-       writeb(efr, &ch->ch_neo_uart->efr);
-
-       /* Turn on table D, with 8 char hi/low watermarks */
-       writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
-
-       ch->ch_r_watermark = 0;
-
-       writeb(16, &ch->ch_neo_uart->tfifo);
-       ch->ch_t_tlevel = 16;
-
-       writeb(16, &ch->ch_neo_uart->rfifo);
-       ch->ch_r_tlevel = 16;
-
-       writeb(ier, &ch->ch_neo_uart->ier);
-}
-
-static inline void neo_set_new_start_stop_chars(struct jsm_channel *ch)
-{
-
-       /* if hardware flow control is set, then skip this whole thing */
-       if (ch->ch_c_cflag & CRTSCTS)
-               return;
-
-       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "start\n");
-
-       /* Tell UART what start/stop chars it should be looking for */
-       writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1);
-       writeb(0, &ch->ch_neo_uart->xonchar2);
-
-       writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1);
-       writeb(0, &ch->ch_neo_uart->xoffchar2);
-}
-
-static void neo_copy_data_from_uart_to_queue(struct jsm_channel *ch)
-{
-       int qleft = 0;
-       u8 linestatus = 0;
-       u8 error_mask = 0;
-       int n = 0;
-       int total = 0;
-       u16 head;
-       u16 tail;
-
-       if (!ch)
-               return;
-
-       /* cache head and tail of queue */
-       head = ch->ch_r_head & RQUEUEMASK;
-       tail = ch->ch_r_tail & RQUEUEMASK;
-
-       /* Get our cached LSR */
-       linestatus = ch->ch_cached_lsr;
-       ch->ch_cached_lsr = 0;
-
-       /* Store how much space we have left in the queue */
-       if ((qleft = tail - head - 1) < 0)
-               qleft += RQUEUEMASK + 1;
-
-       /*
-        * If the UART is not in FIFO mode, force the FIFO copy to
-        * NOT be run, by setting total to 0.
-        *
-        * On the other hand, if the UART IS in FIFO mode, then ask
-        * the UART to give us an approximation of data it has RX'ed.
-        */
-       if (!(ch->ch_flags & CH_FIFO_ENABLED))
-               total = 0;
-       else {
-               total = readb(&ch->ch_neo_uart->rfifo);
-
-               /*
-                * EXAR chip bug - RX FIFO COUNT - Fudge factor.
-                *
-                * This resolves a problem/bug with the Exar chip that sometimes
-                * returns a bogus value in the rfifo register.
-                * The count can be any where from 0-3 bytes "off".
-                * Bizarre, but true.
-                */
-               total -= 3;
-       }
-
-       /*
-        * Finally, bound the copy to make sure we don't overflow
-        * our own queue...
-        * The byte by byte copy loop below this loop this will
-        * deal with the queue overflow possibility.
-        */
-       total = min(total, qleft);
-
-       while (total > 0) {
-               /*
-                * Grab the linestatus register, we need to check
-                * to see if there are any errors in the FIFO.
-                */
-               linestatus = readb(&ch->ch_neo_uart->lsr);
-
-               /*
-                * Break out if there is a FIFO error somewhere.
-                * This will allow us to go byte by byte down below,
-                * finding the exact location of the error.
-                */
-               if (linestatus & UART_17158_RX_FIFO_DATA_ERROR)
-                       break;
-
-               /* Make sure we don't go over the end of our queue */
-               n = min(((u32) total), (RQUEUESIZE - (u32) head));
-
-               /*
-                * Cut down n even further if needed, this is to fix
-                * a problem with memcpy_fromio() with the Neo on the
-                * IBM pSeries platform.
-                * 15 bytes max appears to be the magic number.
-                */
-               n = min((u32) n, (u32) 12);
-
-               /*
-                * Since we are grabbing the linestatus register, which
-                * will reset some bits after our read, we need to ensure
-                * we don't miss our TX FIFO emptys.
-                */
-               if (linestatus & (UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR))
-                       ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
-
-               linestatus = 0;
-
-               /* Copy data from uart to the queue */
-               memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, n);
-               /*
-                * Since RX_FIFO_DATA_ERROR was 0, we are guarenteed
-                * that all the data currently in the FIFO is free of
-                * breaks and parity/frame/orun errors.
-                */
-               memset(ch->ch_equeue + head, 0, n);
-
-               /* Add to and flip head if needed */
-               head = (head + n) & RQUEUEMASK;
-               total -= n;
-               qleft -= n;
-               ch->ch_rxcount += n;
-       }
-
-       /*
-        * Create a mask to determine whether we should
-        * insert the character (if any) into our queue.
-        */
-       if (ch->ch_c_iflag & IGNBRK)
-               error_mask |= UART_LSR_BI;
-
-       /*
-        * Now cleanup any leftover bytes still in the UART.
-        * Also deal with any possible queue overflow here as well.
-        */
-       while (1) {
-
-               /*
-                * Its possible we have a linestatus from the loop above
-                * this, so we "OR" on any extra bits.
-                */
-               linestatus |= readb(&ch->ch_neo_uart->lsr);
-
-               /*
-                * If the chip tells us there is no more data pending to
-                * be read, we can then leave.
-                * But before we do, cache the linestatus, just in case.
-                */
-               if (!(linestatus & UART_LSR_DR)) {
-                       ch->ch_cached_lsr = linestatus;
-                       break;
-               }
-
-               /* No need to store this bit */
-               linestatus &= ~UART_LSR_DR;
-
-               /*
-                * Since we are grabbing the linestatus register, which
-                * will reset some bits after our read, we need to ensure
-                * we don't miss our TX FIFO emptys.
-                */
-               if (linestatus & (UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR)) {
-                       linestatus &= ~(UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR);
-                       ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
-               }
-
-               /*
-                * Discard character if we are ignoring the error mask.
-                */
-               if (linestatus & error_mask) {
-                       u8 discard;
-                       linestatus = 0;
-                       memcpy_fromio(&discard, &ch->ch_neo_uart->txrxburst, 1);
-                       continue;
-               }
-
-               /*
-                * If our queue is full, we have no choice but to drop some data.
-                * The assumption is that HWFLOW or SWFLOW should have stopped
-                * things way way before we got to this point.
-                *
-                * I decided that I wanted to ditch the oldest data first,
-                * I hope thats okay with everyone? Yes? Good.
-                */
-               while (qleft < 1) {
-                       jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
-                               "Queue full, dropping DATA:%x LSR:%x\n",
-                               ch->ch_rqueue[tail], ch->ch_equeue[tail]);
-
-                       ch->ch_r_tail = tail = (tail + 1) & RQUEUEMASK;
-                       ch->ch_err_overrun++;
-                       qleft++;
-               }
-
-               memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, 1);
-               ch->ch_equeue[head] = (u8) linestatus;
-
-               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
-                               "DATA/LSR pair: %x %x\n", ch->ch_rqueue[head], ch->ch_equeue[head]);
-
-               /* Ditch any remaining linestatus value. */
-               linestatus = 0;
-
-               /* Add to and flip head if needed */
-               head = (head + 1) & RQUEUEMASK;
-
-               qleft--;
-               ch->ch_rxcount++;
-       }
-
-       /*
-        * Write new final heads to channel structure.
-        */
-       ch->ch_r_head = head & RQUEUEMASK;
-       ch->ch_e_head = head & EQUEUEMASK;
-       jsm_input(ch);
-}
-
-static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch)
-{
-       u16 head;
-       u16 tail;
-       int n;
-       int s;
-       int qlen;
-       u32 len_written = 0;
-
-       if (!ch)
-               return;
-
-       /* No data to write to the UART */
-       if (ch->ch_w_tail == ch->ch_w_head)
-               return;
-
-       /* If port is "stopped", don't send any data to the UART */
-       if ((ch->ch_flags & CH_STOP) || (ch->ch_flags & CH_BREAK_SENDING))
-               return;
-       /*
-        * If FIFOs are disabled. Send data directly to txrx register
-        */
-       if (!(ch->ch_flags & CH_FIFO_ENABLED)) {
-               u8 lsrbits = readb(&ch->ch_neo_uart->lsr);
-
-               ch->ch_cached_lsr |= lsrbits;
-               if (ch->ch_cached_lsr & UART_LSR_THRE) {
-                       ch->ch_cached_lsr &= ~(UART_LSR_THRE);
-
-                       writeb(ch->ch_wqueue[ch->ch_w_tail], &ch->ch_neo_uart->txrx);
-                       jsm_printk(WRITE, INFO, &ch->ch_bd->pci_dev,
-                                       "Tx data: %x\n", ch->ch_wqueue[ch->ch_w_head]);
-                       ch->ch_w_tail++;
-                       ch->ch_w_tail &= WQUEUEMASK;
-                       ch->ch_txcount++;
-               }
-               return;
-       }
-
-       /*
-        * We have to do it this way, because of the EXAR TXFIFO count bug.
-        */
-       if (!(ch->ch_flags & (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM)))
-               return;
-
-       n = UART_17158_TX_FIFOSIZE - ch->ch_t_tlevel;
-
-       /* cache head and tail of queue */
-       head = ch->ch_w_head & WQUEUEMASK;
-       tail = ch->ch_w_tail & WQUEUEMASK;
-       qlen = (head - tail) & WQUEUEMASK;
-
-       /* Find minimum of the FIFO space, versus queue length */
-       n = min(n, qlen);
-
-       while (n > 0) {
-
-               s = ((head >= tail) ? head : WQUEUESIZE) - tail;
-               s = min(s, n);
-
-               if (s <= 0)
-                       break;
-
-               memcpy_toio(&ch->ch_neo_uart->txrxburst, ch->ch_wqueue + tail, s);
-               /* Add and flip queue if needed */
-               tail = (tail + s) & WQUEUEMASK;
-               n -= s;
-               ch->ch_txcount += s;
-               len_written += s;
-       }
-
-       /* Update the final tail */
-       ch->ch_w_tail = tail & WQUEUEMASK;
-
-       if (len_written >= ch->ch_t_tlevel)
-               ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
-
-       if (!jsm_tty_write(&ch->uart_port))
-               uart_write_wakeup(&ch->uart_port);
-}
-
-static void neo_parse_modem(struct jsm_channel *ch, u8 signals)
-{
-       u8 msignals = signals;
-
-       jsm_printk(MSIGS, INFO, &ch->ch_bd->pci_dev,
-                       "neo_parse_modem: port: %d msignals: %x\n", ch->ch_portnum, msignals);
-
-       /* Scrub off lower bits. They signify delta's, which I don't care about */
-       /* Keep DDCD and DDSR though */
-       msignals &= 0xf8;
-
-       if (msignals & UART_MSR_DDCD)
-               uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_DCD);
-       if (msignals & UART_MSR_DDSR)
-               uart_handle_cts_change(&ch->uart_port, msignals & UART_MSR_CTS);
-       if (msignals & UART_MSR_DCD)
-               ch->ch_mistat |= UART_MSR_DCD;
-       else
-               ch->ch_mistat &= ~UART_MSR_DCD;
-
-       if (msignals & UART_MSR_DSR)
-               ch->ch_mistat |= UART_MSR_DSR;
-       else
-               ch->ch_mistat &= ~UART_MSR_DSR;
-
-       if (msignals & UART_MSR_RI)
-               ch->ch_mistat |= UART_MSR_RI;
-       else
-               ch->ch_mistat &= ~UART_MSR_RI;
-
-       if (msignals & UART_MSR_CTS)
-               ch->ch_mistat |= UART_MSR_CTS;
-       else
-               ch->ch_mistat &= ~UART_MSR_CTS;
-
-       jsm_printk(MSIGS, INFO, &ch->ch_bd->pci_dev,
-                       "Port: %d DTR: %d RTS: %d CTS: %d DSR: %d " "RI: %d CD: %d\n",
-               ch->ch_portnum,
-               !!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_DTR),
-               !!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_RTS),
-               !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_CTS),
-               !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DSR),
-               !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_RI),
-               !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DCD));
-}
-
-/* Make the UART raise any of the output signals we want up */
-static void neo_assert_modem_signals(struct jsm_channel *ch)
-{
-       if (!ch)
-               return;
-
-       writeb(ch->ch_mostat, &ch->ch_neo_uart->mcr);
-
-       /* flush write operation */
-       neo_pci_posting_flush(ch->ch_bd);
-}
-
-/*
- * Flush the WRITE FIFO on the Neo.
- *
- * NOTE: Channel lock MUST be held before calling this function!
- */
-static void neo_flush_uart_write(struct jsm_channel *ch)
-{
-       u8 tmp = 0;
-       int i = 0;
-
-       if (!ch)
-               return;
-
-       writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_XMIT), &ch->ch_neo_uart->isr_fcr);
-
-       for (i = 0; i < 10; i++) {
-
-               /* Check to see if the UART feels it completely flushed the FIFO. */
-               tmp = readb(&ch->ch_neo_uart->isr_fcr);
-               if (tmp & 4) {
-                       jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev,
-                                       "Still flushing TX UART... i: %d\n", i);
-                       udelay(10);
-               }
-               else
-                       break;
-       }
-
-       ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
-}
-
-
-/*
- * Flush the READ FIFO on the Neo.
- *
- * NOTE: Channel lock MUST be held before calling this function!
- */
-static void neo_flush_uart_read(struct jsm_channel *ch)
-{
-       u8 tmp = 0;
-       int i = 0;
-
-       if (!ch)
-               return;
-
-       writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR), &ch->ch_neo_uart->isr_fcr);
-
-       for (i = 0; i < 10; i++) {
-
-               /* Check to see if the UART feels it completely flushed the FIFO. */
-               tmp = readb(&ch->ch_neo_uart->isr_fcr);
-               if (tmp & 2) {
-                       jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev,
-                                       "Still flushing RX UART... i: %d\n", i);
-                       udelay(10);
-               }
-               else
-                       break;
-       }
-}
-
-/*
- * No locks are assumed to be held when calling this function.
- */
-static void neo_clear_break(struct jsm_channel *ch, int force)
-{
-       unsigned long lock_flags;
-
-       spin_lock_irqsave(&ch->ch_lock, lock_flags);
-
-       /* Turn break off, and unset some variables */
-       if (ch->ch_flags & CH_BREAK_SENDING) {
-               u8 temp = readb(&ch->ch_neo_uart->lcr);
-               writeb((temp & ~UART_LCR_SBC), &ch->ch_neo_uart->lcr);
-
-               ch->ch_flags &= ~(CH_BREAK_SENDING);
-               jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev,
-                               "clear break Finishing UART_LCR_SBC! finished: %lx\n", jiffies);
-
-               /* flush write operation */
-               neo_pci_posting_flush(ch->ch_bd);
-       }
-       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-}
-
-/*
- * Parse the ISR register.
- */
-static inline void neo_parse_isr(struct jsm_board *brd, u32 port)
-{
-       struct jsm_channel *ch;
-       u8 isr;
-       u8 cause;
-       unsigned long lock_flags;
-
-       if (!brd)
-               return;
-
-       if (port > brd->maxports)
-               return;
-
-       ch = brd->channels[port];
-       if (!ch)
-               return;
-
-       /* Here we try to figure out what caused the interrupt to happen */
-       while (1) {
-
-               isr = readb(&ch->ch_neo_uart->isr_fcr);
-
-               /* Bail if no pending interrupt */
-               if (isr & UART_IIR_NO_INT)
-                       break;
-
-               /*
-                * Yank off the upper 2 bits, which just show that the FIFO's are enabled.
-                */
-               isr &= ~(UART_17158_IIR_FIFO_ENABLED);
-
-               jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
-                               "%s:%d isr: %x\n", __FILE__, __LINE__, isr);
-
-               if (isr & (UART_17158_IIR_RDI_TIMEOUT | UART_IIR_RDI)) {
-                       /* Read data from uart -> queue */
-                       neo_copy_data_from_uart_to_queue(ch);
-
-                       /* Call our tty layer to enforce queue flow control if needed. */
-                       spin_lock_irqsave(&ch->ch_lock, lock_flags);
-                       jsm_check_queue_flow_control(ch);
-                       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-               }
-
-               if (isr & UART_IIR_THRI) {
-                       /* Transfer data (if any) from Write Queue -> UART. */
-                       spin_lock_irqsave(&ch->ch_lock, lock_flags);
-                       ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
-                       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-                       neo_copy_data_from_queue_to_uart(ch);
-               }
-
-               if (isr & UART_17158_IIR_XONXOFF) {
-                       cause = readb(&ch->ch_neo_uart->xoffchar1);
-
-                       jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
-                                       "Port %d. Got ISR_XONXOFF: cause:%x\n", port, cause);
-
-                       /*
-                        * Since the UART detected either an XON or
-                        * XOFF match, we need to figure out which
-                        * one it was, so we can suspend or resume data flow.
-                        */
-                       spin_lock_irqsave(&ch->ch_lock, lock_flags);
-                       if (cause == UART_17158_XON_DETECT) {
-                               /* Is output stopped right now, if so, resume it */
-                               if (brd->channels[port]->ch_flags & CH_STOP) {
-                                       ch->ch_flags &= ~(CH_STOP);
-                               }
-                               jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
-                                               "Port %d. XON detected in incoming data\n", port);
-                       }
-                       else if (cause == UART_17158_XOFF_DETECT) {
-                               if (!(brd->channels[port]->ch_flags & CH_STOP)) {
-                                       ch->ch_flags |= CH_STOP;
-                                       jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
-                                                       "Setting CH_STOP\n");
-                               }
-                               jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
-                                               "Port: %d. XOFF detected in incoming data\n", port);
-                       }
-                       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-               }
-
-               if (isr & UART_17158_IIR_HWFLOW_STATE_CHANGE) {
-                       /*
-                        * If we get here, this means the hardware is doing auto flow control.
-                        * Check to see whether RTS/DTR or CTS/DSR caused this interrupt.
-                        */
-                       cause = readb(&ch->ch_neo_uart->mcr);
-
-                       /* Which pin is doing auto flow? RTS or DTR? */
-                       spin_lock_irqsave(&ch->ch_lock, lock_flags);
-                       if ((cause & 0x4) == 0) {
-                               if (cause & UART_MCR_RTS)
-                                       ch->ch_mostat |= UART_MCR_RTS;
-                               else
-                                       ch->ch_mostat &= ~(UART_MCR_RTS);
-                       } else {
-                               if (cause & UART_MCR_DTR)
-                                       ch->ch_mostat |= UART_MCR_DTR;
-                               else
-                                       ch->ch_mostat &= ~(UART_MCR_DTR);
-                       }
-                       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-               }
-
-               /* Parse any modem signal changes */
-               jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
-                               "MOD_STAT: sending to parse_modem_sigs\n");
-               neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr));
-       }
-}
-
-static inline void neo_parse_lsr(struct jsm_board *brd, u32 port)
-{
-       struct jsm_channel *ch;
-       int linestatus;
-       unsigned long lock_flags;
-
-       if (!brd)
-               return;
-
-       if (port > brd->maxports)
-               return;
-
-       ch = brd->channels[port];
-       if (!ch)
-               return;
-
-       linestatus = readb(&ch->ch_neo_uart->lsr);
-
-       jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
-                       "%s:%d port: %d linestatus: %x\n", __FILE__, __LINE__, port, linestatus);
-
-       ch->ch_cached_lsr |= linestatus;
-
-       if (ch->ch_cached_lsr & UART_LSR_DR) {
-               /* Read data from uart -> queue */
-               neo_copy_data_from_uart_to_queue(ch);
-               spin_lock_irqsave(&ch->ch_lock, lock_flags);
-               jsm_check_queue_flow_control(ch);
-               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-       }
-
-       /*
-        * This is a special flag. It indicates that at least 1
-        * RX error (parity, framing, or break) has happened.
-        * Mark this in our struct, which will tell me that I have
-        *to do the special RX+LSR read for this FIFO load.
-        */
-       if (linestatus & UART_17158_RX_FIFO_DATA_ERROR)
-               jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
-                       "%s:%d Port: %d Got an RX error, need to parse LSR\n",
-                       __FILE__, __LINE__, port);
-
-       /*
-        * The next 3 tests should *NOT* happen, as the above test
-        * should encapsulate all 3... At least, thats what Exar says.
-        */
-
-       if (linestatus & UART_LSR_PE) {
-               ch->ch_err_parity++;
-               jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
-                       "%s:%d Port: %d. PAR ERR!\n", __FILE__, __LINE__, port);
-       }
-
-       if (linestatus & UART_LSR_FE) {
-               ch->ch_err_frame++;
-               jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
-                       "%s:%d Port: %d. FRM ERR!\n", __FILE__, __LINE__, port);
-       }
-
-       if (linestatus & UART_LSR_BI) {
-               ch->ch_err_break++;
-               jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
-                       "%s:%d Port: %d. BRK INTR!\n", __FILE__, __LINE__, port);
-       }
-
-       if (linestatus & UART_LSR_OE) {
-               /*
-                * Rx Oruns. Exar says that an orun will NOT corrupt
-                * the FIFO. It will just replace the holding register
-                * with this new data byte. So basically just ignore this.
-                * Probably we should eventually have an orun stat in our driver...
-                */
-               ch->ch_err_overrun++;
-               jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
-                       "%s:%d Port: %d. Rx Overrun!\n", __FILE__, __LINE__, port);
-       }
-
-       if (linestatus & UART_LSR_THRE) {
-               spin_lock_irqsave(&ch->ch_lock, lock_flags);
-               ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
-               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-
-               /* Transfer data (if any) from Write Queue -> UART. */
-               neo_copy_data_from_queue_to_uart(ch);
-       }
-       else if (linestatus & UART_17158_TX_AND_FIFO_CLR) {
-               spin_lock_irqsave(&ch->ch_lock, lock_flags);
-               ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
-               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-
-               /* Transfer data (if any) from Write Queue -> UART. */
-               neo_copy_data_from_queue_to_uart(ch);
-       }
-}
-
-/*
- * neo_param()
- * Send any/all changes to the line to the UART.
- */
-static void neo_param(struct jsm_channel *ch)
-{
-       u8 lcr = 0;
-       u8 uart_lcr, ier;
-       u32 baud;
-       int quot;
-       struct jsm_board *bd;
-
-       bd = ch->ch_bd;
-       if (!bd)
-               return;
-
-       /*
-        * If baud rate is zero, flush queues, and set mval to drop DTR.
-        */
-       if ((ch->ch_c_cflag & (CBAUD)) == 0) {
-               ch->ch_r_head = ch->ch_r_tail = 0;
-               ch->ch_e_head = ch->ch_e_tail = 0;
-               ch->ch_w_head = ch->ch_w_tail = 0;
-
-               neo_flush_uart_write(ch);
-               neo_flush_uart_read(ch);
-
-               ch->ch_flags |= (CH_BAUD0);
-               ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR);
-               neo_assert_modem_signals(ch);
-               return;
-
-       } else {
-               int i;
-               unsigned int cflag;
-               static struct {
-                       unsigned int rate;
-                       unsigned int cflag;
-               } baud_rates[] = {
-                       { 921600, B921600 },
-                       { 460800, B460800 },
-                       { 230400, B230400 },
-                       { 115200, B115200 },
-                       {  57600, B57600  },
-                       {  38400, B38400  },
-                       {  19200, B19200  },
-                       {   9600, B9600   },
-                       {   4800, B4800   },
-                       {   2400, B2400   },
-                       {   1200, B1200   },
-                       {    600, B600    },
-                       {    300, B300    },
-                       {    200, B200    },
-                       {    150, B150    },
-                       {    134, B134    },
-                       {    110, B110    },
-                       {     75, B75     },
-                       {     50, B50     },
-               };
-
-               cflag = C_BAUD(ch->uart_port.state->port.tty);
-               baud = 9600;
-               for (i = 0; i < ARRAY_SIZE(baud_rates); i++) {
-                       if (baud_rates[i].cflag == cflag) {
-                               baud = baud_rates[i].rate;
-                               break;
-                       }
-               }
-
-               if (ch->ch_flags & CH_BAUD0)
-                       ch->ch_flags &= ~(CH_BAUD0);
-       }
-
-       if (ch->ch_c_cflag & PARENB)
-               lcr |= UART_LCR_PARITY;
-
-       if (!(ch->ch_c_cflag & PARODD))
-               lcr |= UART_LCR_EPAR;
-
-       /*
-        * Not all platforms support mark/space parity,
-        * so this will hide behind an ifdef.
-        */
-#ifdef CMSPAR
-       if (ch->ch_c_cflag & CMSPAR)
-               lcr |= UART_LCR_SPAR;
-#endif
-
-       if (ch->ch_c_cflag & CSTOPB)
-               lcr |= UART_LCR_STOP;
-
-       switch (ch->ch_c_cflag & CSIZE) {
-               case CS5:
-                       lcr |= UART_LCR_WLEN5;
-                       break;
-               case CS6:
-                       lcr |= UART_LCR_WLEN6;
-                       break;
-               case CS7:
-                       lcr |= UART_LCR_WLEN7;
-                       break;
-               case CS8:
-               default:
-                       lcr |= UART_LCR_WLEN8;
-               break;
-       }
-
-       ier = readb(&ch->ch_neo_uart->ier);
-       uart_lcr = readb(&ch->ch_neo_uart->lcr);
-
-       if (baud == 0)
-               baud = 9600;
-
-       quot = ch->ch_bd->bd_dividend / baud;
-
-       if (quot != 0) {
-               writeb(UART_LCR_DLAB, &ch->ch_neo_uart->lcr);
-               writeb((quot & 0xff), &ch->ch_neo_uart->txrx);
-               writeb((quot >> 8), &ch->ch_neo_uart->ier);
-               writeb(lcr, &ch->ch_neo_uart->lcr);
-       }
-
-       if (uart_lcr != lcr)
-               writeb(lcr, &ch->ch_neo_uart->lcr);
-
-       if (ch->ch_c_cflag & CREAD)
-               ier |= (UART_IER_RDI | UART_IER_RLSI);
-
-       ier |= (UART_IER_THRI | UART_IER_MSI);
-
-       writeb(ier, &ch->ch_neo_uart->ier);
-
-       /* Set new start/stop chars */
-       neo_set_new_start_stop_chars(ch);
-
-       if (ch->ch_c_cflag & CRTSCTS)
-               neo_set_cts_flow_control(ch);
-       else if (ch->ch_c_iflag & IXON) {
-               /* If start/stop is set to disable, then we should disable flow control */
-               if ((ch->ch_startc == __DISABLED_CHAR) || (ch->ch_stopc == __DISABLED_CHAR))
-                       neo_set_no_output_flow_control(ch);
-               else
-                       neo_set_ixon_flow_control(ch);
-       }
-       else
-               neo_set_no_output_flow_control(ch);
-
-       if (ch->ch_c_cflag & CRTSCTS)
-               neo_set_rts_flow_control(ch);
-       else if (ch->ch_c_iflag & IXOFF) {
-               /* If start/stop is set to disable, then we should disable flow control */
-               if ((ch->ch_startc == __DISABLED_CHAR) || (ch->ch_stopc == __DISABLED_CHAR))
-                       neo_set_no_input_flow_control(ch);
-               else
-                       neo_set_ixoff_flow_control(ch);
-       }
-       else
-               neo_set_no_input_flow_control(ch);
-       /*
-        * Adjust the RX FIFO Trigger level if baud is less than 9600.
-        * Not exactly elegant, but this is needed because of the Exar chip's
-        * delay on firing off the RX FIFO interrupt on slower baud rates.
-        */
-       if (baud < 9600) {
-               writeb(1, &ch->ch_neo_uart->rfifo);
-               ch->ch_r_tlevel = 1;
-       }
-
-       neo_assert_modem_signals(ch);
-
-       /* Get current status of the modem signals now */
-       neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr));
-       return;
-}
-
-/*
- * jsm_neo_intr()
- *
- * Neo specific interrupt handler.
- */
-static irqreturn_t neo_intr(int irq, void *voidbrd)
-{
-       struct jsm_board *brd = voidbrd;
-       struct jsm_channel *ch;
-       int port = 0;
-       int type = 0;
-       int current_port;
-       u32 tmp;
-       u32 uart_poll;
-       unsigned long lock_flags;
-       unsigned long lock_flags2;
-       int outofloop_count = 0;
-
-       /* Lock out the slow poller from running on this board. */
-       spin_lock_irqsave(&brd->bd_intr_lock, lock_flags);
-
-       /*
-        * Read in "extended" IRQ information from the 32bit Neo register.
-        * Bits 0-7: What port triggered the interrupt.
-        * Bits 8-31: Each 3bits indicate what type of interrupt occurred.
-        */
-       uart_poll = readl(brd->re_map_membase + UART_17158_POLL_ADDR_OFFSET);
-
-       jsm_printk(INTR, INFO, &brd->pci_dev,
-               "%s:%d uart_poll: %x\n", __FILE__, __LINE__, uart_poll);
-
-       if (!uart_poll) {
-               jsm_printk(INTR, INFO, &brd->pci_dev,
-                       "Kernel interrupted to me, but no pending interrupts...\n");
-               spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags);
-               return IRQ_NONE;
-       }
-
-       /* At this point, we have at least SOMETHING to service, dig further... */
-
-       current_port = 0;
-
-       /* Loop on each port */
-       while (((uart_poll & 0xff) != 0) && (outofloop_count < 0xff)){
-
-               tmp = uart_poll;
-               outofloop_count++;
-
-               /* Check current port to see if it has interrupt pending */
-               if ((tmp & jsm_offset_table[current_port]) != 0) {
-                       port = current_port;
-                       type = tmp >> (8 + (port * 3));
-                       type &= 0x7;
-               } else {
-                       current_port++;
-                       continue;
-               }
-
-               jsm_printk(INTR, INFO, &brd->pci_dev,
-               "%s:%d port: %x type: %x\n", __FILE__, __LINE__, port, type);
-
-               /* Remove this port + type from uart_poll */
-               uart_poll &= ~(jsm_offset_table[port]);
-
-               if (!type) {
-                       /* If no type, just ignore it, and move onto next port */
-                       jsm_printk(INTR, ERR, &brd->pci_dev,
-                               "Interrupt with no type! port: %d\n", port);
-                       continue;
-               }
-
-               /* Switch on type of interrupt we have */
-               switch (type) {
-
-               case UART_17158_RXRDY_TIMEOUT:
-                       /*
-                        * RXRDY Time-out is cleared by reading data in the
-                       * RX FIFO until it falls below the trigger level.
-                        */
-
-                       /* Verify the port is in range. */
-                       if (port > brd->nasync)
-                               continue;
-
-                       ch = brd->channels[port];
-                       neo_copy_data_from_uart_to_queue(ch);
-
-                       /* Call our tty layer to enforce queue flow control if needed. */
-                       spin_lock_irqsave(&ch->ch_lock, lock_flags2);
-                       jsm_check_queue_flow_control(ch);
-                       spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
-
-                       continue;
-
-               case UART_17158_RX_LINE_STATUS:
-                       /*
-                        * RXRDY and RX LINE Status (logic OR of LSR[4:1])
-                        */
-                       neo_parse_lsr(brd, port);
-                       continue;
-
-               case UART_17158_TXRDY:
-                       /*
-                        * TXRDY interrupt clears after reading ISR register for the UART channel.
-                        */
-
-                       /*
-                        * Yes, this is odd...
-                        * Why would I check EVERY possibility of type of
-                        * interrupt, when we know its TXRDY???
-                        * Becuz for some reason, even tho we got triggered for TXRDY,
-                        * it seems to be occassionally wrong. Instead of TX, which
-                        * it should be, I was getting things like RXDY too. Weird.
-                        */
-                       neo_parse_isr(brd, port);
-                       continue;
-
-               case UART_17158_MSR:
-                       /*
-                        * MSR or flow control was seen.
-                        */
-                       neo_parse_isr(brd, port);
-                       continue;
-
-               default:
-                       /*
-                        * The UART triggered us with a bogus interrupt type.
-                        * It appears the Exar chip, when REALLY bogged down, will throw
-                        * these once and awhile.
-                        * Its harmless, just ignore it and move on.
-                        */
-                       jsm_printk(INTR, ERR, &brd->pci_dev,
-                               "%s:%d Unknown Interrupt type: %x\n", __FILE__, __LINE__, type);
-                       continue;
-               }
-       }
-
-       spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags);
-
-       jsm_printk(INTR, INFO, &brd->pci_dev, "finish.\n");
-       return IRQ_HANDLED;
-}
-
-/*
- * Neo specific way of turning off the receiver.
- * Used as a way to enforce queue flow control when in
- * hardware flow control mode.
- */
-static void neo_disable_receiver(struct jsm_channel *ch)
-{
-       u8 tmp = readb(&ch->ch_neo_uart->ier);
-       tmp &= ~(UART_IER_RDI);
-       writeb(tmp, &ch->ch_neo_uart->ier);
-
-       /* flush write operation */
-       neo_pci_posting_flush(ch->ch_bd);
-}
-
-
-/*
- * Neo specific way of turning on the receiver.
- * Used as a way to un-enforce queue flow control when in
- * hardware flow control mode.
- */
-static void neo_enable_receiver(struct jsm_channel *ch)
-{
-       u8 tmp = readb(&ch->ch_neo_uart->ier);
-       tmp |= (UART_IER_RDI);
-       writeb(tmp, &ch->ch_neo_uart->ier);
-
-       /* flush write operation */
-       neo_pci_posting_flush(ch->ch_bd);
-}
-
-static void neo_send_start_character(struct jsm_channel *ch)
-{
-       if (!ch)
-               return;
-
-       if (ch->ch_startc != __DISABLED_CHAR) {
-               ch->ch_xon_sends++;
-               writeb(ch->ch_startc, &ch->ch_neo_uart->txrx);
-
-               /* flush write operation */
-               neo_pci_posting_flush(ch->ch_bd);
-       }
-}
-
-static void neo_send_stop_character(struct jsm_channel *ch)
-{
-       if (!ch)
-               return;
-
-       if (ch->ch_stopc != __DISABLED_CHAR) {
-               ch->ch_xoff_sends++;
-               writeb(ch->ch_stopc, &ch->ch_neo_uart->txrx);
-
-               /* flush write operation */
-               neo_pci_posting_flush(ch->ch_bd);
-       }
-}
-
-/*
- * neo_uart_init
- */
-static void neo_uart_init(struct jsm_channel *ch)
-{
-       writeb(0, &ch->ch_neo_uart->ier);
-       writeb(0, &ch->ch_neo_uart->efr);
-       writeb(UART_EFR_ECB, &ch->ch_neo_uart->efr);
-
-       /* Clear out UART and FIFO */
-       readb(&ch->ch_neo_uart->txrx);
-       writeb((UART_FCR_ENABLE_FIFO|UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT), &ch->ch_neo_uart->isr_fcr);
-       readb(&ch->ch_neo_uart->lsr);
-       readb(&ch->ch_neo_uart->msr);
-
-       ch->ch_flags |= CH_FIFO_ENABLED;
-
-       /* Assert any signals we want up */
-       writeb(ch->ch_mostat, &ch->ch_neo_uart->mcr);
-}
-
-/*
- * Make the UART completely turn off.
- */
-static void neo_uart_off(struct jsm_channel *ch)
-{
-       /* Turn off UART enhanced bits */
-       writeb(0, &ch->ch_neo_uart->efr);
-
-       /* Stop all interrupts from occurring. */
-       writeb(0, &ch->ch_neo_uart->ier);
-}
-
-static u32 neo_get_uart_bytes_left(struct jsm_channel *ch)
-{
-       u8 left = 0;
-       u8 lsr = readb(&ch->ch_neo_uart->lsr);
-
-       /* We must cache the LSR as some of the bits get reset once read... */
-       ch->ch_cached_lsr |= lsr;
-
-       /* Determine whether the Transmitter is empty or not */
-       if (!(lsr & UART_LSR_TEMT))
-               left = 1;
-       else {
-               ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
-               left = 0;
-       }
-
-       return left;
-}
-
-/* Channel lock MUST be held by the calling function! */
-static void neo_send_break(struct jsm_channel *ch)
-{
-       /*
-        * Set the time we should stop sending the break.
-        * If we are already sending a break, toss away the existing
-        * time to stop, and use this new value instead.
-        */
-
-       /* Tell the UART to start sending the break */
-       if (!(ch->ch_flags & CH_BREAK_SENDING)) {
-               u8 temp = readb(&ch->ch_neo_uart->lcr);
-               writeb((temp | UART_LCR_SBC), &ch->ch_neo_uart->lcr);
-               ch->ch_flags |= (CH_BREAK_SENDING);
-
-               /* flush write operation */
-               neo_pci_posting_flush(ch->ch_bd);
-       }
-}
-
-/*
- * neo_send_immediate_char.
- *
- * Sends a specific character as soon as possible to the UART,
- * jumping over any bytes that might be in the write queue.
- *
- * The channel lock MUST be held by the calling function.
- */
-static void neo_send_immediate_char(struct jsm_channel *ch, unsigned char c)
-{
-       if (!ch)
-               return;
-
-       writeb(c, &ch->ch_neo_uart->txrx);
-
-       /* flush write operation */
-       neo_pci_posting_flush(ch->ch_bd);
-}
-
-struct board_ops jsm_neo_ops = {
-       .intr                           = neo_intr,
-       .uart_init                      = neo_uart_init,
-       .uart_off                       = neo_uart_off,
-       .param                          = neo_param,
-       .assert_modem_signals           = neo_assert_modem_signals,
-       .flush_uart_write               = neo_flush_uart_write,
-       .flush_uart_read                = neo_flush_uart_read,
-       .disable_receiver               = neo_disable_receiver,
-       .enable_receiver                = neo_enable_receiver,
-       .send_break                     = neo_send_break,
-       .clear_break                    = neo_clear_break,
-       .send_start_character           = neo_send_start_character,
-       .send_stop_character            = neo_send_stop_character,
-       .copy_data_from_queue_to_uart   = neo_copy_data_from_queue_to_uart,
-       .get_uart_bytes_left            = neo_get_uart_bytes_left,
-       .send_immediate_char            = neo_send_immediate_char
-};
diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c
deleted file mode 100644 (file)
index 7a4a914..0000000
+++ /dev/null
@@ -1,910 +0,0 @@
-/************************************************************************
- * Copyright 2003 Digi International (www.digi.com)
- *
- * Copyright (C) 2004 IBM Corporation. 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, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
- *
- * Contact Information:
- * Scott H Kilau <Scott_Kilau@digi.com>
- * Ananda Venkatarman <mansarov@us.ibm.com>
- * Modifications:
- * 01/19/06:   changed jsm_input routine to use the dynamically allocated
- *             tty_buffer changes. Contributors: Scott Kilau and Ananda V.
- ***********************************************************************/
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_reg.h>
-#include <linux/delay.h>       /* For udelay */
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-#include "jsm.h"
-
-static DECLARE_BITMAP(linemap, MAXLINES);
-
-static void jsm_carrier(struct jsm_channel *ch);
-
-static inline int jsm_get_mstat(struct jsm_channel *ch)
-{
-       unsigned char mstat;
-       unsigned result;
-
-       jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "start\n");
-
-       mstat = (ch->ch_mostat | ch->ch_mistat);
-
-       result = 0;
-
-       if (mstat & UART_MCR_DTR)
-               result |= TIOCM_DTR;
-       if (mstat & UART_MCR_RTS)
-               result |= TIOCM_RTS;
-       if (mstat & UART_MSR_CTS)
-               result |= TIOCM_CTS;
-       if (mstat & UART_MSR_DSR)
-               result |= TIOCM_DSR;
-       if (mstat & UART_MSR_RI)
-               result |= TIOCM_RI;
-       if (mstat & UART_MSR_DCD)
-               result |= TIOCM_CD;
-
-       jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n");
-       return result;
-}
-
-static unsigned int jsm_tty_tx_empty(struct uart_port *port)
-{
-       return TIOCSER_TEMT;
-}
-
-/*
- * Return modem signals to ld.
- */
-static unsigned int jsm_tty_get_mctrl(struct uart_port *port)
-{
-       int result;
-       struct jsm_channel *channel = (struct jsm_channel *)port;
-
-       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
-
-       result = jsm_get_mstat(channel);
-
-       if (result < 0)
-               return -ENXIO;
-
-       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
-
-       return result;
-}
-
-/*
- * jsm_set_modem_info()
- *
- * Set modem signals, called by ld.
- */
-static void jsm_tty_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct jsm_channel *channel = (struct jsm_channel *)port;
-
-       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
-
-       if (mctrl & TIOCM_RTS)
-               channel->ch_mostat |= UART_MCR_RTS;
-       else
-               channel->ch_mostat &= ~UART_MCR_RTS;
-
-       if (mctrl & TIOCM_DTR)
-               channel->ch_mostat |= UART_MCR_DTR;
-       else
-               channel->ch_mostat &= ~UART_MCR_DTR;
-
-       channel->ch_bd->bd_ops->assert_modem_signals(channel);
-
-       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
-       udelay(10);
-}
-
-static void jsm_tty_start_tx(struct uart_port *port)
-{
-       struct jsm_channel *channel = (struct jsm_channel *)port;
-
-       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
-
-       channel->ch_flags &= ~(CH_STOP);
-       jsm_tty_write(port);
-
-       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
-}
-
-static void jsm_tty_stop_tx(struct uart_port *port)
-{
-       struct jsm_channel *channel = (struct jsm_channel *)port;
-
-       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
-
-       channel->ch_flags |= (CH_STOP);
-
-       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
-}
-
-static void jsm_tty_send_xchar(struct uart_port *port, char ch)
-{
-       unsigned long lock_flags;
-       struct jsm_channel *channel = (struct jsm_channel *)port;
-       struct ktermios *termios;
-
-       spin_lock_irqsave(&port->lock, lock_flags);
-       termios = port->state->port.tty->termios;
-       if (ch == termios->c_cc[VSTART])
-               channel->ch_bd->bd_ops->send_start_character(channel);
-
-       if (ch == termios->c_cc[VSTOP])
-               channel->ch_bd->bd_ops->send_stop_character(channel);
-       spin_unlock_irqrestore(&port->lock, lock_flags);
-}
-
-static void jsm_tty_stop_rx(struct uart_port *port)
-{
-       struct jsm_channel *channel = (struct jsm_channel *)port;
-
-       channel->ch_bd->bd_ops->disable_receiver(channel);
-}
-
-static void jsm_tty_enable_ms(struct uart_port *port)
-{
-       /* Nothing needed */
-}
-
-static void jsm_tty_break(struct uart_port *port, int break_state)
-{
-       unsigned long lock_flags;
-       struct jsm_channel *channel = (struct jsm_channel *)port;
-
-       spin_lock_irqsave(&port->lock, lock_flags);
-       if (break_state == -1)
-               channel->ch_bd->bd_ops->send_break(channel);
-       else
-               channel->ch_bd->bd_ops->clear_break(channel, 0);
-
-       spin_unlock_irqrestore(&port->lock, lock_flags);
-}
-
-static int jsm_tty_open(struct uart_port *port)
-{
-       struct jsm_board *brd;
-       struct jsm_channel *channel = (struct jsm_channel *)port;
-       struct ktermios *termios;
-
-       /* Get board pointer from our array of majors we have allocated */
-       brd = channel->ch_bd;
-
-       /*
-        * Allocate channel buffers for read/write/error.
-        * Set flag, so we don't get trounced on.
-        */
-       channel->ch_flags |= (CH_OPENING);
-
-       /* Drop locks, as malloc with GFP_KERNEL can sleep */
-
-       if (!channel->ch_rqueue) {
-               channel->ch_rqueue = kzalloc(RQUEUESIZE, GFP_KERNEL);
-               if (!channel->ch_rqueue) {
-                       jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
-                               "unable to allocate read queue buf");
-                       return -ENOMEM;
-               }
-       }
-       if (!channel->ch_equeue) {
-               channel->ch_equeue = kzalloc(EQUEUESIZE, GFP_KERNEL);
-               if (!channel->ch_equeue) {
-                       jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
-                               "unable to allocate error queue buf");
-                       return -ENOMEM;
-               }
-       }
-       if (!channel->ch_wqueue) {
-               channel->ch_wqueue = kzalloc(WQUEUESIZE, GFP_KERNEL);
-               if (!channel->ch_wqueue) {
-                       jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
-                               "unable to allocate write queue buf");
-                       return -ENOMEM;
-               }
-       }
-
-       channel->ch_flags &= ~(CH_OPENING);
-       /*
-        * Initialize if neither terminal is open.
-        */
-       jsm_printk(OPEN, INFO, &channel->ch_bd->pci_dev,
-               "jsm_open: initializing channel in open...\n");
-
-       /*
-        * Flush input queues.
-        */
-       channel->ch_r_head = channel->ch_r_tail = 0;
-       channel->ch_e_head = channel->ch_e_tail = 0;
-       channel->ch_w_head = channel->ch_w_tail = 0;
-
-       brd->bd_ops->flush_uart_write(channel);
-       brd->bd_ops->flush_uart_read(channel);
-
-       channel->ch_flags = 0;
-       channel->ch_cached_lsr = 0;
-       channel->ch_stops_sent = 0;
-
-       termios = port->state->port.tty->termios;
-       channel->ch_c_cflag     = termios->c_cflag;
-       channel->ch_c_iflag     = termios->c_iflag;
-       channel->ch_c_oflag     = termios->c_oflag;
-       channel->ch_c_lflag     = termios->c_lflag;
-       channel->ch_startc      = termios->c_cc[VSTART];
-       channel->ch_stopc       = termios->c_cc[VSTOP];
-
-       /* Tell UART to init itself */
-       brd->bd_ops->uart_init(channel);
-
-       /*
-        * Run param in case we changed anything
-        */
-       brd->bd_ops->param(channel);
-
-       jsm_carrier(channel);
-
-       channel->ch_open_count++;
-
-       jsm_printk(OPEN, INFO, &channel->ch_bd->pci_dev, "finish\n");
-       return 0;
-}
-
-static void jsm_tty_close(struct uart_port *port)
-{
-       struct jsm_board *bd;
-       struct ktermios *ts;
-       struct jsm_channel *channel = (struct jsm_channel *)port;
-
-       jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n");
-
-       bd = channel->ch_bd;
-       ts = port->state->port.tty->termios;
-
-       channel->ch_flags &= ~(CH_STOPI);
-
-       channel->ch_open_count--;
-
-       /*
-        * If we have HUPCL set, lower DTR and RTS
-        */
-       if (channel->ch_c_cflag & HUPCL) {
-               jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev,
-                       "Close. HUPCL set, dropping DTR/RTS\n");
-
-               /* Drop RTS/DTR */
-               channel->ch_mostat &= ~(UART_MCR_DTR | UART_MCR_RTS);
-               bd->bd_ops->assert_modem_signals(channel);
-       }
-
-       /* Turn off UART interrupts for this port */
-       channel->ch_bd->bd_ops->uart_off(channel);
-
-       jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "finish\n");
-}
-
-static void jsm_tty_set_termios(struct uart_port *port,
-                                struct ktermios *termios,
-                                struct ktermios *old_termios)
-{
-       unsigned long lock_flags;
-       struct jsm_channel *channel = (struct jsm_channel *)port;
-
-       spin_lock_irqsave(&port->lock, lock_flags);
-       channel->ch_c_cflag     = termios->c_cflag;
-       channel->ch_c_iflag     = termios->c_iflag;
-       channel->ch_c_oflag     = termios->c_oflag;
-       channel->ch_c_lflag     = termios->c_lflag;
-       channel->ch_startc      = termios->c_cc[VSTART];
-       channel->ch_stopc       = termios->c_cc[VSTOP];
-
-       channel->ch_bd->bd_ops->param(channel);
-       jsm_carrier(channel);
-       spin_unlock_irqrestore(&port->lock, lock_flags);
-}
-
-static const char *jsm_tty_type(struct uart_port *port)
-{
-       return "jsm";
-}
-
-static void jsm_tty_release_port(struct uart_port *port)
-{
-}
-
-static int jsm_tty_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-static void jsm_config_port(struct uart_port *port, int flags)
-{
-       port->type = PORT_JSM;
-}
-
-static struct uart_ops jsm_ops = {
-       .tx_empty       = jsm_tty_tx_empty,
-       .set_mctrl      = jsm_tty_set_mctrl,
-       .get_mctrl      = jsm_tty_get_mctrl,
-       .stop_tx        = jsm_tty_stop_tx,
-       .start_tx       = jsm_tty_start_tx,
-       .send_xchar     = jsm_tty_send_xchar,
-       .stop_rx        = jsm_tty_stop_rx,
-       .enable_ms      = jsm_tty_enable_ms,
-       .break_ctl      = jsm_tty_break,
-       .startup        = jsm_tty_open,
-       .shutdown       = jsm_tty_close,
-       .set_termios    = jsm_tty_set_termios,
-       .type           = jsm_tty_type,
-       .release_port   = jsm_tty_release_port,
-       .request_port   = jsm_tty_request_port,
-       .config_port    = jsm_config_port,
-};
-
-/*
- * jsm_tty_init()
- *
- * Init the tty subsystem.  Called once per board after board has been
- * downloaded and init'ed.
- */
-int __devinit jsm_tty_init(struct jsm_board *brd)
-{
-       int i;
-       void __iomem *vaddr;
-       struct jsm_channel *ch;
-
-       if (!brd)
-               return -ENXIO;
-
-       jsm_printk(INIT, INFO, &brd->pci_dev, "start\n");
-
-       /*
-        * Initialize board structure elements.
-        */
-
-       brd->nasync = brd->maxports;
-
-       /*
-        * Allocate channel memory that might not have been allocated
-        * when the driver was first loaded.
-        */
-       for (i = 0; i < brd->nasync; i++) {
-               if (!brd->channels[i]) {
-
-                       /*
-                        * Okay to malloc with GFP_KERNEL, we are not at
-                        * interrupt context, and there are no locks held.
-                        */
-                       brd->channels[i] = kzalloc(sizeof(struct jsm_channel), GFP_KERNEL);
-                       if (!brd->channels[i]) {
-                               jsm_printk(CORE, ERR, &brd->pci_dev,
-                                       "%s:%d Unable to allocate memory for channel struct\n",
-                                                        __FILE__, __LINE__);
-                       }
-               }
-       }
-
-       ch = brd->channels[0];
-       vaddr = brd->re_map_membase;
-
-       /* Set up channel variables */
-       for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) {
-
-               if (!brd->channels[i])
-                       continue;
-
-               spin_lock_init(&ch->ch_lock);
-
-               if (brd->bd_uart_offset == 0x200)
-                       ch->ch_neo_uart =  vaddr + (brd->bd_uart_offset * i);
-
-               ch->ch_bd = brd;
-               ch->ch_portnum = i;
-
-               /* .25 second delay */
-               ch->ch_close_delay = 250;
-
-               init_waitqueue_head(&ch->ch_flags_wait);
-       }
-
-       jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n");
-       return 0;
-}
-
-int jsm_uart_port_init(struct jsm_board *brd)
-{
-       int i, rc;
-       unsigned int line;
-       struct jsm_channel *ch;
-
-       if (!brd)
-               return -ENXIO;
-
-       jsm_printk(INIT, INFO, &brd->pci_dev, "start\n");
-
-       /*
-        * Initialize board structure elements.
-        */
-
-       brd->nasync = brd->maxports;
-
-       /* Set up channel variables */
-       for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) {
-
-               if (!brd->channels[i])
-                       continue;
-
-               brd->channels[i]->uart_port.irq = brd->irq;
-               brd->channels[i]->uart_port.uartclk = 14745600;
-               brd->channels[i]->uart_port.type = PORT_JSM;
-               brd->channels[i]->uart_port.iotype = UPIO_MEM;
-               brd->channels[i]->uart_port.membase = brd->re_map_membase;
-               brd->channels[i]->uart_port.fifosize = 16;
-               brd->channels[i]->uart_port.ops = &jsm_ops;
-               line = find_first_zero_bit(linemap, MAXLINES);
-               if (line >= MAXLINES) {
-                       printk(KERN_INFO "jsm: linemap is full, added device failed\n");
-                       continue;
-               } else
-                       set_bit(line, linemap);
-               brd->channels[i]->uart_port.line = line;
-               rc = uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port);
-               if (rc){
-                       printk(KERN_INFO "jsm: Port %d failed. Aborting...\n", i);
-                       return rc;
-               }
-               else
-                       printk(KERN_INFO "jsm: Port %d added\n", i);
-       }
-
-       jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n");
-       return 0;
-}
-
-int jsm_remove_uart_port(struct jsm_board *brd)
-{
-       int i;
-       struct jsm_channel *ch;
-
-       if (!brd)
-               return -ENXIO;
-
-       jsm_printk(INIT, INFO, &brd->pci_dev, "start\n");
-
-       /*
-        * Initialize board structure elements.
-        */
-
-       brd->nasync = brd->maxports;
-
-       /* Set up channel variables */
-       for (i = 0; i < brd->nasync; i++) {
-
-               if (!brd->channels[i])
-                       continue;
-
-               ch = brd->channels[i];
-
-               clear_bit(ch->uart_port.line, linemap);
-               uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port);
-       }
-
-       jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n");
-       return 0;
-}
-
-void jsm_input(struct jsm_channel *ch)
-{
-       struct jsm_board *bd;
-       struct tty_struct *tp;
-       u32 rmask;
-       u16 head;
-       u16 tail;
-       int data_len;
-       unsigned long lock_flags;
-       int len = 0;
-       int n = 0;
-       int s = 0;
-       int i = 0;
-
-       jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start\n");
-
-       if (!ch)
-               return;
-
-       tp = ch->uart_port.state->port.tty;
-
-       bd = ch->ch_bd;
-       if(!bd)
-               return;
-
-       spin_lock_irqsave(&ch->ch_lock, lock_flags);
-
-       /*
-        *Figure the number of characters in the buffer.
-        *Exit immediately if none.
-        */
-
-       rmask = RQUEUEMASK;
-
-       head = ch->ch_r_head & rmask;
-       tail = ch->ch_r_tail & rmask;
-
-       data_len = (head - tail) & rmask;
-       if (data_len == 0) {
-               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-               return;
-       }
-
-       jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start\n");
-
-       /*
-        *If the device is not open, or CREAD is off, flush
-        *input data and return immediately.
-        */
-       if (!tp ||
-               !(tp->termios->c_cflag & CREAD) ) {
-
-               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
-                       "input. dropping %d bytes on port %d...\n", data_len, ch->ch_portnum);
-               ch->ch_r_head = tail;
-
-               /* Force queue flow control to be released, if needed */
-               jsm_check_queue_flow_control(ch);
-
-               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-               return;
-       }
-
-       /*
-        * If we are throttled, simply don't read any data.
-        */
-       if (ch->ch_flags & CH_STOPI) {
-               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
-                       "Port %d throttled, not reading any data. head: %x tail: %x\n",
-                       ch->ch_portnum, head, tail);
-               return;
-       }
-
-       jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start 2\n");
-
-       if (data_len <= 0) {
-               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "jsm_input 1\n");
-               return;
-       }
-
-       len = tty_buffer_request_room(tp, data_len);
-       n = len;
-
-       /*
-        * n now contains the most amount of data we can copy,
-        * bounded either by the flip buffer size or the amount
-        * of data the card actually has pending...
-        */
-       while (n) {
-               s = ((head >= tail) ? head : RQUEUESIZE) - tail;
-               s = min(s, n);
-
-               if (s <= 0)
-                       break;
-
-                       /*
-                        * If conditions are such that ld needs to see all
-                        * UART errors, we will have to walk each character
-                        * and error byte and send them to the buffer one at
-                        * a time.
-                        */
-
-               if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
-                       for (i = 0; i < s; i++) {
-                               /*
-                                * Give the Linux ld the flags in the
-                                * format it likes.
-                                */
-                               if (*(ch->ch_equeue +tail +i) & UART_LSR_BI)
-                                       tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i),  TTY_BREAK);
-                               else if (*(ch->ch_equeue +tail +i) & UART_LSR_PE)
-                                       tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_PARITY);
-                               else if (*(ch->ch_equeue +tail +i) & UART_LSR_FE)
-                                       tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_FRAME);
-                               else
-                                       tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_NORMAL);
-                       }
-               } else {
-                       tty_insert_flip_string(tp, ch->ch_rqueue + tail, s) ;
-               }
-               tail += s;
-               n -= s;
-               /* Flip queue if needed */
-               tail &= rmask;
-       }
-
-       ch->ch_r_tail = tail & rmask;
-       ch->ch_e_tail = tail & rmask;
-       jsm_check_queue_flow_control(ch);
-       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-
-       /* Tell the tty layer its okay to "eat" the data now */
-       tty_flip_buffer_push(tp);
-
-       jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n");
-}
-
-static void jsm_carrier(struct jsm_channel *ch)
-{
-       struct jsm_board *bd;
-
-       int virt_carrier = 0;
-       int phys_carrier = 0;
-
-       jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, "start\n");
-       if (!ch)
-               return;
-
-       bd = ch->ch_bd;
-
-       if (!bd)
-               return;
-
-       if (ch->ch_mistat & UART_MSR_DCD) {
-               jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev,
-                       "mistat: %x D_CD: %x\n", ch->ch_mistat, ch->ch_mistat & UART_MSR_DCD);
-               phys_carrier = 1;
-       }
-
-       if (ch->ch_c_cflag & CLOCAL)
-               virt_carrier = 1;
-
-       jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev,
-               "DCD: physical: %d virt: %d\n", phys_carrier, virt_carrier);
-
-       /*
-        * Test for a VIRTUAL carrier transition to HIGH.
-        */
-       if (((ch->ch_flags & CH_FCAR) == 0) && (virt_carrier == 1)) {
-
-               /*
-                * When carrier rises, wake any threads waiting
-                * for carrier in the open routine.
-                */
-
-               jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev,
-                       "carrier: virt DCD rose\n");
-
-               if (waitqueue_active(&(ch->ch_flags_wait)))
-                       wake_up_interruptible(&ch->ch_flags_wait);
-       }
-
-       /*
-        * Test for a PHYSICAL carrier transition to HIGH.
-        */
-       if (((ch->ch_flags & CH_CD) == 0) && (phys_carrier == 1)) {
-
-               /*
-                * When carrier rises, wake any threads waiting
-                * for carrier in the open routine.
-                */
-
-               jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev,
-                       "carrier: physical DCD rose\n");
-
-               if (waitqueue_active(&(ch->ch_flags_wait)))
-                       wake_up_interruptible(&ch->ch_flags_wait);
-       }
-
-       /*
-        *  Test for a PHYSICAL transition to low, so long as we aren't
-        *  currently ignoring physical transitions (which is what "virtual
-        *  carrier" indicates).
-        *
-        *  The transition of the virtual carrier to low really doesn't
-        *  matter... it really only means "ignore carrier state", not
-        *  "make pretend that carrier is there".
-        */
-       if ((virt_carrier == 0) && ((ch->ch_flags & CH_CD) != 0)
-                       && (phys_carrier == 0)) {
-               /*
-                *      When carrier drops:
-                *
-                *      Drop carrier on all open units.
-                *
-                *      Flush queues, waking up any task waiting in the
-                *      line discipline.
-                *
-                *      Send a hangup to the control terminal.
-                *
-                *      Enable all select calls.
-                */
-               if (waitqueue_active(&(ch->ch_flags_wait)))
-                       wake_up_interruptible(&ch->ch_flags_wait);
-       }
-
-       /*
-        *  Make sure that our cached values reflect the current reality.
-        */
-       if (virt_carrier == 1)
-               ch->ch_flags |= CH_FCAR;
-       else
-               ch->ch_flags &= ~CH_FCAR;
-
-       if (phys_carrier == 1)
-               ch->ch_flags |= CH_CD;
-       else
-               ch->ch_flags &= ~CH_CD;
-}
-
-
-void jsm_check_queue_flow_control(struct jsm_channel *ch)
-{
-       struct board_ops *bd_ops = ch->ch_bd->bd_ops;
-       int qleft;
-
-       /* Store how much space we have left in the queue */
-       if ((qleft = ch->ch_r_tail - ch->ch_r_head - 1) < 0)
-               qleft += RQUEUEMASK + 1;
-
-       /*
-        * Check to see if we should enforce flow control on our queue because
-        * the ld (or user) isn't reading data out of our queue fast enuf.
-        *
-        * NOTE: This is done based on what the current flow control of the
-        * port is set for.
-        *
-        * 1) HWFLOW (RTS) - Turn off the UART's Receive interrupt.
-        *      This will cause the UART's FIFO to back up, and force
-        *      the RTS signal to be dropped.
-        * 2) SWFLOW (IXOFF) - Keep trying to send a stop character to
-        *      the other side, in hopes it will stop sending data to us.
-        * 3) NONE - Nothing we can do.  We will simply drop any extra data
-        *      that gets sent into us when the queue fills up.
-        */
-       if (qleft < 256) {
-               /* HWFLOW */
-               if (ch->ch_c_cflag & CRTSCTS) {
-                       if(!(ch->ch_flags & CH_RECEIVER_OFF)) {
-                               bd_ops->disable_receiver(ch);
-                               ch->ch_flags |= (CH_RECEIVER_OFF);
-                               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
-                                       "Internal queue hit hilevel mark (%d)! Turning off interrupts.\n",
-                                       qleft);
-                       }
-               }
-               /* SWFLOW */
-               else if (ch->ch_c_iflag & IXOFF) {
-                       if (ch->ch_stops_sent <= MAX_STOPS_SENT) {
-                               bd_ops->send_stop_character(ch);
-                               ch->ch_stops_sent++;
-                               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
-                                       "Sending stop char! Times sent: %x\n", ch->ch_stops_sent);
-                       }
-               }
-       }
-
-       /*
-        * Check to see if we should unenforce flow control because
-        * ld (or user) finally read enuf data out of our queue.
-        *
-        * NOTE: This is done based on what the current flow control of the
-        * port is set for.
-        *
-        * 1) HWFLOW (RTS) - Turn back on the UART's Receive interrupt.
-        *      This will cause the UART's FIFO to raise RTS back up,
-        *      which will allow the other side to start sending data again.
-        * 2) SWFLOW (IXOFF) - Send a start character to
-        *      the other side, so it will start sending data to us again.
-        * 3) NONE - Do nothing. Since we didn't do anything to turn off the
-        *      other side, we don't need to do anything now.
-        */
-       if (qleft > (RQUEUESIZE / 2)) {
-               /* HWFLOW */
-               if (ch->ch_c_cflag & CRTSCTS) {
-                       if (ch->ch_flags & CH_RECEIVER_OFF) {
-                               bd_ops->enable_receiver(ch);
-                               ch->ch_flags &= ~(CH_RECEIVER_OFF);
-                               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
-                                       "Internal queue hit lowlevel mark (%d)! Turning on interrupts.\n",
-                                       qleft);
-                       }
-               }
-               /* SWFLOW */
-               else if (ch->ch_c_iflag & IXOFF && ch->ch_stops_sent) {
-                       ch->ch_stops_sent = 0;
-                       bd_ops->send_start_character(ch);
-                       jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "Sending start char!\n");
-               }
-       }
-}
-
-/*
- * jsm_tty_write()
- *
- * Take data from the user or kernel and send it out to the FEP.
- * In here exists all the Transparent Print magic as well.
- */
-int jsm_tty_write(struct uart_port *port)
-{
-       int bufcount;
-       int data_count = 0,data_count1 =0;
-       u16 head;
-       u16 tail;
-       u16 tmask;
-       u32 remain;
-       int temp_tail = port->state->xmit.tail;
-       struct jsm_channel *channel = (struct jsm_channel *)port;
-
-       tmask = WQUEUEMASK;
-       head = (channel->ch_w_head) & tmask;
-       tail = (channel->ch_w_tail) & tmask;
-
-       if ((bufcount = tail - head - 1) < 0)
-               bufcount += WQUEUESIZE;
-
-       bufcount = min(bufcount, 56);
-       remain = WQUEUESIZE - head;
-
-       data_count = 0;
-       if (bufcount >= remain) {
-               bufcount -= remain;
-               while ((port->state->xmit.head != temp_tail) &&
-               (data_count < remain)) {
-                       channel->ch_wqueue[head++] =
-                       port->state->xmit.buf[temp_tail];
-
-                       temp_tail++;
-                       temp_tail &= (UART_XMIT_SIZE - 1);
-                       data_count++;
-               }
-               if (data_count == remain) head = 0;
-       }
-
-       data_count1 = 0;
-       if (bufcount > 0) {
-               remain = bufcount;
-               while ((port->state->xmit.head != temp_tail) &&
-                       (data_count1 < remain)) {
-                       channel->ch_wqueue[head++] =
-                               port->state->xmit.buf[temp_tail];
-
-                       temp_tail++;
-                       temp_tail &= (UART_XMIT_SIZE - 1);
-                       data_count1++;
-
-               }
-       }
-
-       port->state->xmit.tail = temp_tail;
-
-       data_count += data_count1;
-       if (data_count) {
-               head &= tmask;
-               channel->ch_w_head = head;
-       }
-
-       if (data_count) {
-               channel->ch_bd->bd_ops->copy_data_from_queue_to_uart(channel);
-       }
-
-       return data_count;
-}
diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c
deleted file mode 100644 (file)
index 25a8bc5..0000000
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Based on the same principle as kgdboe using the NETPOLL api, this
- * driver uses a console polling api to implement a gdb serial inteface
- * which is multiplexed on a console port.
- *
- * Maintainer: Jason Wessel <jason.wessel@windriver.com>
- *
- * 2007-2008 (c) Jason Wessel - Wind River Systems, Inc.
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-#include <linux/kernel.h>
-#include <linux/ctype.h>
-#include <linux/kgdb.h>
-#include <linux/kdb.h>
-#include <linux/tty.h>
-#include <linux/console.h>
-#include <linux/vt_kern.h>
-#include <linux/input.h>
-
-#define MAX_CONFIG_LEN         40
-
-static struct kgdb_io          kgdboc_io_ops;
-
-/* -1 = init not run yet, 0 = unconfigured, 1 = configured. */
-static int configured          = -1;
-
-static char config[MAX_CONFIG_LEN];
-static struct kparam_string kps = {
-       .string                 = config,
-       .maxlen                 = MAX_CONFIG_LEN,
-};
-
-static int kgdboc_use_kms;  /* 1 if we use kernel mode switching */
-static struct tty_driver       *kgdb_tty_driver;
-static int                     kgdb_tty_line;
-
-#ifdef CONFIG_KDB_KEYBOARD
-static int kgdboc_reset_connect(struct input_handler *handler,
-                               struct input_dev *dev,
-                               const struct input_device_id *id)
-{
-       input_reset_device(dev);
-
-       /* Retrun an error - we do not want to bind, just to reset */
-       return -ENODEV;
-}
-
-static void kgdboc_reset_disconnect(struct input_handle *handle)
-{
-       /* We do not expect anyone to actually bind to us */
-       BUG();
-}
-
-static const struct input_device_id kgdboc_reset_ids[] = {
-       {
-               .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
-               .evbit = { BIT_MASK(EV_KEY) },
-       },
-       { }
-};
-
-static struct input_handler kgdboc_reset_handler = {
-       .connect        = kgdboc_reset_connect,
-       .disconnect     = kgdboc_reset_disconnect,
-       .name           = "kgdboc_reset",
-       .id_table       = kgdboc_reset_ids,
-};
-
-static DEFINE_MUTEX(kgdboc_reset_mutex);
-
-static void kgdboc_restore_input_helper(struct work_struct *dummy)
-{
-       /*
-        * We need to take a mutex to prevent several instances of
-        * this work running on different CPUs so they don't try
-        * to register again already registered handler.
-        */
-       mutex_lock(&kgdboc_reset_mutex);
-
-       if (input_register_handler(&kgdboc_reset_handler) == 0)
-               input_unregister_handler(&kgdboc_reset_handler);
-
-       mutex_unlock(&kgdboc_reset_mutex);
-}
-
-static DECLARE_WORK(kgdboc_restore_input_work, kgdboc_restore_input_helper);
-
-static void kgdboc_restore_input(void)
-{
-       if (likely(system_state == SYSTEM_RUNNING))
-               schedule_work(&kgdboc_restore_input_work);
-}
-
-static int kgdboc_register_kbd(char **cptr)
-{
-       if (strncmp(*cptr, "kbd", 3) == 0) {
-               if (kdb_poll_idx < KDB_POLL_FUNC_MAX) {
-                       kdb_poll_funcs[kdb_poll_idx] = kdb_get_kbd_char;
-                       kdb_poll_idx++;
-                       if (cptr[0][3] == ',')
-                               *cptr += 4;
-                       else
-                               return 1;
-               }
-       }
-       return 0;
-}
-
-static void kgdboc_unregister_kbd(void)
-{
-       int i;
-
-       for (i = 0; i < kdb_poll_idx; i++) {
-               if (kdb_poll_funcs[i] == kdb_get_kbd_char) {
-                       kdb_poll_idx--;
-                       kdb_poll_funcs[i] = kdb_poll_funcs[kdb_poll_idx];
-                       kdb_poll_funcs[kdb_poll_idx] = NULL;
-                       i--;
-               }
-       }
-       flush_work_sync(&kgdboc_restore_input_work);
-}
-#else /* ! CONFIG_KDB_KEYBOARD */
-#define kgdboc_register_kbd(x) 0
-#define kgdboc_unregister_kbd()
-#define kgdboc_restore_input()
-#endif /* ! CONFIG_KDB_KEYBOARD */
-
-static int kgdboc_option_setup(char *opt)
-{
-       if (strlen(opt) > MAX_CONFIG_LEN) {
-               printk(KERN_ERR "kgdboc: config string too long\n");
-               return -ENOSPC;
-       }
-       strcpy(config, opt);
-
-       return 0;
-}
-
-__setup("kgdboc=", kgdboc_option_setup);
-
-static void cleanup_kgdboc(void)
-{
-       kgdboc_unregister_kbd();
-       if (configured == 1)
-               kgdb_unregister_io_module(&kgdboc_io_ops);
-}
-
-static int configure_kgdboc(void)
-{
-       struct tty_driver *p;
-       int tty_line = 0;
-       int err;
-       char *cptr = config;
-       struct console *cons;
-
-       err = kgdboc_option_setup(config);
-       if (err || !strlen(config) || isspace(config[0]))
-               goto noconfig;
-
-       err = -ENODEV;
-       kgdboc_io_ops.is_console = 0;
-       kgdb_tty_driver = NULL;
-
-       kgdboc_use_kms = 0;
-       if (strncmp(cptr, "kms,", 4) == 0) {
-               cptr += 4;
-               kgdboc_use_kms = 1;
-       }
-
-       if (kgdboc_register_kbd(&cptr))
-               goto do_register;
-
-       p = tty_find_polling_driver(cptr, &tty_line);
-       if (!p)
-               goto noconfig;
-
-       cons = console_drivers;
-       while (cons) {
-               int idx;
-               if (cons->device && cons->device(cons, &idx) == p &&
-                   idx == tty_line) {
-                       kgdboc_io_ops.is_console = 1;
-                       break;
-               }
-               cons = cons->next;
-       }
-
-       kgdb_tty_driver = p;
-       kgdb_tty_line = tty_line;
-
-do_register:
-       err = kgdb_register_io_module(&kgdboc_io_ops);
-       if (err)
-               goto noconfig;
-
-       configured = 1;
-
-       return 0;
-
-noconfig:
-       config[0] = 0;
-       configured = 0;
-       cleanup_kgdboc();
-
-       return err;
-}
-
-static int __init init_kgdboc(void)
-{
-       /* Already configured? */
-       if (configured == 1)
-               return 0;
-
-       return configure_kgdboc();
-}
-
-static int kgdboc_get_char(void)
-{
-       if (!kgdb_tty_driver)
-               return -1;
-       return kgdb_tty_driver->ops->poll_get_char(kgdb_tty_driver,
-                                               kgdb_tty_line);
-}
-
-static void kgdboc_put_char(u8 chr)
-{
-       if (!kgdb_tty_driver)
-               return;
-       kgdb_tty_driver->ops->poll_put_char(kgdb_tty_driver,
-                                       kgdb_tty_line, chr);
-}
-
-static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp)
-{
-       int len = strlen(kmessage);
-
-       if (len >= MAX_CONFIG_LEN) {
-               printk(KERN_ERR "kgdboc: config string too long\n");
-               return -ENOSPC;
-       }
-
-       /* Only copy in the string if the init function has not run yet */
-       if (configured < 0) {
-               strcpy(config, kmessage);
-               return 0;
-       }
-
-       if (kgdb_connected) {
-               printk(KERN_ERR
-                      "kgdboc: Cannot reconfigure while KGDB is connected.\n");
-
-               return -EBUSY;
-       }
-
-       strcpy(config, kmessage);
-       /* Chop out \n char as a result of echo */
-       if (config[len - 1] == '\n')
-               config[len - 1] = '\0';
-
-       if (configured == 1)
-               cleanup_kgdboc();
-
-       /* Go and configure with the new params. */
-       return configure_kgdboc();
-}
-
-static int dbg_restore_graphics;
-
-static void kgdboc_pre_exp_handler(void)
-{
-       if (!dbg_restore_graphics && kgdboc_use_kms) {
-               dbg_restore_graphics = 1;
-               con_debug_enter(vc_cons[fg_console].d);
-       }
-       /* Increment the module count when the debugger is active */
-       if (!kgdb_connected)
-               try_module_get(THIS_MODULE);
-}
-
-static void kgdboc_post_exp_handler(void)
-{
-       /* decrement the module count when the debugger detaches */
-       if (!kgdb_connected)
-               module_put(THIS_MODULE);
-       if (kgdboc_use_kms && dbg_restore_graphics) {
-               dbg_restore_graphics = 0;
-               con_debug_leave();
-       }
-       kgdboc_restore_input();
-}
-
-static struct kgdb_io kgdboc_io_ops = {
-       .name                   = "kgdboc",
-       .read_char              = kgdboc_get_char,
-       .write_char             = kgdboc_put_char,
-       .pre_exception          = kgdboc_pre_exp_handler,
-       .post_exception         = kgdboc_post_exp_handler,
-};
-
-#ifdef CONFIG_KGDB_SERIAL_CONSOLE
-/* This is only available if kgdboc is a built in for early debugging */
-static int __init kgdboc_early_init(char *opt)
-{
-       /* save the first character of the config string because the
-        * init routine can destroy it.
-        */
-       char save_ch;
-
-       kgdboc_option_setup(opt);
-       save_ch = config[0];
-       init_kgdboc();
-       config[0] = save_ch;
-       return 0;
-}
-
-early_param("ekgdboc", kgdboc_early_init);
-#endif /* CONFIG_KGDB_SERIAL_CONSOLE */
-
-module_init(init_kgdboc);
-module_exit(cleanup_kgdboc);
-module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644);
-MODULE_PARM_DESC(kgdboc, "<serial_device>[,baud]");
-MODULE_DESCRIPTION("KGDB Console TTY Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c
deleted file mode 100644 (file)
index bea5c21..0000000
+++ /dev/null
@@ -1,1192 +0,0 @@
-/*
- *  m32r_sio.c
- *
- *  Driver for M32R serial ports
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *  Based on drivers/serial/8250.c.
- *
- *  Copyright (C) 2001  Russell King.
- *  Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
- *
- * 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.
- */
-
-/*
- * A note about mapbase / membase
- *
- *  mapbase is the physical address of the IO port.  Currently, we don't
- *  support this very well, and it may well be dropped from this driver
- *  in future.  As such, mapbase should be NULL.
- *
- *  membase is an 'ioremapped' cookie.  This is compatible with the old
- *  serial.c driver, and is currently the preferred form.
- */
-
-#if defined(CONFIG_SERIAL_M32R_SIO_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/serial.h>
-#include <linux/serialP.h>
-#include <linux/delay.h>
-
-#include <asm/m32r.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#define PORT_M32R_BASE PORT_M32R_SIO
-#define PORT_INDEX(x)  (x - PORT_M32R_BASE + 1)
-#define BAUD_RATE      115200
-
-#include <linux/serial_core.h>
-#include "m32r_sio.h"
-#include "m32r_sio_reg.h"
-
-/*
- * Debugging.
- */
-#if 0
-#define DEBUG_AUTOCONF(fmt...) printk(fmt)
-#else
-#define DEBUG_AUTOCONF(fmt...) do { } while (0)
-#endif
-
-#if 0
-#define DEBUG_INTR(fmt...)     printk(fmt)
-#else
-#define DEBUG_INTR(fmt...)     do { } while (0)
-#endif
-
-#define PASS_LIMIT     256
-
-/*
- * We default to IRQ0 for the "no irq" hack.   Some
- * machine types want others as well - they're free
- * to redefine this in their header file.
- */
-#define is_real_interrupt(irq) ((irq) != 0)
-
-#define BASE_BAUD      115200
-
-/* Standard COM flags */
-#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST)
-
-/*
- * SERIAL_PORT_DFNS tells us about built-in ports that have no
- * standard enumeration mechanism.   Platforms that can find all
- * serial ports via mechanisms like ACPI or PCI need not supply it.
- */
-#if defined(CONFIG_PLAT_USRV)
-
-#define SERIAL_PORT_DFNS                                               \
-       /* UART  CLK     PORT   IRQ            FLAGS */                 \
-       { 0, BASE_BAUD, 0x3F8, PLD_IRQ_UART0, STD_COM_FLAGS }, /* ttyS0 */ \
-       { 0, BASE_BAUD, 0x2F8, PLD_IRQ_UART1, STD_COM_FLAGS }, /* ttyS1 */
-
-#else /* !CONFIG_PLAT_USRV */
-
-#if defined(CONFIG_SERIAL_M32R_PLDSIO)
-#define SERIAL_PORT_DFNS                                               \
-       { 0, BASE_BAUD, ((unsigned long)PLD_ESIO0CR), PLD_IRQ_SIO0_RCV, \
-         STD_COM_FLAGS }, /* ttyS0 */
-#else
-#define SERIAL_PORT_DFNS                                               \
-       { 0, BASE_BAUD, M32R_SIO_OFFSET, M32R_IRQ_SIO0_R,               \
-         STD_COM_FLAGS }, /* ttyS0 */
-#endif
-
-#endif /* !CONFIG_PLAT_USRV */
-
-static struct old_serial_port old_serial_port[] = {
-       SERIAL_PORT_DFNS
-};
-
-#define UART_NR        ARRAY_SIZE(old_serial_port)
-
-struct uart_sio_port {
-       struct uart_port        port;
-       struct timer_list       timer;          /* "no irq" timer */
-       struct list_head        list;           /* ports on this IRQ */
-       unsigned short          rev;
-       unsigned char           acr;
-       unsigned char           ier;
-       unsigned char           lcr;
-       unsigned char           mcr_mask;       /* mask of user bits */
-       unsigned char           mcr_force;      /* mask of forced bits */
-       unsigned char           lsr_break_flag;
-
-       /*
-        * We provide a per-port pm hook.
-        */
-       void                    (*pm)(struct uart_port *port,
-                                     unsigned int state, unsigned int old);
-};
-
-struct irq_info {
-       spinlock_t              lock;
-       struct list_head        *head;
-};
-
-static struct irq_info irq_lists[NR_IRQS];
-
-/*
- * Here we define the default xmit fifo size used for each type of UART.
- */
-static const struct serial_uart_config uart_config[] = {
-       [PORT_UNKNOWN] = {
-               .name                   = "unknown",
-               .dfl_xmit_fifo_size     = 1,
-               .flags                  = 0,
-       },
-       [PORT_INDEX(PORT_M32R_SIO)] = {
-               .name                   = "M32RSIO",
-               .dfl_xmit_fifo_size     = 1,
-               .flags                  = 0,
-       },
-};
-
-#ifdef CONFIG_SERIAL_M32R_PLDSIO
-
-#define __sio_in(x) inw((unsigned long)(x))
-#define __sio_out(v,x) outw((v),(unsigned long)(x))
-
-static inline void sio_set_baud_rate(unsigned long baud)
-{
-       unsigned short sbaud;
-       sbaud = (boot_cpu_data.bus_clock / (baud * 4))-1;
-       __sio_out(sbaud, PLD_ESIO0BAUR);
-}
-
-static void sio_reset(void)
-{
-       unsigned short tmp;
-
-       tmp = __sio_in(PLD_ESIO0RXB);
-       tmp = __sio_in(PLD_ESIO0RXB);
-       tmp = __sio_in(PLD_ESIO0CR);
-       sio_set_baud_rate(BAUD_RATE);
-       __sio_out(0x0300, PLD_ESIO0CR);
-       __sio_out(0x0003, PLD_ESIO0CR);
-}
-
-static void sio_init(void)
-{
-       unsigned short tmp;
-
-       tmp = __sio_in(PLD_ESIO0RXB);
-       tmp = __sio_in(PLD_ESIO0RXB);
-       tmp = __sio_in(PLD_ESIO0CR);
-       __sio_out(0x0300, PLD_ESIO0CR);
-       __sio_out(0x0003, PLD_ESIO0CR);
-}
-
-static void sio_error(int *status)
-{
-       printk("SIO0 error[%04x]\n", *status);
-       do {
-               sio_init();
-       } while ((*status = __sio_in(PLD_ESIO0CR)) != 3);
-}
-
-#else /* not CONFIG_SERIAL_M32R_PLDSIO */
-
-#define __sio_in(x) inl(x)
-#define __sio_out(v,x) outl((v),(x))
-
-static inline void sio_set_baud_rate(unsigned long baud)
-{
-       unsigned long i, j;
-
-       i = boot_cpu_data.bus_clock / (baud * 16);
-       j = (boot_cpu_data.bus_clock - (i * baud * 16)) / baud;
-       i -= 1;
-       j = (j + 1) >> 1;
-
-       __sio_out(i, M32R_SIO0_BAUR_PORTL);
-       __sio_out(j, M32R_SIO0_RBAUR_PORTL);
-}
-
-static void sio_reset(void)
-{
-       __sio_out(0x00000300, M32R_SIO0_CR_PORTL);      /* init status */
-       __sio_out(0x00000800, M32R_SIO0_MOD1_PORTL);    /* 8bit        */
-       __sio_out(0x00000080, M32R_SIO0_MOD0_PORTL);    /* 1stop non   */
-       sio_set_baud_rate(BAUD_RATE);
-       __sio_out(0x00000000, M32R_SIO0_TRCR_PORTL);
-       __sio_out(0x00000003, M32R_SIO0_CR_PORTL);      /* RXCEN */
-}
-
-static void sio_init(void)
-{
-       unsigned int tmp;
-
-       tmp = __sio_in(M32R_SIO0_RXB_PORTL);
-       tmp = __sio_in(M32R_SIO0_RXB_PORTL);
-       tmp = __sio_in(M32R_SIO0_STS_PORTL);
-       __sio_out(0x00000003, M32R_SIO0_CR_PORTL);
-}
-
-static void sio_error(int *status)
-{
-       printk("SIO0 error[%04x]\n", *status);
-       do {
-               sio_init();
-       } while ((*status = __sio_in(M32R_SIO0_CR_PORTL)) != 3);
-}
-
-#endif /* CONFIG_SERIAL_M32R_PLDSIO */
-
-static unsigned int sio_in(struct uart_sio_port *up, int offset)
-{
-       return __sio_in(up->port.iobase + offset);
-}
-
-static void sio_out(struct uart_sio_port *up, int offset, int value)
-{
-       __sio_out(value, up->port.iobase + offset);
-}
-
-static unsigned int serial_in(struct uart_sio_port *up, int offset)
-{
-       if (!offset)
-               return 0;
-
-       return __sio_in(offset);
-}
-
-static void serial_out(struct uart_sio_port *up, int offset, int value)
-{
-       if (!offset)
-               return;
-
-       __sio_out(value, offset);
-}
-
-static void m32r_sio_stop_tx(struct uart_port *port)
-{
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-
-       if (up->ier & UART_IER_THRI) {
-               up->ier &= ~UART_IER_THRI;
-               serial_out(up, UART_IER, up->ier);
-       }
-}
-
-static void m32r_sio_start_tx(struct uart_port *port)
-{
-#ifdef CONFIG_SERIAL_M32R_PLDSIO
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-       struct circ_buf *xmit = &up->port.state->xmit;
-
-       if (!(up->ier & UART_IER_THRI)) {
-               up->ier |= UART_IER_THRI;
-               serial_out(up, UART_IER, up->ier);
-               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               up->port.icount.tx++;
-       }
-       while((serial_in(up, UART_LSR) & UART_EMPTY) != UART_EMPTY);
-#else
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-
-       if (!(up->ier & UART_IER_THRI)) {
-               up->ier |= UART_IER_THRI;
-               serial_out(up, UART_IER, up->ier);
-       }
-#endif
-}
-
-static void m32r_sio_stop_rx(struct uart_port *port)
-{
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-
-       up->ier &= ~UART_IER_RLSI;
-       up->port.read_status_mask &= ~UART_LSR_DR;
-       serial_out(up, UART_IER, up->ier);
-}
-
-static void m32r_sio_enable_ms(struct uart_port *port)
-{
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-
-       up->ier |= UART_IER_MSI;
-       serial_out(up, UART_IER, up->ier);
-}
-
-static void receive_chars(struct uart_sio_port *up, int *status)
-{
-       struct tty_struct *tty = up->port.state->port.tty;
-       unsigned char ch;
-       unsigned char flag;
-       int max_count = 256;
-
-       do {
-               ch = sio_in(up, SIORXB);
-               flag = TTY_NORMAL;
-               up->port.icount.rx++;
-
-               if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
-                                      UART_LSR_FE | UART_LSR_OE))) {
-                       /*
-                        * For statistics only
-                        */
-                       if (*status & UART_LSR_BI) {
-                               *status &= ~(UART_LSR_FE | UART_LSR_PE);
-                               up->port.icount.brk++;
-                               /*
-                                * We do the SysRQ and SAK checking
-                                * here because otherwise the break
-                                * may get masked by ignore_status_mask
-                                * or read_status_mask.
-                                */
-                               if (uart_handle_break(&up->port))
-                                       goto ignore_char;
-                       } else if (*status & UART_LSR_PE)
-                               up->port.icount.parity++;
-                       else if (*status & UART_LSR_FE)
-                               up->port.icount.frame++;
-                       if (*status & UART_LSR_OE)
-                               up->port.icount.overrun++;
-
-                       /*
-                        * Mask off conditions which should be ingored.
-                        */
-                       *status &= up->port.read_status_mask;
-
-                       if (up->port.line == up->port.cons->index) {
-                               /* Recover the break flag from console xmit */
-                               *status |= up->lsr_break_flag;
-                               up->lsr_break_flag = 0;
-                       }
-
-                       if (*status & UART_LSR_BI) {
-                               DEBUG_INTR("handling break....");
-                               flag = TTY_BREAK;
-                       } else if (*status & UART_LSR_PE)
-                               flag = TTY_PARITY;
-                       else if (*status & UART_LSR_FE)
-                               flag = TTY_FRAME;
-               }
-               if (uart_handle_sysrq_char(&up->port, ch))
-                       goto ignore_char;
-               if ((*status & up->port.ignore_status_mask) == 0)
-                       tty_insert_flip_char(tty, ch, flag);
-
-               if (*status & UART_LSR_OE) {
-                       /*
-                        * Overrun is special, since it's reported
-                        * immediately, and doesn't affect the current
-                        * character.
-                        */
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               }
-       ignore_char:
-               *status = serial_in(up, UART_LSR);
-       } while ((*status & UART_LSR_DR) && (max_count-- > 0));
-       tty_flip_buffer_push(tty);
-}
-
-static void transmit_chars(struct uart_sio_port *up)
-{
-       struct circ_buf *xmit = &up->port.state->xmit;
-       int count;
-
-       if (up->port.x_char) {
-#ifndef CONFIG_SERIAL_M32R_PLDSIO      /* XXX */
-               serial_out(up, UART_TX, up->port.x_char);
-#endif
-               up->port.icount.tx++;
-               up->port.x_char = 0;
-               return;
-       }
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
-               m32r_sio_stop_tx(&up->port);
-               return;
-       }
-
-       count = up->port.fifosize;
-       do {
-               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               up->port.icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-               while (!(serial_in(up, UART_LSR) & UART_LSR_THRE));
-
-       } while (--count > 0);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&up->port);
-
-       DEBUG_INTR("THRE...");
-
-       if (uart_circ_empty(xmit))
-               m32r_sio_stop_tx(&up->port);
-}
-
-/*
- * This handles the interrupt from one port.
- */
-static inline void m32r_sio_handle_port(struct uart_sio_port *up,
-       unsigned int status)
-{
-       DEBUG_INTR("status = %x...", status);
-
-       if (status & 0x04)
-               receive_chars(up, &status);
-       if (status & 0x01)
-               transmit_chars(up);
-}
-
-/*
- * This is the serial driver's interrupt routine.
- *
- * Arjan thinks the old way was overly complex, so it got simplified.
- * Alan disagrees, saying that need the complexity to handle the weird
- * nature of ISA shared interrupts.  (This is a special exception.)
- *
- * In order to handle ISA shared interrupts properly, we need to check
- * that all ports have been serviced, and therefore the ISA interrupt
- * line has been de-asserted.
- *
- * This means we need to loop through all ports. checking that they
- * don't have an interrupt pending.
- */
-static irqreturn_t m32r_sio_interrupt(int irq, void *dev_id)
-{
-       struct irq_info *i = dev_id;
-       struct list_head *l, *end = NULL;
-       int pass_counter = 0;
-
-       DEBUG_INTR("m32r_sio_interrupt(%d)...", irq);
-
-#ifdef CONFIG_SERIAL_M32R_PLDSIO
-//     if (irq == PLD_IRQ_SIO0_SND)
-//             irq = PLD_IRQ_SIO0_RCV;
-#else
-       if (irq == M32R_IRQ_SIO0_S)
-               irq = M32R_IRQ_SIO0_R;
-#endif
-
-       spin_lock(&i->lock);
-
-       l = i->head;
-       do {
-               struct uart_sio_port *up;
-               unsigned int sts;
-
-               up = list_entry(l, struct uart_sio_port, list);
-
-               sts = sio_in(up, SIOSTS);
-               if (sts & 0x5) {
-                       spin_lock(&up->port.lock);
-                       m32r_sio_handle_port(up, sts);
-                       spin_unlock(&up->port.lock);
-
-                       end = NULL;
-               } else if (end == NULL)
-                       end = l;
-
-               l = l->next;
-
-               if (l == i->head && pass_counter++ > PASS_LIMIT) {
-                       if (sts & 0xe0)
-                               sio_error(&sts);
-                       break;
-               }
-       } while (l != end);
-
-       spin_unlock(&i->lock);
-
-       DEBUG_INTR("end.\n");
-
-       return IRQ_HANDLED;
-}
-
-/*
- * To support ISA shared interrupts, we need to have one interrupt
- * handler that ensures that the IRQ line has been deasserted
- * before returning.  Failing to do this will result in the IRQ
- * line being stuck active, and, since ISA irqs are edge triggered,
- * no more IRQs will be seen.
- */
-static void serial_do_unlink(struct irq_info *i, struct uart_sio_port *up)
-{
-       spin_lock_irq(&i->lock);
-
-       if (!list_empty(i->head)) {
-               if (i->head == &up->list)
-                       i->head = i->head->next;
-               list_del(&up->list);
-       } else {
-               BUG_ON(i->head != &up->list);
-               i->head = NULL;
-       }
-
-       spin_unlock_irq(&i->lock);
-}
-
-static int serial_link_irq_chain(struct uart_sio_port *up)
-{
-       struct irq_info *i = irq_lists + up->port.irq;
-       int ret, irq_flags = 0;
-
-       spin_lock_irq(&i->lock);
-
-       if (i->head) {
-               list_add(&up->list, i->head);
-               spin_unlock_irq(&i->lock);
-
-               ret = 0;
-       } else {
-               INIT_LIST_HEAD(&up->list);
-               i->head = &up->list;
-               spin_unlock_irq(&i->lock);
-
-               ret = request_irq(up->port.irq, m32r_sio_interrupt,
-                                 irq_flags, "SIO0-RX", i);
-               ret |= request_irq(up->port.irq + 1, m32r_sio_interrupt,
-                                 irq_flags, "SIO0-TX", i);
-               if (ret < 0)
-                       serial_do_unlink(i, up);
-       }
-
-       return ret;
-}
-
-static void serial_unlink_irq_chain(struct uart_sio_port *up)
-{
-       struct irq_info *i = irq_lists + up->port.irq;
-
-       BUG_ON(i->head == NULL);
-
-       if (list_empty(i->head)) {
-               free_irq(up->port.irq, i);
-               free_irq(up->port.irq + 1, i);
-       }
-
-       serial_do_unlink(i, up);
-}
-
-/*
- * This function is used to handle ports that do not have an interrupt.
- */
-static void m32r_sio_timeout(unsigned long data)
-{
-       struct uart_sio_port *up = (struct uart_sio_port *)data;
-       unsigned int timeout;
-       unsigned int sts;
-
-       sts = sio_in(up, SIOSTS);
-       if (sts & 0x5) {
-               spin_lock(&up->port.lock);
-               m32r_sio_handle_port(up, sts);
-               spin_unlock(&up->port.lock);
-       }
-
-       timeout = up->port.timeout;
-       timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
-       mod_timer(&up->timer, jiffies + timeout);
-}
-
-static unsigned int m32r_sio_tx_empty(struct uart_port *port)
-{
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-       unsigned long flags;
-       unsigned int ret;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       return ret;
-}
-
-static unsigned int m32r_sio_get_mctrl(struct uart_port *port)
-{
-       return 0;
-}
-
-static void m32r_sio_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-
-}
-
-static void m32r_sio_break_ctl(struct uart_port *port, int break_state)
-{
-
-}
-
-static int m32r_sio_startup(struct uart_port *port)
-{
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-       int retval;
-
-       sio_init();
-
-       /*
-        * If the "interrupt" for this port doesn't correspond with any
-        * hardware interrupt, we use a timer-based system.  The original
-        * driver used to do this with IRQ0.
-        */
-       if (!is_real_interrupt(up->port.irq)) {
-               unsigned int timeout = up->port.timeout;
-
-               timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
-
-               up->timer.data = (unsigned long)up;
-               mod_timer(&up->timer, jiffies + timeout);
-       } else {
-               retval = serial_link_irq_chain(up);
-               if (retval)
-                       return retval;
-       }
-
-       /*
-        * Finally, enable interrupts.  Note: Modem status interrupts
-        * are set via set_termios(), which will be occurring imminently
-        * anyway, so we don't enable them here.
-        * - M32R_SIO: 0x0c
-        * - M32R_PLDSIO: 0x04
-        */
-       up->ier = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
-       sio_out(up, SIOTRCR, up->ier);
-
-       /*
-        * And clear the interrupt registers again for luck.
-        */
-       sio_reset();
-
-       return 0;
-}
-
-static void m32r_sio_shutdown(struct uart_port *port)
-{
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-
-       /*
-        * Disable interrupts from this port
-        */
-       up->ier = 0;
-       sio_out(up, SIOTRCR, 0);
-
-       /*
-        * Disable break condition and FIFOs
-        */
-
-       sio_init();
-
-       if (!is_real_interrupt(up->port.irq))
-               del_timer_sync(&up->timer);
-       else
-               serial_unlink_irq_chain(up);
-}
-
-static unsigned int m32r_sio_get_divisor(struct uart_port *port,
-       unsigned int baud)
-{
-       return uart_get_divisor(port, baud);
-}
-
-static void m32r_sio_set_termios(struct uart_port *port,
-       struct ktermios *termios, struct ktermios *old)
-{
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-       unsigned char cval = 0;
-       unsigned long flags;
-       unsigned int baud, quot;
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               cval = UART_LCR_WLEN5;
-               break;
-       case CS6:
-               cval = UART_LCR_WLEN6;
-               break;
-       case CS7:
-               cval = UART_LCR_WLEN7;
-               break;
-       default:
-       case CS8:
-               cval = UART_LCR_WLEN8;
-               break;
-       }
-
-       if (termios->c_cflag & CSTOPB)
-               cval |= UART_LCR_STOP;
-       if (termios->c_cflag & PARENB)
-               cval |= UART_LCR_PARITY;
-       if (!(termios->c_cflag & PARODD))
-               cval |= UART_LCR_EPAR;
-#ifdef CMSPAR
-       if (termios->c_cflag & CMSPAR)
-               cval |= UART_LCR_SPAR;
-#endif
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-#ifdef CONFIG_SERIAL_M32R_PLDSIO
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/4);
-#else
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
-#endif
-       quot = m32r_sio_get_divisor(port, baud);
-
-       /*
-        * Ok, we're now changing the port state.  Do it with
-        * interrupts disabled.
-        */
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       sio_set_baud_rate(baud);
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
-       if (termios->c_iflag & INPCK)
-               up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               up->port.read_status_mask |= UART_LSR_BI;
-
-       /*
-        * Characteres to ignore
-        */
-       up->port.ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
-       if (termios->c_iflag & IGNBRK) {
-               up->port.ignore_status_mask |= UART_LSR_BI;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       up->port.ignore_status_mask |= UART_LSR_OE;
-       }
-
-       /*
-        * ignore all characters if CREAD is not set
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               up->port.ignore_status_mask |= UART_LSR_DR;
-
-       /*
-        * CTS flow control flag and modem status interrupts
-        */
-       up->ier &= ~UART_IER_MSI;
-       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
-               up->ier |= UART_IER_MSI;
-
-       serial_out(up, UART_IER, up->ier);
-
-       up->lcr = cval;                                 /* Save LCR */
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static void m32r_sio_pm(struct uart_port *port, unsigned int state,
-       unsigned int oldstate)
-{
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-
-       if (up->pm)
-               up->pm(port, state, oldstate);
-}
-
-/*
- * Resource handling.  This is complicated by the fact that resources
- * depend on the port type.  Maybe we should be claiming the standard
- * 8250 ports, and then trying to get other resources as necessary?
- */
-static int
-m32r_sio_request_std_resource(struct uart_sio_port *up, struct resource **res)
-{
-       unsigned int size = 8 << up->port.regshift;
-#ifndef CONFIG_SERIAL_M32R_PLDSIO
-       unsigned long start;
-#endif
-       int ret = 0;
-
-       switch (up->port.iotype) {
-       case UPIO_MEM:
-               if (up->port.mapbase) {
-#ifdef CONFIG_SERIAL_M32R_PLDSIO
-                       *res = request_mem_region(up->port.mapbase, size, "serial");
-#else
-                       start = up->port.mapbase;
-                       *res = request_mem_region(start, size, "serial");
-#endif
-                       if (!*res)
-                               ret = -EBUSY;
-               }
-               break;
-
-       case UPIO_PORT:
-               *res = request_region(up->port.iobase, size, "serial");
-               if (!*res)
-                       ret = -EBUSY;
-               break;
-       }
-       return ret;
-}
-
-static void m32r_sio_release_port(struct uart_port *port)
-{
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-       unsigned long start, offset = 0, size = 0;
-
-       size <<= up->port.regshift;
-
-       switch (up->port.iotype) {
-       case UPIO_MEM:
-               if (up->port.mapbase) {
-                       /*
-                        * Unmap the area.
-                        */
-                       iounmap(up->port.membase);
-                       up->port.membase = NULL;
-
-                       start = up->port.mapbase;
-
-                       if (size)
-                               release_mem_region(start + offset, size);
-                       release_mem_region(start, 8 << up->port.regshift);
-               }
-               break;
-
-       case UPIO_PORT:
-               start = up->port.iobase;
-
-               if (size)
-                       release_region(start + offset, size);
-               release_region(start + offset, 8 << up->port.regshift);
-               break;
-
-       default:
-               break;
-       }
-}
-
-static int m32r_sio_request_port(struct uart_port *port)
-{
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-       struct resource *res = NULL;
-       int ret = 0;
-
-       ret = m32r_sio_request_std_resource(up, &res);
-
-       /*
-        * If we have a mapbase, then request that as well.
-        */
-       if (ret == 0 && up->port.flags & UPF_IOREMAP) {
-               int size = res->end - res->start + 1;
-
-               up->port.membase = ioremap(up->port.mapbase, size);
-               if (!up->port.membase)
-                       ret = -ENOMEM;
-       }
-
-       if (ret < 0) {
-               if (res)
-                       release_resource(res);
-       }
-
-       return ret;
-}
-
-static void m32r_sio_config_port(struct uart_port *port, int flags)
-{
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       up->port.type = (PORT_M32R_SIO - PORT_M32R_BASE + 1);
-       up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size;
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static int
-m32r_sio_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       if (ser->irq >= nr_irqs || ser->irq < 0 ||
-           ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||
-           ser->type >= ARRAY_SIZE(uart_config))
-               return -EINVAL;
-       return 0;
-}
-
-static const char *
-m32r_sio_type(struct uart_port *port)
-{
-       int type = port->type;
-
-       if (type >= ARRAY_SIZE(uart_config))
-               type = 0;
-       return uart_config[type].name;
-}
-
-static struct uart_ops m32r_sio_pops = {
-       .tx_empty       = m32r_sio_tx_empty,
-       .set_mctrl      = m32r_sio_set_mctrl,
-       .get_mctrl      = m32r_sio_get_mctrl,
-       .stop_tx        = m32r_sio_stop_tx,
-       .start_tx       = m32r_sio_start_tx,
-       .stop_rx        = m32r_sio_stop_rx,
-       .enable_ms      = m32r_sio_enable_ms,
-       .break_ctl      = m32r_sio_break_ctl,
-       .startup        = m32r_sio_startup,
-       .shutdown       = m32r_sio_shutdown,
-       .set_termios    = m32r_sio_set_termios,
-       .pm             = m32r_sio_pm,
-       .type           = m32r_sio_type,
-       .release_port   = m32r_sio_release_port,
-       .request_port   = m32r_sio_request_port,
-       .config_port    = m32r_sio_config_port,
-       .verify_port    = m32r_sio_verify_port,
-};
-
-static struct uart_sio_port m32r_sio_ports[UART_NR];
-
-static void __init m32r_sio_init_ports(void)
-{
-       struct uart_sio_port *up;
-       static int first = 1;
-       int i;
-
-       if (!first)
-               return;
-       first = 0;
-
-       for (i = 0, up = m32r_sio_ports; i < ARRAY_SIZE(old_serial_port);
-            i++, up++) {
-               up->port.iobase   = old_serial_port[i].port;
-               up->port.irq      = irq_canonicalize(old_serial_port[i].irq);
-               up->port.uartclk  = old_serial_port[i].baud_base * 16;
-               up->port.flags    = old_serial_port[i].flags;
-               up->port.membase  = old_serial_port[i].iomem_base;
-               up->port.iotype   = old_serial_port[i].io_type;
-               up->port.regshift = old_serial_port[i].iomem_reg_shift;
-               up->port.ops      = &m32r_sio_pops;
-       }
-}
-
-static void __init m32r_sio_register_ports(struct uart_driver *drv)
-{
-       int i;
-
-       m32r_sio_init_ports();
-
-       for (i = 0; i < UART_NR; i++) {
-               struct uart_sio_port *up = &m32r_sio_ports[i];
-
-               up->port.line = i;
-               up->port.ops = &m32r_sio_pops;
-               init_timer(&up->timer);
-               up->timer.function = m32r_sio_timeout;
-
-               /*
-                * ALPHA_KLUDGE_MCR needs to be killed.
-                */
-               up->mcr_mask = ~ALPHA_KLUDGE_MCR;
-               up->mcr_force = ALPHA_KLUDGE_MCR;
-
-               uart_add_one_port(drv, &up->port);
-       }
-}
-
-#ifdef CONFIG_SERIAL_M32R_SIO_CONSOLE
-
-/*
- *     Wait for transmitter & holding register to empty
- */
-static inline void wait_for_xmitr(struct uart_sio_port *up)
-{
-       unsigned int status, tmout = 10000;
-
-       /* Wait up to 10ms for the character(s) to be sent. */
-       do {
-               status = sio_in(up, SIOSTS);
-
-               if (--tmout == 0)
-                       break;
-               udelay(1);
-       } while ((status & UART_EMPTY) != UART_EMPTY);
-
-       /* Wait up to 1s for flow control if necessary */
-       if (up->port.flags & UPF_CONS_FLOW) {
-               tmout = 1000000;
-               while (--tmout)
-                       udelay(1);
-       }
-}
-
-static void m32r_sio_console_putchar(struct uart_port *port, int ch)
-{
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-
-       wait_for_xmitr(up);
-       sio_out(up, SIOTXB, ch);
-}
-
-/*
- *     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.
- */
-static void m32r_sio_console_write(struct console *co, const char *s,
-       unsigned int count)
-{
-       struct uart_sio_port *up = &m32r_sio_ports[co->index];
-       unsigned int ier;
-
-       /*
-        *      First save the UER then disable the interrupts
-        */
-       ier = sio_in(up, SIOTRCR);
-       sio_out(up, SIOTRCR, 0);
-
-       uart_console_write(&up->port, s, count, m32r_sio_console_putchar);
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore the IER
-        */
-       wait_for_xmitr(up);
-       sio_out(up, SIOTRCR, ier);
-}
-
-static int __init m32r_sio_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port;
-       int baud = 9600;
-       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.
-        */
-       if (co->index >= UART_NR)
-               co->index = 0;
-       port = &m32r_sio_ports[co->index].port;
-
-       /*
-        * Temporary fix.
-        */
-       spin_lock_init(&port->lock);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver m32r_sio_reg;
-static struct console m32r_sio_console = {
-       .name           = "ttyS",
-       .write          = m32r_sio_console_write,
-       .device         = uart_console_device,
-       .setup          = m32r_sio_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &m32r_sio_reg,
-};
-
-static int __init m32r_sio_console_init(void)
-{
-       sio_reset();
-       sio_init();
-       m32r_sio_init_ports();
-       register_console(&m32r_sio_console);
-       return 0;
-}
-console_initcall(m32r_sio_console_init);
-
-#define M32R_SIO_CONSOLE       &m32r_sio_console
-#else
-#define M32R_SIO_CONSOLE       NULL
-#endif
-
-static struct uart_driver m32r_sio_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "sio",
-       .dev_name               = "ttyS",
-       .major                  = TTY_MAJOR,
-       .minor                  = 64,
-       .nr                     = UART_NR,
-       .cons                   = M32R_SIO_CONSOLE,
-};
-
-/**
- *     m32r_sio_suspend_port - suspend one serial port
- *     @line: serial line number
- *
- *     Suspend one serial port.
- */
-void m32r_sio_suspend_port(int line)
-{
-       uart_suspend_port(&m32r_sio_reg, &m32r_sio_ports[line].port);
-}
-
-/**
- *     m32r_sio_resume_port - resume one serial port
- *     @line: serial line number
- *
- *     Resume one serial port.
- */
-void m32r_sio_resume_port(int line)
-{
-       uart_resume_port(&m32r_sio_reg, &m32r_sio_ports[line].port);
-}
-
-static int __init m32r_sio_init(void)
-{
-       int ret, i;
-
-       printk(KERN_INFO "Serial: M32R SIO driver\n");
-
-       for (i = 0; i < nr_irqs; i++)
-               spin_lock_init(&irq_lists[i].lock);
-
-       ret = uart_register_driver(&m32r_sio_reg);
-       if (ret >= 0)
-               m32r_sio_register_ports(&m32r_sio_reg);
-
-       return ret;
-}
-
-static void __exit m32r_sio_exit(void)
-{
-       int i;
-
-       for (i = 0; i < UART_NR; i++)
-               uart_remove_one_port(&m32r_sio_reg, &m32r_sio_ports[i].port);
-
-       uart_unregister_driver(&m32r_sio_reg);
-}
-
-module_init(m32r_sio_init);
-module_exit(m32r_sio_exit);
-
-EXPORT_SYMBOL(m32r_sio_suspend_port);
-EXPORT_SYMBOL(m32r_sio_resume_port);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Generic M32R SIO serial driver");
diff --git a/drivers/serial/m32r_sio.h b/drivers/serial/m32r_sio.h
deleted file mode 100644 (file)
index e9b7e11..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *  m32r_sio.h
- *
- *  Driver for M32R serial ports
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *  Based on drivers/serial/8250.h.
- *
- *  Copyright (C) 2001  Russell King.
- *  Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
- *
- * 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.
- */
-
-
-struct m32r_sio_probe {
-       struct module   *owner;
-       int             (*pci_init_one)(struct pci_dev *dev);
-       void            (*pci_remove_one)(struct pci_dev *dev);
-       void            (*pnp_init)(void);
-};
-
-int m32r_sio_register_probe(struct m32r_sio_probe *probe);
-void m32r_sio_unregister_probe(struct m32r_sio_probe *probe);
-void m32r_sio_get_irq_map(unsigned int *map);
-void m32r_sio_suspend_port(int line);
-void m32r_sio_resume_port(int line);
-
-struct old_serial_port {
-       unsigned int uart;
-       unsigned int baud_base;
-       unsigned int port;
-       unsigned int irq;
-       unsigned int flags;
-       unsigned char io_type;
-       unsigned char __iomem *iomem_base;
-       unsigned short iomem_reg_shift;
-};
-
-#define _INLINE_ inline
-
-#define PROBE_RSA      (1 << 0)
-#define PROBE_ANY      (~0)
-
-#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
diff --git a/drivers/serial/m32r_sio_reg.h b/drivers/serial/m32r_sio_reg.h
deleted file mode 100644 (file)
index 4671473..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * m32r_sio_reg.h
- *
- * Copyright (C) 1992, 1994 by Theodore Ts'o.
- * Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
- *
- * Redistribution of this file is permitted under the terms of the GNU
- * Public License (GPL)
- *
- * These are the UART port assignments, expressed as offsets from the base
- * register.  These assignments should hold for any serial port based on
- * a 8250, 16450, or 16550(A).
- */
-
-#ifndef _M32R_SIO_REG_H
-#define _M32R_SIO_REG_H
-
-
-#ifdef CONFIG_SERIAL_M32R_PLDSIO
-
-#define SIOCR          0x000
-#define SIOMOD0                0x002
-#define SIOMOD1                0x004
-#define SIOSTS         0x006
-#define SIOTRCR                0x008
-#define SIOBAUR                0x00a
-// #define SIORBAUR    0x018
-#define SIOTXB         0x00c
-#define SIORXB         0x00e
-
-#define UART_RX                ((unsigned long) PLD_ESIO0RXB)
-                               /* In:  Receive buffer (DLAB=0) */
-#define UART_TX                ((unsigned long) PLD_ESIO0TXB)
-                               /* Out: Transmit buffer (DLAB=0) */
-#define UART_DLL       0       /* Out: Divisor Latch Low (DLAB=1) */
-#define UART_TRG       0       /* (LCR=BF) FCTR bit 7 selects Rx or Tx
-                                * In: Fifo count
-                                * Out: Fifo custom trigger levels
-                                * XR16C85x only */
-
-#define UART_DLM       0       /* Out: Divisor Latch High (DLAB=1) */
-#define UART_IER       ((unsigned long) PLD_ESIO0INTCR)
-                               /* Out: Interrupt Enable Register */
-#define UART_FCTR      0       /* (LCR=BF) Feature Control Register
-                                * XR16C85x only */
-
-#define UART_IIR       0       /* In:  Interrupt ID Register */
-#define UART_FCR       0       /* Out: FIFO Control Register */
-#define UART_EFR       0       /* I/O: Extended Features Register */
-                               /* (DLAB=1, 16C660 only) */
-
-#define UART_LCR       0       /* Out: Line Control Register */
-#define UART_MCR       0       /* Out: Modem Control Register */
-#define UART_LSR       ((unsigned long) PLD_ESIO0STS)
-                               /* In:  Line Status Register */
-#define UART_MSR       0       /* In:  Modem Status Register */
-#define UART_SCR       0       /* I/O: Scratch Register */
-#define UART_EMSR      0       /* (LCR=BF) Extended Mode Select Register
-                                * FCTR bit 6 selects SCR or EMSR
-                                * XR16c85x only */
-
-#else /* not CONFIG_SERIAL_M32R_PLDSIO */
-
-#define SIOCR          0x000
-#define SIOMOD0                0x004
-#define SIOMOD1                0x008
-#define SIOSTS         0x00c
-#define SIOTRCR                0x010
-#define SIOBAUR                0x014
-#define SIORBAUR       0x018
-#define SIOTXB         0x01c
-#define SIORXB         0x020
-
-#define UART_RX                M32R_SIO0_RXB_PORTL     /* In:  Receive buffer (DLAB=0) */
-#define UART_TX                M32R_SIO0_TXB_PORTL     /* Out: Transmit buffer (DLAB=0) */
-#define UART_DLL       0       /* Out: Divisor Latch Low (DLAB=1) */
-#define UART_TRG       0       /* (LCR=BF) FCTR bit 7 selects Rx or Tx
-                                * In: Fifo count
-                                * Out: Fifo custom trigger levels
-                                * XR16C85x only */
-
-#define UART_DLM       0       /* Out: Divisor Latch High (DLAB=1) */
-#define UART_IER       M32R_SIO0_TRCR_PORTL    /* Out: Interrupt Enable Register */
-#define UART_FCTR      0       /* (LCR=BF) Feature Control Register
-                                * XR16C85x only */
-
-#define UART_IIR       0       /* In:  Interrupt ID Register */
-#define UART_FCR       0       /* Out: FIFO Control Register */
-#define UART_EFR       0       /* I/O: Extended Features Register */
-                               /* (DLAB=1, 16C660 only) */
-
-#define UART_LCR       0       /* Out: Line Control Register */
-#define UART_MCR       0       /* Out: Modem Control Register */
-#define UART_LSR       M32R_SIO0_STS_PORTL     /* In:  Line Status Register */
-#define UART_MSR       0       /* In:  Modem Status Register */
-#define UART_SCR       0       /* I/O: Scratch Register */
-#define UART_EMSR      0       /* (LCR=BF) Extended Mode Select Register
-                                * FCTR bit 6 selects SCR or EMSR
-                                * XR16c85x only */
-
-#endif /* CONFIG_SERIAL_M32R_PLDSIO */
-
-#define UART_EMPTY     (UART_LSR_TEMT | UART_LSR_THRE)
-
-/*
- * These are the definitions for the Line Control Register
- *
- * Note: if the word length is 5 bits (UART_LCR_WLEN5), then setting
- * UART_LCR_STOP will select 1.5 stop bits, not 2 stop bits.
- */
-#define UART_LCR_DLAB  0x80    /* Divisor latch access bit */
-#define UART_LCR_SBC   0x40    /* Set break control */
-#define UART_LCR_SPAR  0x20    /* Stick parity (?) */
-#define UART_LCR_EPAR  0x10    /* Even parity select */
-#define UART_LCR_PARITY        0x08    /* Parity Enable */
-#define UART_LCR_STOP  0x04    /* Stop bits: 0=1 stop bit, 1= 2 stop bits */
-#define UART_LCR_WLEN5  0x00   /* Wordlength: 5 bits */
-#define UART_LCR_WLEN6  0x01   /* Wordlength: 6 bits */
-#define UART_LCR_WLEN7  0x02   /* Wordlength: 7 bits */
-#define UART_LCR_WLEN8  0x03   /* Wordlength: 8 bits */
-
-/*
- * These are the definitions for the Line Status Register
- */
-#define UART_LSR_TEMT  0x02    /* Transmitter empty */
-#define UART_LSR_THRE  0x01    /* Transmit-hold-register empty */
-#define UART_LSR_BI    0x00    /* Break interrupt indicator */
-#define UART_LSR_FE    0x80    /* Frame error indicator */
-#define UART_LSR_PE    0x40    /* Parity error indicator */
-#define UART_LSR_OE    0x20    /* Overrun error indicator */
-#define UART_LSR_DR    0x04    /* Receiver data ready */
-
-/*
- * These are the definitions for the Interrupt Identification Register
- */
-#define UART_IIR_NO_INT        0x01    /* No interrupts pending */
-#define UART_IIR_ID    0x06    /* Mask for the interrupt ID */
-
-#define UART_IIR_MSI   0x00    /* Modem status interrupt */
-#define UART_IIR_THRI  0x02    /* Transmitter holding register empty */
-#define UART_IIR_RDI   0x04    /* Receiver data interrupt */
-#define UART_IIR_RLSI  0x06    /* Receiver line status interrupt */
-
-/*
- * These are the definitions for the Interrupt Enable Register
- */
-#define UART_IER_MSI   0x00    /* Enable Modem status interrupt */
-#define UART_IER_RLSI  0x08    /* Enable receiver line status interrupt */
-#define UART_IER_THRI  0x03    /* Enable Transmitter holding register int. */
-#define UART_IER_RDI   0x04    /* Enable receiver data interrupt */
-
-#endif /* _M32R_SIO_REG_H */
diff --git a/drivers/serial/max3100.c b/drivers/serial/max3100.c
deleted file mode 100644 (file)
index beb1afa..0000000
+++ /dev/null
@@ -1,926 +0,0 @@
-/*
- *
- *  Copyright (C) 2008 Christian Pellegrin <chripell@evolware.org>
- *
- * 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.
- *
- *
- * Notes: the MAX3100 doesn't provide an interrupt on CTS so we have
- * to use polling for flow control. TX empty IRQ is unusable, since
- * writing conf clears FIFO buffer and we cannot have this interrupt
- * always asking us for attention.
- *
- * Example platform data:
-
- static struct plat_max3100 max3100_plat_data = {
- .loopback = 0,
- .crystal = 0,
- .poll_time = 100,
- };
-
- static struct spi_board_info spi_board_info[] = {
- {
- .modalias     = "max3100",
- .platform_data        = &max3100_plat_data,
- .irq          = IRQ_EINT12,
- .max_speed_hz = 5*1000*1000,
- .chip_select  = 0,
- },
- };
-
- * The initial minor number is 209 in the low-density serial port:
- * mknod /dev/ttyMAX0 c 204 209
- */
-
-#define MAX3100_MAJOR 204
-#define MAX3100_MINOR 209
-/* 4 MAX3100s should be enough for everyone */
-#define MAX_MAX3100 4
-
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/spi/spi.h>
-#include <linux/freezer.h>
-
-#include <linux/serial_max3100.h>
-
-#define MAX3100_C    (1<<14)
-#define MAX3100_D    (0<<14)
-#define MAX3100_W    (1<<15)
-#define MAX3100_RX   (0<<15)
-
-#define MAX3100_WC   (MAX3100_W  | MAX3100_C)
-#define MAX3100_RC   (MAX3100_RX | MAX3100_C)
-#define MAX3100_WD   (MAX3100_W  | MAX3100_D)
-#define MAX3100_RD   (MAX3100_RX | MAX3100_D)
-#define MAX3100_CMD  (3 << 14)
-
-#define MAX3100_T    (1<<14)
-#define MAX3100_R    (1<<15)
-
-#define MAX3100_FEN  (1<<13)
-#define MAX3100_SHDN (1<<12)
-#define MAX3100_TM   (1<<11)
-#define MAX3100_RM   (1<<10)
-#define MAX3100_PM   (1<<9)
-#define MAX3100_RAM  (1<<8)
-#define MAX3100_IR   (1<<7)
-#define MAX3100_ST   (1<<6)
-#define MAX3100_PE   (1<<5)
-#define MAX3100_L    (1<<4)
-#define MAX3100_BAUD (0xf)
-
-#define MAX3100_TE   (1<<10)
-#define MAX3100_RAFE (1<<10)
-#define MAX3100_RTS  (1<<9)
-#define MAX3100_CTS  (1<<9)
-#define MAX3100_PT   (1<<8)
-#define MAX3100_DATA (0xff)
-
-#define MAX3100_RT   (MAX3100_R | MAX3100_T)
-#define MAX3100_RTC  (MAX3100_RT | MAX3100_CTS | MAX3100_RAFE)
-
-/* the following simulate a status reg for ignore_status_mask */
-#define MAX3100_STATUS_PE 1
-#define MAX3100_STATUS_FE 2
-#define MAX3100_STATUS_OE 4
-
-struct max3100_port {
-       struct uart_port port;
-       struct spi_device *spi;
-
-       int cts;                /* last CTS received for flow ctrl */
-       int tx_empty;           /* last TX empty bit */
-
-       spinlock_t conf_lock;   /* shared data */
-       int conf_commit;        /* need to make changes */
-       int conf;               /* configuration for the MAX31000
-                                * (bits 0-7, bits 8-11 are irqs) */
-       int rts_commit;         /* need to change rts */
-       int rts;                /* rts status */
-       int baud;               /* current baud rate */
-
-       int parity;             /* keeps track if we should send parity */
-#define MAX3100_PARITY_ON 1
-#define MAX3100_PARITY_ODD 2
-#define MAX3100_7BIT 4
-       int rx_enabled;         /* if we should rx chars */
-
-       int irq;                /* irq assigned to the max3100 */
-
-       int minor;              /* minor number */
-       int crystal;            /* 1 if 3.6864Mhz crystal 0 for 1.8432 */
-       int loopback;           /* 1 if we are in loopback mode */
-
-       /* for handling irqs: need workqueue since we do spi_sync */
-       struct workqueue_struct *workqueue;
-       struct work_struct work;
-       /* set to 1 to make the workhandler exit as soon as possible */
-       int  force_end_work;
-       /* need to know we are suspending to avoid deadlock on workqueue */
-       int suspending;
-
-       /* hook for suspending MAX3100 via dedicated pin */
-       void (*max3100_hw_suspend) (int suspend);
-
-       /* poll time (in ms) for ctrl lines */
-       int poll_time;
-       /* and its timer */
-       struct timer_list       timer;
-};
-
-static struct max3100_port *max3100s[MAX_MAX3100]; /* the chips */
-static DEFINE_MUTEX(max3100s_lock);               /* race on probe */
-
-static int max3100_do_parity(struct max3100_port *s, u16 c)
-{
-       int parity;
-
-       if (s->parity & MAX3100_PARITY_ODD)
-               parity = 1;
-       else
-               parity = 0;
-
-       if (s->parity & MAX3100_7BIT)
-               c &= 0x7f;
-       else
-               c &= 0xff;
-
-       parity = parity ^ (hweight8(c) & 1);
-       return parity;
-}
-
-static int max3100_check_parity(struct max3100_port *s, u16 c)
-{
-       return max3100_do_parity(s, c) == ((c >> 8) & 1);
-}
-
-static void max3100_calc_parity(struct max3100_port *s, u16 *c)
-{
-       if (s->parity & MAX3100_7BIT)
-               *c &= 0x7f;
-       else
-               *c &= 0xff;
-
-       if (s->parity & MAX3100_PARITY_ON)
-               *c |= max3100_do_parity(s, *c) << 8;
-}
-
-static void max3100_work(struct work_struct *w);
-
-static void max3100_dowork(struct max3100_port *s)
-{
-       if (!s->force_end_work && !work_pending(&s->work) &&
-           !freezing(current) && !s->suspending)
-               queue_work(s->workqueue, &s->work);
-}
-
-static void max3100_timeout(unsigned long data)
-{
-       struct max3100_port *s = (struct max3100_port *)data;
-
-       if (s->port.state) {
-               max3100_dowork(s);
-               mod_timer(&s->timer, jiffies + s->poll_time);
-       }
-}
-
-static int max3100_sr(struct max3100_port *s, u16 tx, u16 *rx)
-{
-       struct spi_message message;
-       u16 etx, erx;
-       int status;
-       struct spi_transfer tran = {
-               .tx_buf = &etx,
-               .rx_buf = &erx,
-               .len = 2,
-       };
-
-       etx = cpu_to_be16(tx);
-       spi_message_init(&message);
-       spi_message_add_tail(&tran, &message);
-       status = spi_sync(s->spi, &message);
-       if (status) {
-               dev_warn(&s->spi->dev, "error while calling spi_sync\n");
-               return -EIO;
-       }
-       *rx = be16_to_cpu(erx);
-       s->tx_empty = (*rx & MAX3100_T) > 0;
-       dev_dbg(&s->spi->dev, "%04x - %04x\n", tx, *rx);
-       return 0;
-}
-
-static int max3100_handlerx(struct max3100_port *s, u16 rx)
-{
-       unsigned int ch, flg, status = 0;
-       int ret = 0, cts;
-
-       if (rx & MAX3100_R && s->rx_enabled) {
-               dev_dbg(&s->spi->dev, "%s\n", __func__);
-               ch = rx & (s->parity & MAX3100_7BIT ? 0x7f : 0xff);
-               if (rx & MAX3100_RAFE) {
-                       s->port.icount.frame++;
-                       flg = TTY_FRAME;
-                       status |= MAX3100_STATUS_FE;
-               } else {
-                       if (s->parity & MAX3100_PARITY_ON) {
-                               if (max3100_check_parity(s, rx)) {
-                                       s->port.icount.rx++;
-                                       flg = TTY_NORMAL;
-                               } else {
-                                       s->port.icount.parity++;
-                                       flg = TTY_PARITY;
-                                       status |= MAX3100_STATUS_PE;
-                               }
-                       } else {
-                               s->port.icount.rx++;
-                               flg = TTY_NORMAL;
-                       }
-               }
-               uart_insert_char(&s->port, status, MAX3100_STATUS_OE, ch, flg);
-               ret = 1;
-       }
-
-       cts = (rx & MAX3100_CTS) > 0;
-       if (s->cts != cts) {
-               s->cts = cts;
-               uart_handle_cts_change(&s->port, cts ? TIOCM_CTS : 0);
-       }
-
-       return ret;
-}
-
-static void max3100_work(struct work_struct *w)
-{
-       struct max3100_port *s = container_of(w, struct max3100_port, work);
-       int rxchars;
-       u16 tx, rx;
-       int conf, cconf, rts, crts;
-       struct circ_buf *xmit = &s->port.state->xmit;
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       rxchars = 0;
-       do {
-               spin_lock(&s->conf_lock);
-               conf = s->conf;
-               cconf = s->conf_commit;
-               s->conf_commit = 0;
-               rts = s->rts;
-               crts = s->rts_commit;
-               s->rts_commit = 0;
-               spin_unlock(&s->conf_lock);
-               if (cconf)
-                       max3100_sr(s, MAX3100_WC | conf, &rx);
-               if (crts) {
-                       max3100_sr(s, MAX3100_WD | MAX3100_TE |
-                                  (s->rts ? MAX3100_RTS : 0), &rx);
-                       rxchars += max3100_handlerx(s, rx);
-               }
-
-               max3100_sr(s, MAX3100_RD, &rx);
-               rxchars += max3100_handlerx(s, rx);
-
-               if (rx & MAX3100_T) {
-                       tx = 0xffff;
-                       if (s->port.x_char) {
-                               tx = s->port.x_char;
-                               s->port.icount.tx++;
-                               s->port.x_char = 0;
-                       } else if (!uart_circ_empty(xmit) &&
-                                  !uart_tx_stopped(&s->port)) {
-                               tx = xmit->buf[xmit->tail];
-                               xmit->tail = (xmit->tail + 1) &
-                                       (UART_XMIT_SIZE - 1);
-                               s->port.icount.tx++;
-                       }
-                       if (tx != 0xffff) {
-                               max3100_calc_parity(s, &tx);
-                               tx |= MAX3100_WD | (s->rts ? MAX3100_RTS : 0);
-                               max3100_sr(s, tx, &rx);
-                               rxchars += max3100_handlerx(s, rx);
-                       }
-               }
-
-               if (rxchars > 16 && s->port.state->port.tty != NULL) {
-                       tty_flip_buffer_push(s->port.state->port.tty);
-                       rxchars = 0;
-               }
-               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-                       uart_write_wakeup(&s->port);
-
-       } while (!s->force_end_work &&
-                !freezing(current) &&
-                ((rx & MAX3100_R) ||
-                 (!uart_circ_empty(xmit) &&
-                  !uart_tx_stopped(&s->port))));
-
-       if (rxchars > 0 && s->port.state->port.tty != NULL)
-               tty_flip_buffer_push(s->port.state->port.tty);
-}
-
-static irqreturn_t max3100_irq(int irqno, void *dev_id)
-{
-       struct max3100_port *s = dev_id;
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       max3100_dowork(s);
-       return IRQ_HANDLED;
-}
-
-static void max3100_enable_ms(struct uart_port *port)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-
-       if (s->poll_time > 0)
-               mod_timer(&s->timer, jiffies);
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-}
-
-static void max3100_start_tx(struct uart_port *port)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       max3100_dowork(s);
-}
-
-static void max3100_stop_rx(struct uart_port *port)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       s->rx_enabled = 0;
-       spin_lock(&s->conf_lock);
-       s->conf &= ~MAX3100_RM;
-       s->conf_commit = 1;
-       spin_unlock(&s->conf_lock);
-       max3100_dowork(s);
-}
-
-static unsigned int max3100_tx_empty(struct uart_port *port)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       /* may not be truly up-to-date */
-       max3100_dowork(s);
-       return s->tx_empty;
-}
-
-static unsigned int max3100_get_mctrl(struct uart_port *port)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       /* may not be truly up-to-date */
-       max3100_dowork(s);
-       /* always assert DCD and DSR since these lines are not wired */
-       return (s->cts ? TIOCM_CTS : 0) | TIOCM_DSR | TIOCM_CAR;
-}
-
-static void max3100_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-       int rts;
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       rts = (mctrl & TIOCM_RTS) > 0;
-
-       spin_lock(&s->conf_lock);
-       if (s->rts != rts) {
-               s->rts = rts;
-               s->rts_commit = 1;
-               max3100_dowork(s);
-       }
-       spin_unlock(&s->conf_lock);
-}
-
-static void
-max3100_set_termios(struct uart_port *port, struct ktermios *termios,
-                   struct ktermios *old)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-       int baud = 0;
-       unsigned cflag;
-       u32 param_new, param_mask, parity = 0;
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       cflag = termios->c_cflag;
-       param_new = 0;
-       param_mask = 0;
-
-       baud = tty_termios_baud_rate(termios);
-       param_new = s->conf & MAX3100_BAUD;
-       switch (baud) {
-       case 300:
-               if (s->crystal)
-                       baud = s->baud;
-               else
-                       param_new = 15;
-               break;
-       case 600:
-               param_new = 14 + s->crystal;
-               break;
-       case 1200:
-               param_new = 13 + s->crystal;
-               break;
-       case 2400:
-               param_new = 12 + s->crystal;
-               break;
-       case 4800:
-               param_new = 11 + s->crystal;
-               break;
-       case 9600:
-               param_new = 10 + s->crystal;
-               break;
-       case 19200:
-               param_new = 9 + s->crystal;
-               break;
-       case 38400:
-               param_new = 8 + s->crystal;
-               break;
-       case 57600:
-               param_new = 1 + s->crystal;
-               break;
-       case 115200:
-               param_new = 0 + s->crystal;
-               break;
-       case 230400:
-               if (s->crystal)
-                       param_new = 0;
-               else
-                       baud = s->baud;
-               break;
-       default:
-               baud = s->baud;
-       }
-       tty_termios_encode_baud_rate(termios, baud, baud);
-       s->baud = baud;
-       param_mask |= MAX3100_BAUD;
-
-       if ((cflag & CSIZE) == CS8) {
-               param_new &= ~MAX3100_L;
-               parity &= ~MAX3100_7BIT;
-       } else {
-               param_new |= MAX3100_L;
-               parity |= MAX3100_7BIT;
-               cflag = (cflag & ~CSIZE) | CS7;
-       }
-       param_mask |= MAX3100_L;
-
-       if (cflag & CSTOPB)
-               param_new |= MAX3100_ST;
-       else
-               param_new &= ~MAX3100_ST;
-       param_mask |= MAX3100_ST;
-
-       if (cflag & PARENB) {
-               param_new |= MAX3100_PE;
-               parity |= MAX3100_PARITY_ON;
-       } else {
-               param_new &= ~MAX3100_PE;
-               parity &= ~MAX3100_PARITY_ON;
-       }
-       param_mask |= MAX3100_PE;
-
-       if (cflag & PARODD)
-               parity |= MAX3100_PARITY_ODD;
-       else
-               parity &= ~MAX3100_PARITY_ODD;
-
-       /* mask termios capabilities we don't support */
-       cflag &= ~CMSPAR;
-       termios->c_cflag = cflag;
-
-       s->port.ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               s->port.ignore_status_mask |=
-                       MAX3100_STATUS_PE | MAX3100_STATUS_FE |
-                       MAX3100_STATUS_OE;
-
-       /* we are sending char from a workqueue so enable */
-       s->port.state->port.tty->low_latency = 1;
-
-       if (s->poll_time > 0)
-               del_timer_sync(&s->timer);
-
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       spin_lock(&s->conf_lock);
-       s->conf = (s->conf & ~param_mask) | (param_new & param_mask);
-       s->conf_commit = 1;
-       s->parity = parity;
-       spin_unlock(&s->conf_lock);
-       max3100_dowork(s);
-
-       if (UART_ENABLE_MS(&s->port, termios->c_cflag))
-               max3100_enable_ms(&s->port);
-}
-
-static void max3100_shutdown(struct uart_port *port)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       if (s->suspending)
-               return;
-
-       s->force_end_work = 1;
-
-       if (s->poll_time > 0)
-               del_timer_sync(&s->timer);
-
-       if (s->workqueue) {
-               flush_workqueue(s->workqueue);
-               destroy_workqueue(s->workqueue);
-               s->workqueue = NULL;
-       }
-       if (s->irq)
-               free_irq(s->irq, s);
-
-       /* set shutdown mode to save power */
-       if (s->max3100_hw_suspend)
-               s->max3100_hw_suspend(1);
-       else  {
-               u16 tx, rx;
-
-               tx = MAX3100_WC | MAX3100_SHDN;
-               max3100_sr(s, tx, &rx);
-       }
-}
-
-static int max3100_startup(struct uart_port *port)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-       char b[12];
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       s->conf = MAX3100_RM;
-       s->baud = s->crystal ? 230400 : 115200;
-       s->rx_enabled = 1;
-
-       if (s->suspending)
-               return 0;
-
-       s->force_end_work = 0;
-       s->parity = 0;
-       s->rts = 0;
-
-       sprintf(b, "max3100-%d", s->minor);
-       s->workqueue = create_freezeable_workqueue(b);
-       if (!s->workqueue) {
-               dev_warn(&s->spi->dev, "cannot create workqueue\n");
-               return -EBUSY;
-       }
-       INIT_WORK(&s->work, max3100_work);
-
-       if (request_irq(s->irq, max3100_irq,
-                       IRQF_TRIGGER_FALLING, "max3100", s) < 0) {
-               dev_warn(&s->spi->dev, "cannot allocate irq %d\n", s->irq);
-               s->irq = 0;
-               destroy_workqueue(s->workqueue);
-               s->workqueue = NULL;
-               return -EBUSY;
-       }
-
-       if (s->loopback) {
-               u16 tx, rx;
-               tx = 0x4001;
-               max3100_sr(s, tx, &rx);
-       }
-
-       if (s->max3100_hw_suspend)
-               s->max3100_hw_suspend(0);
-       s->conf_commit = 1;
-       max3100_dowork(s);
-       /* wait for clock to settle */
-       msleep(50);
-
-       max3100_enable_ms(&s->port);
-
-       return 0;
-}
-
-static const char *max3100_type(struct uart_port *port)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       return s->port.type == PORT_MAX3100 ? "MAX3100" : NULL;
-}
-
-static void max3100_release_port(struct uart_port *port)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-}
-
-static void max3100_config_port(struct uart_port *port, int flags)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       if (flags & UART_CONFIG_TYPE)
-               s->port.type = PORT_MAX3100;
-}
-
-static int max3100_verify_port(struct uart_port *port,
-                              struct serial_struct *ser)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-       int ret = -EINVAL;
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       if (ser->type == PORT_UNKNOWN || ser->type == PORT_MAX3100)
-               ret = 0;
-       return ret;
-}
-
-static void max3100_stop_tx(struct uart_port *port)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-}
-
-static int max3100_request_port(struct uart_port *port)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-       return 0;
-}
-
-static void max3100_break_ctl(struct uart_port *port, int break_state)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-}
-
-static struct uart_ops max3100_ops = {
-       .tx_empty       = max3100_tx_empty,
-       .set_mctrl      = max3100_set_mctrl,
-       .get_mctrl      = max3100_get_mctrl,
-       .stop_tx        = max3100_stop_tx,
-       .start_tx       = max3100_start_tx,
-       .stop_rx        = max3100_stop_rx,
-       .enable_ms      = max3100_enable_ms,
-       .break_ctl      = max3100_break_ctl,
-       .startup        = max3100_startup,
-       .shutdown       = max3100_shutdown,
-       .set_termios    = max3100_set_termios,
-       .type           = max3100_type,
-       .release_port   = max3100_release_port,
-       .request_port   = max3100_request_port,
-       .config_port    = max3100_config_port,
-       .verify_port    = max3100_verify_port,
-};
-
-static struct uart_driver max3100_uart_driver = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "ttyMAX",
-       .dev_name       = "ttyMAX",
-       .major          = MAX3100_MAJOR,
-       .minor          = MAX3100_MINOR,
-       .nr             = MAX_MAX3100,
-};
-static int uart_driver_registered;
-
-static int __devinit max3100_probe(struct spi_device *spi)
-{
-       int i, retval;
-       struct plat_max3100 *pdata;
-       u16 tx, rx;
-
-       mutex_lock(&max3100s_lock);
-
-       if (!uart_driver_registered) {
-               uart_driver_registered = 1;
-               retval = uart_register_driver(&max3100_uart_driver);
-               if (retval) {
-                       printk(KERN_ERR "Couldn't register max3100 uart driver\n");
-                       mutex_unlock(&max3100s_lock);
-                       return retval;
-               }
-       }
-
-       for (i = 0; i < MAX_MAX3100; i++)
-               if (!max3100s[i])
-                       break;
-       if (i == MAX_MAX3100) {
-               dev_warn(&spi->dev, "too many MAX3100 chips\n");
-               mutex_unlock(&max3100s_lock);
-               return -ENOMEM;
-       }
-
-       max3100s[i] = kzalloc(sizeof(struct max3100_port), GFP_KERNEL);
-       if (!max3100s[i]) {
-               dev_warn(&spi->dev,
-                        "kmalloc for max3100 structure %d failed!\n", i);
-               mutex_unlock(&max3100s_lock);
-               return -ENOMEM;
-       }
-       max3100s[i]->spi = spi;
-       max3100s[i]->irq = spi->irq;
-       spin_lock_init(&max3100s[i]->conf_lock);
-       dev_set_drvdata(&spi->dev, max3100s[i]);
-       pdata = spi->dev.platform_data;
-       max3100s[i]->crystal = pdata->crystal;
-       max3100s[i]->loopback = pdata->loopback;
-       max3100s[i]->poll_time = pdata->poll_time * HZ / 1000;
-       if (pdata->poll_time > 0 && max3100s[i]->poll_time == 0)
-               max3100s[i]->poll_time = 1;
-       max3100s[i]->max3100_hw_suspend = pdata->max3100_hw_suspend;
-       max3100s[i]->minor = i;
-       init_timer(&max3100s[i]->timer);
-       max3100s[i]->timer.function = max3100_timeout;
-       max3100s[i]->timer.data = (unsigned long) max3100s[i];
-
-       dev_dbg(&spi->dev, "%s: adding port %d\n", __func__, i);
-       max3100s[i]->port.irq = max3100s[i]->irq;
-       max3100s[i]->port.uartclk = max3100s[i]->crystal ? 3686400 : 1843200;
-       max3100s[i]->port.fifosize = 16;
-       max3100s[i]->port.ops = &max3100_ops;
-       max3100s[i]->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
-       max3100s[i]->port.line = i;
-       max3100s[i]->port.type = PORT_MAX3100;
-       max3100s[i]->port.dev = &spi->dev;
-       retval = uart_add_one_port(&max3100_uart_driver, &max3100s[i]->port);
-       if (retval < 0)
-               dev_warn(&spi->dev,
-                        "uart_add_one_port failed for line %d with error %d\n",
-                        i, retval);
-
-       /* set shutdown mode to save power. Will be woken-up on open */
-       if (max3100s[i]->max3100_hw_suspend)
-               max3100s[i]->max3100_hw_suspend(1);
-       else {
-               tx = MAX3100_WC | MAX3100_SHDN;
-               max3100_sr(max3100s[i], tx, &rx);
-       }
-       mutex_unlock(&max3100s_lock);
-       return 0;
-}
-
-static int __devexit max3100_remove(struct spi_device *spi)
-{
-       struct max3100_port *s = dev_get_drvdata(&spi->dev);
-       int i;
-
-       mutex_lock(&max3100s_lock);
-
-       /* find out the index for the chip we are removing */
-       for (i = 0; i < MAX_MAX3100; i++)
-               if (max3100s[i] == s)
-                       break;
-
-       dev_dbg(&spi->dev, "%s: removing port %d\n", __func__, i);
-       uart_remove_one_port(&max3100_uart_driver, &max3100s[i]->port);
-       kfree(max3100s[i]);
-       max3100s[i] = NULL;
-
-       /* check if this is the last chip we have */
-       for (i = 0; i < MAX_MAX3100; i++)
-               if (max3100s[i]) {
-                       mutex_unlock(&max3100s_lock);
-                       return 0;
-               }
-       pr_debug("removing max3100 driver\n");
-       uart_unregister_driver(&max3100_uart_driver);
-
-       mutex_unlock(&max3100s_lock);
-       return 0;
-}
-
-#ifdef CONFIG_PM
-
-static int max3100_suspend(struct spi_device *spi, pm_message_t state)
-{
-       struct max3100_port *s = dev_get_drvdata(&spi->dev);
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       disable_irq(s->irq);
-
-       s->suspending = 1;
-       uart_suspend_port(&max3100_uart_driver, &s->port);
-
-       if (s->max3100_hw_suspend)
-               s->max3100_hw_suspend(1);
-       else {
-               /* no HW suspend, so do SW one */
-               u16 tx, rx;
-
-               tx = MAX3100_WC | MAX3100_SHDN;
-               max3100_sr(s, tx, &rx);
-       }
-       return 0;
-}
-
-static int max3100_resume(struct spi_device *spi)
-{
-       struct max3100_port *s = dev_get_drvdata(&spi->dev);
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       if (s->max3100_hw_suspend)
-               s->max3100_hw_suspend(0);
-       uart_resume_port(&max3100_uart_driver, &s->port);
-       s->suspending = 0;
-
-       enable_irq(s->irq);
-
-       s->conf_commit = 1;
-       if (s->workqueue)
-               max3100_dowork(s);
-
-       return 0;
-}
-
-#else
-#define max3100_suspend NULL
-#define max3100_resume  NULL
-#endif
-
-static struct spi_driver max3100_driver = {
-       .driver = {
-               .name           = "max3100",
-               .bus            = &spi_bus_type,
-               .owner          = THIS_MODULE,
-       },
-
-       .probe          = max3100_probe,
-       .remove         = __devexit_p(max3100_remove),
-       .suspend        = max3100_suspend,
-       .resume         = max3100_resume,
-};
-
-static int __init max3100_init(void)
-{
-       return spi_register_driver(&max3100_driver);
-}
-module_init(max3100_init);
-
-static void __exit max3100_exit(void)
-{
-       spi_unregister_driver(&max3100_driver);
-}
-module_exit(max3100_exit);
-
-MODULE_DESCRIPTION("MAX3100 driver");
-MODULE_AUTHOR("Christian Pellegrin <chripell@evolware.org>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("spi:max3100");
diff --git a/drivers/serial/max3107-aava.c b/drivers/serial/max3107-aava.c
deleted file mode 100644 (file)
index a1fe304..0000000
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- *  max3107.c - spi uart protocol driver for Maxim 3107
- *  Based on max3100.c
- *     by Christian Pellegrin <chripell@evolware.org>
- *  and        max3110.c
- *     by Feng Tang <feng.tang@intel.com>
- *
- *  Copyright (C) Aavamobile 2009
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  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/delay.h>
-#include <linux/device.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/spi/spi.h>
-#include <linux/freezer.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/sfi.h>
-#include <asm/mrst.h>
-#include "max3107.h"
-
-/* GPIO direction to input function */
-static int max3107_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
-{
-       struct max3107_port *s = container_of(chip, struct max3107_port, chip);
-       u16 buf[1];             /* Buffer for SPI transfer */
-
-       if (offset >= MAX3107_GPIO_COUNT) {
-               dev_err(&s->spi->dev, "Invalid GPIO\n");
-               return -EINVAL;
-       }
-
-       /* Read current GPIO configuration register */
-       buf[0] = MAX3107_GPIOCFG_REG;
-       /* Perform SPI transfer */
-       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
-               dev_err(&s->spi->dev, "SPI transfer GPIO read failed\n");
-               return -EIO;
-       }
-       buf[0] &= MAX3107_SPI_RX_DATA_MASK;
-
-       /* Set GPIO to input */
-       buf[0] &= ~(0x0001 << offset);
-
-       /* Write new GPIO configuration register value */
-       buf[0] |= (MAX3107_WRITE_BIT | MAX3107_GPIOCFG_REG);
-       /* Perform SPI transfer */
-       if (max3107_rw(s, (u8 *)buf, NULL, 2)) {
-               dev_err(&s->spi->dev, "SPI transfer GPIO write failed\n");
-               return -EIO;
-       }
-       return 0;
-}
-
-/* GPIO direction to output function */
-static int max3107_gpio_direction_out(struct gpio_chip *chip, unsigned offset,
-                                       int value)
-{
-       struct max3107_port *s = container_of(chip, struct max3107_port, chip);
-       u16 buf[2];     /* Buffer for SPI transfers */
-
-       if (offset >= MAX3107_GPIO_COUNT) {
-               dev_err(&s->spi->dev, "Invalid GPIO\n");
-               return -EINVAL;
-       }
-
-       /* Read current GPIO configuration and data registers */
-       buf[0] = MAX3107_GPIOCFG_REG;
-       buf[1] = MAX3107_GPIODATA_REG;
-       /* Perform SPI transfer */
-       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 4)) {
-               dev_err(&s->spi->dev, "SPI transfer gpio failed\n");
-               return -EIO;
-       }
-       buf[0] &= MAX3107_SPI_RX_DATA_MASK;
-       buf[1] &= MAX3107_SPI_RX_DATA_MASK;
-
-       /* Set GPIO to output */
-       buf[0] |= (0x0001 << offset);
-       /* Set value */
-       if (value)
-               buf[1] |= (0x0001 << offset);
-       else
-               buf[1] &= ~(0x0001 << offset);
-
-       /* Write new GPIO configuration and data register values */
-       buf[0] |= (MAX3107_WRITE_BIT | MAX3107_GPIOCFG_REG);
-       buf[1] |= (MAX3107_WRITE_BIT | MAX3107_GPIODATA_REG);
-       /* Perform SPI transfer */
-       if (max3107_rw(s, (u8 *)buf, NULL, 4)) {
-               dev_err(&s->spi->dev,
-                       "SPI transfer for GPIO conf data w failed\n");
-               return -EIO;
-       }
-       return 0;
-}
-
-/* GPIO value query function */
-static int max3107_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
-       struct max3107_port *s = container_of(chip, struct max3107_port, chip);
-       u16 buf[1];     /* Buffer for SPI transfer */
-
-       if (offset >= MAX3107_GPIO_COUNT) {
-               dev_err(&s->spi->dev, "Invalid GPIO\n");
-               return -EINVAL;
-       }
-
-       /* Read current GPIO data register */
-       buf[0] = MAX3107_GPIODATA_REG;
-       /* Perform SPI transfer */
-       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
-               dev_err(&s->spi->dev, "SPI transfer GPIO data r failed\n");
-               return -EIO;
-       }
-       buf[0] &= MAX3107_SPI_RX_DATA_MASK;
-
-       /* Return value */
-       return buf[0] & (0x0001 << offset);
-}
-
-/* GPIO value set function */
-static void max3107_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
-{
-       struct max3107_port *s = container_of(chip, struct max3107_port, chip);
-       u16 buf[2];     /* Buffer for SPI transfers */
-
-       if (offset >= MAX3107_GPIO_COUNT) {
-               dev_err(&s->spi->dev, "Invalid GPIO\n");
-               return;
-       }
-
-       /* Read current GPIO configuration registers*/
-       buf[0] = MAX3107_GPIODATA_REG;
-       buf[1] = MAX3107_GPIOCFG_REG;
-       /* Perform SPI transfer */
-       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 4)) {
-               dev_err(&s->spi->dev,
-                       "SPI transfer for GPIO data and config read failed\n");
-               return;
-       }
-       buf[0] &= MAX3107_SPI_RX_DATA_MASK;
-       buf[1] &= MAX3107_SPI_RX_DATA_MASK;
-
-       if (!(buf[1] & (0x0001 << offset))) {
-               /* Configured as input, can't set value */
-               dev_warn(&s->spi->dev,
-                               "Trying to set value for input GPIO\n");
-               return;
-       }
-
-       /* Set value */
-       if (value)
-               buf[0] |= (0x0001 << offset);
-       else
-               buf[0] &= ~(0x0001 << offset);
-
-       /* Write new GPIO data register value */
-       buf[0] |= (MAX3107_WRITE_BIT | MAX3107_GPIODATA_REG);
-       /* Perform SPI transfer */
-       if (max3107_rw(s, (u8 *)buf, NULL, 2))
-               dev_err(&s->spi->dev, "SPI transfer GPIO data w failed\n");
-}
-
-/* GPIO chip data */
-static struct gpio_chip max3107_gpio_chip = {
-       .owner                  = THIS_MODULE,
-       .direction_input        = max3107_gpio_direction_in,
-       .direction_output       = max3107_gpio_direction_out,
-       .get                    = max3107_gpio_get,
-       .set                    = max3107_gpio_set,
-       .can_sleep              = 1,
-       .base                   = MAX3107_GPIO_BASE,
-       .ngpio                  = MAX3107_GPIO_COUNT,
-};
-
-/**
- *     max3107_aava_reset      -       reset on AAVA systems
- *     @spi: The SPI device we are probing
- *
- *     Reset the device ready for probing.
- */
-
-static int max3107_aava_reset(struct spi_device *spi)
-{
-       /* Reset the chip */
-       if (gpio_request(MAX3107_RESET_GPIO, "max3107")) {
-               pr_err("Requesting RESET GPIO failed\n");
-               return -EIO;
-       }
-       if (gpio_direction_output(MAX3107_RESET_GPIO, 0)) {
-               pr_err("Setting RESET GPIO to 0 failed\n");
-               gpio_free(MAX3107_RESET_GPIO);
-               return -EIO;
-       }
-       msleep(MAX3107_RESET_DELAY);
-       if (gpio_direction_output(MAX3107_RESET_GPIO, 1)) {
-               pr_err("Setting RESET GPIO to 1 failed\n");
-               gpio_free(MAX3107_RESET_GPIO);
-               return -EIO;
-       }
-       gpio_free(MAX3107_RESET_GPIO);
-       msleep(MAX3107_WAKEUP_DELAY);
-       return 0;
-}
-
-static int max3107_aava_configure(struct max3107_port *s)
-{
-       int retval;
-
-       /* Initialize GPIO chip data */
-       s->chip = max3107_gpio_chip;
-       s->chip.label = s->spi->modalias;
-       s->chip.dev = &s->spi->dev;
-
-       /* Add GPIO chip */
-       retval = gpiochip_add(&s->chip);
-       if (retval) {
-               dev_err(&s->spi->dev, "Adding GPIO chip failed\n");
-               return retval;
-       }
-
-       /* Temporary fix for EV2 boot problems, set modem reset to 0 */
-       max3107_gpio_direction_out(&s->chip, 3, 0);
-       return 0;
-}
-
-#if 0
-/* This will get enabled once we have the board stuff merged for this
-   specific case */
-
-static const struct baud_table brg13_ext[] = {
-       { 300,    MAX3107_BRG13_B300 },
-       { 600,    MAX3107_BRG13_B600 },
-       { 1200,   MAX3107_BRG13_B1200 },
-       { 2400,   MAX3107_BRG13_B2400 },
-       { 4800,   MAX3107_BRG13_B4800 },
-       { 9600,   MAX3107_BRG13_B9600 },
-       { 19200,  MAX3107_BRG13_B19200 },
-       { 57600,  MAX3107_BRG13_B57600 },
-       { 115200, MAX3107_BRG13_B115200 },
-       { 230400, MAX3107_BRG13_B230400 },
-       { 460800, MAX3107_BRG13_B460800 },
-       { 921600, MAX3107_BRG13_B921600 },
-       { 0, 0 }
-};
-
-static void max3107_aava_init(struct max3107_port *s)
-{
-       /*override for AAVA SC specific*/
-       if (mrst_platform_id() == MRST_PLATFORM_AAVA_SC) {
-               if (get_koski_build_id() <= KOSKI_EV2)
-                       if (s->ext_clk) {
-                               s->brg_cfg = MAX3107_BRG13_B9600;
-                               s->baud_tbl = (struct baud_table *)brg13_ext;
-                       }
-       }
-}
-#endif
-
-static int __devexit max3107_aava_remove(struct spi_device *spi)
-{
-       struct max3107_port *s = dev_get_drvdata(&spi->dev);
-
-       /* Remove GPIO chip */
-       if (gpiochip_remove(&s->chip))
-               dev_warn(&spi->dev, "Removing GPIO chip failed\n");
-
-       /* Then do the default remove */
-       return max3107_remove(spi);
-}
-
-/* Platform data */
-static struct max3107_plat aava_plat_data = {
-       .loopback               = 0,
-       .ext_clk                = 1,
-/*     .init                   = max3107_aava_init, */
-       .configure              = max3107_aava_configure,
-       .hw_suspend             = max3107_hw_susp,
-       .polled_mode            = 0,
-       .poll_time              = 0,
-};
-
-
-static int __devinit max3107_probe_aava(struct spi_device *spi)
-{
-       int err = max3107_aava_reset(spi);
-       if (err < 0)
-               return err;
-       return max3107_probe(spi, &aava_plat_data);
-}
-
-/* Spi driver data */
-static struct spi_driver max3107_driver = {
-       .driver = {
-               .name           = "aava-max3107",
-               .bus            = &spi_bus_type,
-               .owner          = THIS_MODULE,
-       },
-       .probe          = max3107_probe_aava,
-       .remove         = __devexit_p(max3107_aava_remove),
-       .suspend        = max3107_suspend,
-       .resume         = max3107_resume,
-};
-
-/* Driver init function */
-static int __init max3107_init(void)
-{
-       return spi_register_driver(&max3107_driver);
-}
-
-/* Driver exit function */
-static void __exit max3107_exit(void)
-{
-       spi_unregister_driver(&max3107_driver);
-}
-
-module_init(max3107_init);
-module_exit(max3107_exit);
-
-MODULE_DESCRIPTION("MAX3107 driver");
-MODULE_AUTHOR("Aavamobile");
-MODULE_ALIAS("aava-max3107-spi");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/serial/max3107.c b/drivers/serial/max3107.c
deleted file mode 100644 (file)
index 910870e..0000000
+++ /dev/null
@@ -1,1213 +0,0 @@
-/*
- *  max3107.c - spi uart protocol driver for Maxim 3107
- *  Based on max3100.c
- *     by Christian Pellegrin <chripell@evolware.org>
- *  and        max3110.c
- *     by Feng Tang <feng.tang@intel.com>
- *
- *  Copyright (C) Aavamobile 2009
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  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/delay.h>
-#include <linux/device.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/gpio.h>
-#include <linux/spi/spi.h>
-#include <linux/freezer.h>
-#include "max3107.h"
-
-static const struct baud_table brg26_ext[] = {
-       { 300,    MAX3107_BRG26_B300 },
-       { 600,    MAX3107_BRG26_B600 },
-       { 1200,   MAX3107_BRG26_B1200 },
-       { 2400,   MAX3107_BRG26_B2400 },
-       { 4800,   MAX3107_BRG26_B4800 },
-       { 9600,   MAX3107_BRG26_B9600 },
-       { 19200,  MAX3107_BRG26_B19200 },
-       { 57600,  MAX3107_BRG26_B57600 },
-       { 115200, MAX3107_BRG26_B115200 },
-       { 230400, MAX3107_BRG26_B230400 },
-       { 460800, MAX3107_BRG26_B460800 },
-       { 921600, MAX3107_BRG26_B921600 },
-       { 0, 0 }
-};
-
-static const struct baud_table brg13_int[] = {
-       { 300,    MAX3107_BRG13_IB300 },
-       { 600,    MAX3107_BRG13_IB600 },
-       { 1200,   MAX3107_BRG13_IB1200 },
-       { 2400,   MAX3107_BRG13_IB2400 },
-       { 4800,   MAX3107_BRG13_IB4800 },
-       { 9600,   MAX3107_BRG13_IB9600 },
-       { 19200,  MAX3107_BRG13_IB19200 },
-       { 57600,  MAX3107_BRG13_IB57600 },
-       { 115200, MAX3107_BRG13_IB115200 },
-       { 230400, MAX3107_BRG13_IB230400 },
-       { 460800, MAX3107_BRG13_IB460800 },
-       { 921600, MAX3107_BRG13_IB921600 },
-       { 0, 0 }
-};
-
-static u32 get_new_brg(int baud, struct max3107_port *s)
-{
-       int i;
-       const struct baud_table *baud_tbl = s->baud_tbl;
-
-       for (i = 0; i < 13; i++) {
-               if (baud == baud_tbl[i].baud)
-                       return baud_tbl[i].new_brg;
-       }
-
-       return 0;
-}
-
-/* Perform SPI transfer for write/read of device register(s) */
-int max3107_rw(struct max3107_port *s, u8 *tx, u8 *rx, int len)
-{
-       struct spi_message spi_msg;
-       struct spi_transfer spi_xfer;
-
-       /* Initialize SPI ,message */
-       spi_message_init(&spi_msg);
-
-       /* Initialize SPI transfer */
-       memset(&spi_xfer, 0, sizeof spi_xfer);
-       spi_xfer.len = len;
-       spi_xfer.tx_buf = tx;
-       spi_xfer.rx_buf = rx;
-       spi_xfer.speed_hz = MAX3107_SPI_SPEED;
-
-       /* Add SPI transfer to SPI message */
-       spi_message_add_tail(&spi_xfer, &spi_msg);
-
-#ifdef DBG_TRACE_SPI_DATA
-       {
-               int i;
-               pr_info("tx len %d:\n", spi_xfer.len);
-               for (i = 0 ; i < spi_xfer.len && i < 32 ; i++)
-                       pr_info(" %x", ((u8 *)spi_xfer.tx_buf)[i]);
-               pr_info("\n");
-       }
-#endif
-
-       /* Perform synchronous SPI transfer */
-       if (spi_sync(s->spi, &spi_msg)) {
-               dev_err(&s->spi->dev, "spi_sync failure\n");
-               return -EIO;
-       }
-
-#ifdef DBG_TRACE_SPI_DATA
-       if (spi_xfer.rx_buf) {
-               int i;
-               pr_info("rx len %d:\n", spi_xfer.len);
-               for (i = 0 ; i < spi_xfer.len && i < 32 ; i++)
-                       pr_info(" %x", ((u8 *)spi_xfer.rx_buf)[i]);
-               pr_info("\n");
-       }
-#endif
-       return 0;
-}
-EXPORT_SYMBOL_GPL(max3107_rw);
-
-/* Puts received data to circular buffer */
-static void put_data_to_circ_buf(struct max3107_port *s, unsigned char *data,
-                                       int len)
-{
-       struct uart_port *port = &s->port;
-       struct tty_struct *tty;
-
-       if (!port->state)
-               return;
-
-       tty = port->state->port.tty;
-       if (!tty)
-               return;
-
-       /* Insert received data */
-       tty_insert_flip_string(tty, data, len);
-       /* Update RX counter */
-       port->icount.rx += len;
-}
-
-/* Handle data receiving */
-static void max3107_handlerx(struct max3107_port *s, u16 rxlvl)
-{
-       int i;
-       int j;
-       int len;                                /* SPI transfer buffer length */
-       u16 *buf;
-       u8 *valid_str;
-
-       if (!s->rx_enabled)
-               /* RX is disabled */
-               return;
-
-       if (rxlvl == 0) {
-               /* RX fifo is empty */
-               return;
-       } else if (rxlvl >= MAX3107_RX_FIFO_SIZE) {
-               dev_warn(&s->spi->dev, "Possible RX FIFO overrun %d\n", rxlvl);
-               /* Ensure sanity of RX level */
-               rxlvl = MAX3107_RX_FIFO_SIZE;
-       }
-       if ((s->rxbuf == 0) || (s->rxstr == 0)) {
-               dev_warn(&s->spi->dev, "Rx buffer/str isn't ready\n");
-               return;
-       }
-       buf = s->rxbuf;
-       valid_str = s->rxstr;
-       while (rxlvl) {
-               pr_debug("rxlvl %d\n", rxlvl);
-               /* Clear buffer */
-               memset(buf, 0, sizeof(u16) * (MAX3107_RX_FIFO_SIZE + 2));
-               len = 0;
-               if (s->irqen_reg & MAX3107_IRQ_RXFIFO_BIT) {
-                       /* First disable RX FIFO interrupt */
-                       pr_debug("Disabling RX INT\n");
-                       buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
-                       s->irqen_reg &= ~MAX3107_IRQ_RXFIFO_BIT;
-                       buf[0] |= s->irqen_reg;
-                       len++;
-               }
-               /* Just increase the length by amount of words in FIFO since
-                * buffer was zeroed and SPI transfer of 0x0000 means reading
-                * from RX FIFO
-                */
-               len += rxlvl;
-               /* Append RX level query */
-               buf[len] = MAX3107_RXFIFOLVL_REG;
-               len++;
-
-               /* Perform the SPI transfer */
-               if (max3107_rw(s, (u8 *)buf, (u8 *)buf, len * 2)) {
-                       dev_err(&s->spi->dev, "SPI transfer for RX h failed\n");
-                       return;
-               }
-
-               /* Skip RX FIFO interrupt disabling word if it was added */
-               j = ((len - 1) - rxlvl);
-               /* Read received words */
-               for (i = 0; i < rxlvl; i++, j++)
-                       valid_str[i] = (u8)buf[j];
-               put_data_to_circ_buf(s, valid_str, rxlvl);
-               /* Get new RX level */
-               rxlvl = (buf[len - 1] & MAX3107_SPI_RX_DATA_MASK);
-       }
-
-       if (s->rx_enabled) {
-               /* RX still enabled, re-enable RX FIFO interrupt */
-               pr_debug("Enabling RX INT\n");
-               buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
-               s->irqen_reg |= MAX3107_IRQ_RXFIFO_BIT;
-               buf[0] |= s->irqen_reg;
-               if (max3107_rw(s, (u8 *)buf, NULL, 2))
-                       dev_err(&s->spi->dev, "RX FIFO INT enabling failed\n");
-       }
-
-       /* Push the received data to receivers */
-       if (s->port.state->port.tty)
-               tty_flip_buffer_push(s->port.state->port.tty);
-}
-
-
-/* Handle data sending */
-static void max3107_handletx(struct max3107_port *s)
-{
-       struct circ_buf *xmit = &s->port.state->xmit;
-       int i;
-       unsigned long flags;
-       int len;                                /* SPI transfer buffer length */
-       u16 *buf;
-
-       if (!s->tx_fifo_empty)
-               /* Don't send more data before previous data is sent */
-               return;
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&s->port))
-               /* No data to send or TX is stopped */
-               return;
-
-       if (!s->txbuf) {
-               dev_warn(&s->spi->dev, "Txbuf isn't ready\n");
-               return;
-       }
-       buf = s->txbuf;
-       /* Get length of data pending in circular buffer */
-       len = uart_circ_chars_pending(xmit);
-       if (len) {
-               /* Limit to size of TX FIFO */
-               if (len > MAX3107_TX_FIFO_SIZE)
-                       len = MAX3107_TX_FIFO_SIZE;
-
-               pr_debug("txlen %d\n", len);
-
-               /* Update TX counter */
-               s->port.icount.tx += len;
-
-               /* TX FIFO will no longer be empty */
-               s->tx_fifo_empty = 0;
-
-               i = 0;
-               if (s->irqen_reg & MAX3107_IRQ_TXEMPTY_BIT) {
-                       /* First disable TX empty interrupt */
-                       pr_debug("Disabling TE INT\n");
-                       buf[i] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
-                       s->irqen_reg &= ~MAX3107_IRQ_TXEMPTY_BIT;
-                       buf[i] |= s->irqen_reg;
-                       i++;
-                       len++;
-               }
-               /* Add data to send */
-               spin_lock_irqsave(&s->port.lock, flags);
-               for ( ; i < len ; i++) {
-                       buf[i] = (MAX3107_WRITE_BIT | MAX3107_THR_REG);
-                       buf[i] |= ((u16)xmit->buf[xmit->tail] &
-                                               MAX3107_SPI_TX_DATA_MASK);
-                       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               }
-               spin_unlock_irqrestore(&s->port.lock, flags);
-               if (!(s->irqen_reg & MAX3107_IRQ_TXEMPTY_BIT)) {
-                       /* Enable TX empty interrupt */
-                       pr_debug("Enabling TE INT\n");
-                       buf[i] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
-                       s->irqen_reg |= MAX3107_IRQ_TXEMPTY_BIT;
-                       buf[i] |= s->irqen_reg;
-                       i++;
-                       len++;
-               }
-               if (!s->tx_enabled) {
-                       /* Enable TX */
-                       pr_debug("Enable TX\n");
-                       buf[i] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
-                       spin_lock_irqsave(&s->data_lock, flags);
-                       s->mode1_reg &= ~MAX3107_MODE1_TXDIS_BIT;
-                       buf[i] |= s->mode1_reg;
-                       spin_unlock_irqrestore(&s->data_lock, flags);
-                       s->tx_enabled = 1;
-                       i++;
-                       len++;
-               }
-
-               /* Perform the SPI transfer */
-               if (max3107_rw(s, (u8 *)buf, NULL, len*2)) {
-                       dev_err(&s->spi->dev,
-                               "SPI transfer TX handling failed\n");
-                       return;
-               }
-       }
-
-       /* Indicate wake up if circular buffer is getting low on data */
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&s->port);
-
-}
-
-/* Handle interrupts
- * Also reads and returns current RX FIFO level
- */
-static u16 handle_interrupt(struct max3107_port *s)
-{
-       u16 buf[4];     /* Buffer for SPI transfers */
-       u8 irq_status;
-       u16 rx_level;
-       unsigned long flags;
-
-       /* Read IRQ status register */
-       buf[0] = MAX3107_IRQSTS_REG;
-       /* Read status IRQ status register */
-       buf[1] = MAX3107_STS_IRQSTS_REG;
-       /* Read LSR IRQ status register */
-       buf[2] = MAX3107_LSR_IRQSTS_REG;
-       /* Query RX level */
-       buf[3] = MAX3107_RXFIFOLVL_REG;
-
-       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 8)) {
-               dev_err(&s->spi->dev,
-                       "SPI transfer for INTR handling failed\n");
-               return 0;
-       }
-
-       irq_status = (u8)buf[0];
-       pr_debug("IRQSTS %x\n", irq_status);
-       rx_level = (buf[3] & MAX3107_SPI_RX_DATA_MASK);
-
-       if (irq_status & MAX3107_IRQ_LSR_BIT) {
-               /* LSR interrupt */
-               if (buf[2] & MAX3107_LSR_RXTO_BIT)
-                       /* RX timeout interrupt,
-                        * handled by normal RX handling
-                        */
-                       pr_debug("RX TO INT\n");
-       }
-
-       if (irq_status & MAX3107_IRQ_TXEMPTY_BIT) {
-               /* Tx empty interrupt,
-                * disable TX and set tx_fifo_empty flag
-                */
-               pr_debug("TE INT, disabling TX\n");
-               buf[0] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
-               spin_lock_irqsave(&s->data_lock, flags);
-               s->mode1_reg |= MAX3107_MODE1_TXDIS_BIT;
-               buf[0] |= s->mode1_reg;
-               spin_unlock_irqrestore(&s->data_lock, flags);
-               if (max3107_rw(s, (u8 *)buf, NULL, 2))
-                       dev_err(&s->spi->dev, "SPI transfer TX dis failed\n");
-               s->tx_enabled = 0;
-               s->tx_fifo_empty = 1;
-       }
-
-       if (irq_status & MAX3107_IRQ_RXFIFO_BIT)
-               /* RX FIFO interrupt,
-                * handled by normal RX handling
-                */
-               pr_debug("RFIFO INT\n");
-
-       /* Return RX level */
-       return rx_level;
-}
-
-/* Trigger work thread*/
-static void max3107_dowork(struct max3107_port *s)
-{
-       if (!work_pending(&s->work) && !freezing(current) && !s->suspended)
-               queue_work(s->workqueue, &s->work);
-       else
-               dev_warn(&s->spi->dev, "interrup isn't serviced normally!\n");
-}
-
-/* Work thread */
-static void max3107_work(struct work_struct *w)
-{
-       struct max3107_port *s = container_of(w, struct max3107_port, work);
-       u16 rxlvl = 0;
-       int len;        /* SPI transfer buffer length */
-       u16 buf[5];     /* Buffer for SPI transfers */
-       unsigned long flags;
-
-       /* Start by reading current RX FIFO level */
-       buf[0] = MAX3107_RXFIFOLVL_REG;
-       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
-               dev_err(&s->spi->dev, "SPI transfer RX lev failed\n");
-               rxlvl = 0;
-       } else {
-               rxlvl = (buf[0] & MAX3107_SPI_RX_DATA_MASK);
-       }
-
-       do {
-               pr_debug("rxlvl %d\n", rxlvl);
-
-               /* Handle RX */
-               max3107_handlerx(s, rxlvl);
-               rxlvl = 0;
-
-               if (s->handle_irq) {
-                       /* Handle pending interrupts
-                        * We also get new RX FIFO level since new data may
-                        * have been received while pushing received data to
-                        * receivers
-                        */
-                       s->handle_irq = 0;
-                       rxlvl = handle_interrupt(s);
-               }
-
-               /* Handle TX */
-               max3107_handletx(s);
-
-               /* Handle configuration changes */
-               len = 0;
-               spin_lock_irqsave(&s->data_lock, flags);
-               if (s->mode1_commit) {
-                       pr_debug("mode1_commit\n");
-                       buf[len] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
-                       buf[len++] |= s->mode1_reg;
-                       s->mode1_commit = 0;
-               }
-               if (s->lcr_commit) {
-                       pr_debug("lcr_commit\n");
-                       buf[len] = (MAX3107_WRITE_BIT | MAX3107_LCR_REG);
-                       buf[len++] |= s->lcr_reg;
-                       s->lcr_commit = 0;
-               }
-               if (s->brg_commit) {
-                       pr_debug("brg_commit\n");
-                       buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVMSB_REG);
-                       buf[len++] |= ((s->brg_cfg >> 16) &
-                                               MAX3107_SPI_TX_DATA_MASK);
-                       buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVLSB_REG);
-                       buf[len++] |= ((s->brg_cfg >> 8) &
-                                               MAX3107_SPI_TX_DATA_MASK);
-                       buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGCFG_REG);
-                       buf[len++] |= ((s->brg_cfg) & 0xff);
-                       s->brg_commit = 0;
-               }
-               spin_unlock_irqrestore(&s->data_lock, flags);
-
-               if (len > 0) {
-                       if (max3107_rw(s, (u8 *)buf, NULL, len * 2))
-                               dev_err(&s->spi->dev,
-                                       "SPI transfer config failed\n");
-               }
-
-               /* Reloop if interrupt handling indicated data in RX FIFO */
-       } while (rxlvl);
-
-}
-
-/* Set sleep mode */
-static void max3107_set_sleep(struct max3107_port *s, int mode)
-{
-       u16 buf[1];     /* Buffer for SPI transfer */
-       unsigned long flags;
-       pr_debug("enter, mode %d\n", mode);
-
-       buf[0] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
-       spin_lock_irqsave(&s->data_lock, flags);
-       switch (mode) {
-       case MAX3107_DISABLE_FORCED_SLEEP:
-                       s->mode1_reg &= ~MAX3107_MODE1_FORCESLEEP_BIT;
-                       break;
-       case MAX3107_ENABLE_FORCED_SLEEP:
-                       s->mode1_reg |= MAX3107_MODE1_FORCESLEEP_BIT;
-                       break;
-       case MAX3107_DISABLE_AUTOSLEEP:
-                       s->mode1_reg &= ~MAX3107_MODE1_AUTOSLEEP_BIT;
-                       break;
-       case MAX3107_ENABLE_AUTOSLEEP:
-                       s->mode1_reg |= MAX3107_MODE1_AUTOSLEEP_BIT;
-                       break;
-       default:
-               spin_unlock_irqrestore(&s->data_lock, flags);
-               dev_warn(&s->spi->dev, "invalid sleep mode\n");
-               return;
-       }
-       buf[0] |= s->mode1_reg;
-       spin_unlock_irqrestore(&s->data_lock, flags);
-
-       if (max3107_rw(s, (u8 *)buf, NULL, 2))
-               dev_err(&s->spi->dev, "SPI transfer sleep mode failed\n");
-
-       if (mode == MAX3107_DISABLE_AUTOSLEEP ||
-                       mode == MAX3107_DISABLE_FORCED_SLEEP)
-               msleep(MAX3107_WAKEUP_DELAY);
-}
-
-/* Perform full register initialization */
-static void max3107_register_init(struct max3107_port *s)
-{
-       u16 buf[11];    /* Buffer for SPI transfers */
-
-       /* 1. Configure baud rate, 9600 as default */
-       s->baud = 9600;
-       /* the below is default*/
-       if (s->ext_clk) {
-               s->brg_cfg = MAX3107_BRG26_B9600;
-               s->baud_tbl = (struct baud_table *)brg26_ext;
-       } else {
-               s->brg_cfg = MAX3107_BRG13_IB9600;
-               s->baud_tbl = (struct baud_table *)brg13_int;
-       }
-
-       if (s->pdata->init)
-               s->pdata->init(s);
-
-       buf[0] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVMSB_REG)
-               | ((s->brg_cfg >> 16) & MAX3107_SPI_TX_DATA_MASK);
-       buf[1] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVLSB_REG)
-               | ((s->brg_cfg >> 8) & MAX3107_SPI_TX_DATA_MASK);
-       buf[2] = (MAX3107_WRITE_BIT | MAX3107_BRGCFG_REG)
-               | ((s->brg_cfg) & 0xff);
-
-       /* 2. Configure LCR register, 8N1 mode by default */
-       s->lcr_reg = MAX3107_LCR_WORD_LEN_8;
-       buf[3] = (MAX3107_WRITE_BIT | MAX3107_LCR_REG)
-               | s->lcr_reg;
-
-       /* 3. Configure MODE 1 register */
-       s->mode1_reg = 0;
-       /* Enable IRQ pin */
-       s->mode1_reg |= MAX3107_MODE1_IRQSEL_BIT;
-       /* Disable TX */
-       s->mode1_reg |= MAX3107_MODE1_TXDIS_BIT;
-       s->tx_enabled = 0;
-       /* RX is enabled */
-       s->rx_enabled = 1;
-       buf[4] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG)
-               | s->mode1_reg;
-
-       /* 4. Configure MODE 2 register */
-       buf[5] = (MAX3107_WRITE_BIT | MAX3107_MODE2_REG);
-       if (s->loopback) {
-               /* Enable loopback */
-               buf[5] |= MAX3107_MODE2_LOOPBACK_BIT;
-       }
-       /* Reset FIFOs */
-       buf[5] |= MAX3107_MODE2_FIFORST_BIT;
-       s->tx_fifo_empty = 1;
-
-       /* 5. Configure FIFO trigger level register */
-       buf[6] = (MAX3107_WRITE_BIT | MAX3107_FIFOTRIGLVL_REG);
-       /* RX FIFO trigger for 16 words, TX FIFO trigger not used */
-       buf[6] |= (MAX3107_FIFOTRIGLVL_RX(16) | MAX3107_FIFOTRIGLVL_TX(0));
-
-       /* 6. Configure flow control levels */
-       buf[7] = (MAX3107_WRITE_BIT | MAX3107_FLOWLVL_REG);
-       /* Flow control halt level 96, resume level 48 */
-       buf[7] |= (MAX3107_FLOWLVL_RES(48) | MAX3107_FLOWLVL_HALT(96));
-
-       /* 7. Configure flow control */
-       buf[8] = (MAX3107_WRITE_BIT | MAX3107_FLOWCTRL_REG);
-       /* Enable auto CTS and auto RTS flow control */
-       buf[8] |= (MAX3107_FLOWCTRL_AUTOCTS_BIT | MAX3107_FLOWCTRL_AUTORTS_BIT);
-
-       /* 8. Configure RX timeout register */
-       buf[9] = (MAX3107_WRITE_BIT | MAX3107_RXTO_REG);
-       /* Timeout after 48 character intervals */
-       buf[9] |= 0x0030;
-
-       /* 9. Configure LSR interrupt enable register */
-       buf[10] = (MAX3107_WRITE_BIT | MAX3107_LSR_IRQEN_REG);
-       /* Enable RX timeout interrupt */
-       buf[10] |= MAX3107_LSR_RXTO_BIT;
-
-       /* Perform SPI transfer */
-       if (max3107_rw(s, (u8 *)buf, NULL, 22))
-               dev_err(&s->spi->dev, "SPI transfer for init failed\n");
-
-       /* 10. Clear IRQ status register by reading it */
-       buf[0] = MAX3107_IRQSTS_REG;
-
-       /* 11. Configure interrupt enable register */
-       /* Enable LSR interrupt */
-       s->irqen_reg = MAX3107_IRQ_LSR_BIT;
-       /* Enable RX FIFO interrupt */
-       s->irqen_reg |= MAX3107_IRQ_RXFIFO_BIT;
-       buf[1] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG)
-               | s->irqen_reg;
-
-       /* 12. Clear FIFO reset that was set in step 6 */
-       buf[2] = (MAX3107_WRITE_BIT | MAX3107_MODE2_REG);
-       if (s->loopback) {
-               /* Keep loopback enabled */
-               buf[2] |= MAX3107_MODE2_LOOPBACK_BIT;
-       }
-
-       /* Perform SPI transfer */
-       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 6))
-               dev_err(&s->spi->dev, "SPI transfer for init failed\n");
-
-}
-
-/* IRQ handler */
-static irqreturn_t max3107_irq(int irqno, void *dev_id)
-{
-       struct max3107_port *s = dev_id;
-
-       if (irqno != s->spi->irq) {
-               /* Unexpected IRQ */
-               return IRQ_NONE;
-       }
-
-       /* Indicate irq */
-       s->handle_irq = 1;
-
-       /* Trigger work thread */
-       max3107_dowork(s);
-
-       return IRQ_HANDLED;
-}
-
-/* HW suspension function
- *
- * Currently autosleep is used to decrease current consumption, alternative
- * approach would be to set the chip to reset mode if UART is not being
- * used but that would mess the GPIOs
- *
- */
-void max3107_hw_susp(struct max3107_port *s, int suspend)
-{
-       pr_debug("enter, suspend %d\n", suspend);
-
-       if (suspend) {
-               /* Suspend requested,
-                * enable autosleep to decrease current consumption
-                */
-               s->suspended = 1;
-               max3107_set_sleep(s, MAX3107_ENABLE_AUTOSLEEP);
-       } else {
-               /* Resume requested,
-                * disable autosleep
-                */
-               s->suspended = 0;
-               max3107_set_sleep(s, MAX3107_DISABLE_AUTOSLEEP);
-       }
-}
-EXPORT_SYMBOL_GPL(max3107_hw_susp);
-
-/* Modem status IRQ enabling */
-static void max3107_enable_ms(struct uart_port *port)
-{
-       /* Modem status not supported */
-}
-
-/* Data send function */
-static void max3107_start_tx(struct uart_port *port)
-{
-       struct max3107_port *s = container_of(port, struct max3107_port, port);
-
-       /* Trigger work thread for sending data */
-       max3107_dowork(s);
-}
-
-/* Function for checking that there is no pending transfers */
-static unsigned int max3107_tx_empty(struct uart_port *port)
-{
-       struct max3107_port *s = container_of(port, struct max3107_port, port);
-
-       pr_debug("returning %d\n",
-                 (s->tx_fifo_empty && uart_circ_empty(&s->port.state->xmit)));
-       return s->tx_fifo_empty && uart_circ_empty(&s->port.state->xmit);
-}
-
-/* Function for stopping RX */
-static void max3107_stop_rx(struct uart_port *port)
-{
-       struct max3107_port *s = container_of(port, struct max3107_port, port);
-       unsigned long flags;
-
-       /* Set RX disabled in MODE 1 register */
-       spin_lock_irqsave(&s->data_lock, flags);
-       s->mode1_reg |= MAX3107_MODE1_RXDIS_BIT;
-       s->mode1_commit = 1;
-       spin_unlock_irqrestore(&s->data_lock, flags);
-       /* Set RX disabled */
-       s->rx_enabled = 0;
-       /* Trigger work thread for doing the actual configuration change */
-       max3107_dowork(s);
-}
-
-/* Function for returning control pin states */
-static unsigned int max3107_get_mctrl(struct uart_port *port)
-{
-       /* DCD and DSR are not wired and CTS/RTS is handled automatically
-        * so just indicate DSR and CAR asserted
-        */
-       return TIOCM_DSR | TIOCM_CAR;
-}
-
-/* Function for setting control pin states */
-static void max3107_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       /* DCD and DSR are not wired and CTS/RTS is hadnled automatically
-        * so do nothing
-        */
-}
-
-/* Function for configuring UART parameters */
-static void max3107_set_termios(struct uart_port *port,
-                               struct ktermios *termios,
-                               struct ktermios *old)
-{
-       struct max3107_port *s = container_of(port, struct max3107_port, port);
-       struct tty_struct *tty;
-       int baud;
-       u16 new_lcr = 0;
-       u32 new_brg = 0;
-       unsigned long flags;
-
-       if (!port->state)
-               return;
-
-       tty = port->state->port.tty;
-       if (!tty)
-               return;
-
-       /* Get new LCR register values */
-       /* Word size */
-       if ((termios->c_cflag & CSIZE) == CS7)
-               new_lcr |= MAX3107_LCR_WORD_LEN_7;
-       else
-               new_lcr |= MAX3107_LCR_WORD_LEN_8;
-
-       /* Parity */
-       if (termios->c_cflag & PARENB) {
-               new_lcr |= MAX3107_LCR_PARITY_BIT;
-               if (!(termios->c_cflag & PARODD))
-                       new_lcr |= MAX3107_LCR_EVENPARITY_BIT;
-       }
-
-       /* Stop bits */
-       if (termios->c_cflag & CSTOPB) {
-               /* 2 stop bits */
-               new_lcr |= MAX3107_LCR_STOPLEN_BIT;
-       }
-
-       /* Mask termios capabilities we don't support */
-       termios->c_cflag &= ~CMSPAR;
-
-       /* Set status ignore mask */
-       s->port.ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               s->port.ignore_status_mask |= MAX3107_ALL_ERRORS;
-
-       /* Set low latency to immediately handle pushed data */
-       s->port.state->port.tty->low_latency = 1;
-
-       /* Get new baud rate generator configuration */
-       baud = tty_get_baud_rate(tty);
-
-       spin_lock_irqsave(&s->data_lock, flags);
-       new_brg = get_new_brg(baud, s);
-       /* if can't find the corrent config, use previous */
-       if (!new_brg) {
-               baud = s->baud;
-               new_brg = s->brg_cfg;
-       }
-       spin_unlock_irqrestore(&s->data_lock, flags);
-       tty_termios_encode_baud_rate(termios, baud, baud);
-       s->baud = baud;
-
-       /* Update timeout according to new baud rate */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       spin_lock_irqsave(&s->data_lock, flags);
-       if (s->lcr_reg != new_lcr) {
-               s->lcr_reg = new_lcr;
-               s->lcr_commit = 1;
-       }
-       if (s->brg_cfg != new_brg) {
-               s->brg_cfg = new_brg;
-               s->brg_commit = 1;
-       }
-       spin_unlock_irqrestore(&s->data_lock, flags);
-
-       /* Trigger work thread for doing the actual configuration change */
-       max3107_dowork(s);
-}
-
-/* Port shutdown function */
-static void max3107_shutdown(struct uart_port *port)
-{
-       struct max3107_port *s = container_of(port, struct max3107_port, port);
-
-       if (s->suspended && s->pdata->hw_suspend)
-               s->pdata->hw_suspend(s, 0);
-
-       /* Free the interrupt */
-       free_irq(s->spi->irq, s);
-
-       if (s->workqueue) {
-               /* Flush and destroy work queue */
-               flush_workqueue(s->workqueue);
-               destroy_workqueue(s->workqueue);
-               s->workqueue = NULL;
-       }
-
-       /* Suspend HW */
-       if (s->pdata->hw_suspend)
-               s->pdata->hw_suspend(s, 1);
-}
-
-/* Port startup function */
-static int max3107_startup(struct uart_port *port)
-{
-       struct max3107_port *s = container_of(port, struct max3107_port, port);
-
-       /* Initialize work queue */
-       s->workqueue = create_freezeable_workqueue("max3107");
-       if (!s->workqueue) {
-               dev_err(&s->spi->dev, "Workqueue creation failed\n");
-               return -EBUSY;
-       }
-       INIT_WORK(&s->work, max3107_work);
-
-       /* Setup IRQ */
-       if (request_irq(s->spi->irq, max3107_irq, IRQF_TRIGGER_FALLING,
-                       "max3107", s)) {
-               dev_err(&s->spi->dev, "IRQ reguest failed\n");
-               destroy_workqueue(s->workqueue);
-               s->workqueue = NULL;
-               return -EBUSY;
-       }
-
-       /* Resume HW */
-       if (s->pdata->hw_suspend)
-               s->pdata->hw_suspend(s, 0);
-
-       /* Init registers */
-       max3107_register_init(s);
-
-       return 0;
-}
-
-/* Port type function */
-static const char *max3107_type(struct uart_port *port)
-{
-       struct max3107_port *s = container_of(port, struct max3107_port, port);
-       return s->spi->modalias;
-}
-
-/* Port release function */
-static void max3107_release_port(struct uart_port *port)
-{
-       /* Do nothing */
-}
-
-/* Port request function */
-static int max3107_request_port(struct uart_port *port)
-{
-       /* Do nothing */
-       return 0;
-}
-
-/* Port config function */
-static void max3107_config_port(struct uart_port *port, int flags)
-{
-       struct max3107_port *s = container_of(port, struct max3107_port, port);
-       s->port.type = PORT_MAX3107;
-}
-
-/* Port verify function */
-static int max3107_verify_port(struct uart_port *port,
-                               struct serial_struct *ser)
-{
-       if (ser->type == PORT_UNKNOWN || ser->type == PORT_MAX3107)
-               return 0;
-
-       return -EINVAL;
-}
-
-/* Port stop TX function */
-static void max3107_stop_tx(struct uart_port *port)
-{
-       /* Do nothing */
-}
-
-/* Port break control function */
-static void max3107_break_ctl(struct uart_port *port, int break_state)
-{
-       /* We don't support break control, do nothing */
-}
-
-
-/* Port functions */
-static struct uart_ops max3107_ops = {
-       .tx_empty       = max3107_tx_empty,
-       .set_mctrl      = max3107_set_mctrl,
-       .get_mctrl      = max3107_get_mctrl,
-       .stop_tx        = max3107_stop_tx,
-       .start_tx       = max3107_start_tx,
-       .stop_rx        = max3107_stop_rx,
-       .enable_ms      = max3107_enable_ms,
-       .break_ctl      = max3107_break_ctl,
-       .startup        = max3107_startup,
-       .shutdown       = max3107_shutdown,
-       .set_termios    = max3107_set_termios,
-       .type           = max3107_type,
-       .release_port   = max3107_release_port,
-       .request_port   = max3107_request_port,
-       .config_port    = max3107_config_port,
-       .verify_port    = max3107_verify_port,
-};
-
-/* UART driver data */
-static struct uart_driver max3107_uart_driver = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "ttyMAX",
-       .dev_name       = "ttyMAX",
-       .nr             = 1,
-};
-
-static int driver_registered = 0;
-
-
-
-/* 'Generic' platform data */
-static struct max3107_plat generic_plat_data = {
-       .loopback               = 0,
-       .ext_clk                = 1,
-       .hw_suspend             = max3107_hw_susp,
-       .polled_mode            = 0,
-       .poll_time              = 0,
-};
-
-
-/*******************************************************************/
-
-/**
- *     max3107_probe           -       SPI bus probe entry point
- *     @spi: the spi device
- *
- *     SPI wants us to probe this device and if appropriate claim it.
- *     Perform any platform specific requirements and then initialise
- *     the device.
- */
-
-int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata)
-{
-       struct max3107_port *s;
-       u16 buf[2];     /* Buffer for SPI transfers */
-       int retval;
-
-       pr_info("enter max3107 probe\n");
-
-       /* Allocate port structure */
-       s = kzalloc(sizeof(*s), GFP_KERNEL);
-       if (!s) {
-               pr_err("Allocating port structure failed\n");
-               return -ENOMEM;
-       }
-
-       s->pdata = pdata;
-
-       /* SPI Rx buffer
-        * +2 for RX FIFO interrupt
-        * disabling and RX level query
-        */
-       s->rxbuf = kzalloc(sizeof(u16) * (MAX3107_RX_FIFO_SIZE+2), GFP_KERNEL);
-       if (!s->rxbuf) {
-               pr_err("Allocating RX buffer failed\n");
-               retval = -ENOMEM;
-               goto err_free4;
-       }
-       s->rxstr = kzalloc(sizeof(u8) * MAX3107_RX_FIFO_SIZE, GFP_KERNEL);
-       if (!s->rxstr) {
-               pr_err("Allocating RX buffer failed\n");
-               retval = -ENOMEM;
-               goto err_free3;
-       }
-       /* SPI Tx buffer
-        * SPI transfer buffer
-        * +3 for TX FIFO empty
-        * interrupt disabling and
-        * enabling and TX enabling
-        */
-       s->txbuf = kzalloc(sizeof(u16) * MAX3107_TX_FIFO_SIZE + 3, GFP_KERNEL);
-       if (!s->txbuf) {
-               pr_err("Allocating TX buffer failed\n");
-               retval = -ENOMEM;
-               goto err_free2;
-       }
-       /* Initialize shared data lock */
-       spin_lock_init(&s->data_lock);
-
-       /* SPI intializations */
-       dev_set_drvdata(&spi->dev, s);
-       spi->mode = SPI_MODE_0;
-       spi->dev.platform_data = pdata;
-       spi->bits_per_word = 16;
-       s->ext_clk = pdata->ext_clk;
-       s->loopback = pdata->loopback;
-       spi_setup(spi);
-       s->spi = spi;
-
-       /* Check REV ID to ensure we are talking to what we expect */
-       buf[0] = MAX3107_REVID_REG;
-       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
-               dev_err(&s->spi->dev, "SPI transfer for REVID read failed\n");
-               retval = -EIO;
-               goto err_free1;
-       }
-       if ((buf[0] & MAX3107_SPI_RX_DATA_MASK) != MAX3107_REVID1 &&
-               (buf[0] & MAX3107_SPI_RX_DATA_MASK) != MAX3107_REVID2) {
-               dev_err(&s->spi->dev, "REVID %x does not match\n",
-                               (buf[0] & MAX3107_SPI_RX_DATA_MASK));
-               retval = -ENODEV;
-               goto err_free1;
-       }
-
-       /* Disable all interrupts */
-       buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG | 0x0000);
-       buf[0] |= 0x0000;
-
-       /* Configure clock source */
-       buf[1] = (MAX3107_WRITE_BIT | MAX3107_CLKSRC_REG);
-       if (s->ext_clk) {
-               /* External clock */
-               buf[1] |= MAX3107_CLKSRC_EXTCLK_BIT;
-       }
-
-       /* PLL bypass ON */
-       buf[1] |= MAX3107_CLKSRC_PLLBYP_BIT;
-
-       /* Perform SPI transfer */
-       if (max3107_rw(s, (u8 *)buf, NULL, 4)) {
-               dev_err(&s->spi->dev, "SPI transfer for init failed\n");
-               retval = -EIO;
-               goto err_free1;
-       }
-
-       /* Register UART driver */
-       if (!driver_registered) {
-               retval = uart_register_driver(&max3107_uart_driver);
-               if (retval) {
-                       dev_err(&s->spi->dev, "Registering UART driver failed\n");
-                       goto err_free1;
-               }
-               driver_registered = 1;
-       }
-
-       /* Initialize UART port data */
-       s->port.fifosize = 128;
-       s->port.ops = &max3107_ops;
-       s->port.line = 0;
-       s->port.dev = &spi->dev;
-       s->port.uartclk = 9600;
-       s->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
-       s->port.irq = s->spi->irq;
-       s->port.type = PORT_MAX3107;
-
-       /* Add UART port */
-       retval = uart_add_one_port(&max3107_uart_driver, &s->port);
-       if (retval < 0) {
-               dev_err(&s->spi->dev, "Adding UART port failed\n");
-               goto err_free1;
-       }
-
-       if (pdata->configure) {
-               retval = pdata->configure(s);
-               if (retval < 0)
-                       goto err_free1;
-       }
-
-       /* Go to suspend mode */
-       if (pdata->hw_suspend)
-               pdata->hw_suspend(s, 1);
-
-       return 0;
-
-err_free1:
-       kfree(s->txbuf);
-err_free2:
-       kfree(s->rxstr);
-err_free3:
-       kfree(s->rxbuf);
-err_free4:
-       kfree(s);
-       return retval;
-}
-EXPORT_SYMBOL_GPL(max3107_probe);
-
-/* Driver remove function */
-int max3107_remove(struct spi_device *spi)
-{
-       struct max3107_port *s = dev_get_drvdata(&spi->dev);
-
-       pr_info("enter max3107 remove\n");
-
-       /* Remove port */
-       if (uart_remove_one_port(&max3107_uart_driver, &s->port))
-               dev_warn(&s->spi->dev, "Removing UART port failed\n");
-
-
-       /* Free TxRx buffer */
-       kfree(s->rxbuf);
-       kfree(s->rxstr);
-       kfree(s->txbuf);
-
-       /* Free port structure */
-       kfree(s);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(max3107_remove);
-
-/* Driver suspend function */
-int max3107_suspend(struct spi_device *spi, pm_message_t state)
-{
-#ifdef CONFIG_PM
-       struct max3107_port *s = dev_get_drvdata(&spi->dev);
-
-       pr_debug("enter suspend\n");
-
-       /* Suspend UART port */
-       uart_suspend_port(&max3107_uart_driver, &s->port);
-
-       /* Go to suspend mode */
-       if (s->pdata->hw_suspend)
-               s->pdata->hw_suspend(s, 1);
-#endif /* CONFIG_PM */
-       return 0;
-}
-EXPORT_SYMBOL_GPL(max3107_suspend);
-
-/* Driver resume function */
-int max3107_resume(struct spi_device *spi)
-{
-#ifdef CONFIG_PM
-       struct max3107_port *s = dev_get_drvdata(&spi->dev);
-
-       pr_debug("enter resume\n");
-
-       /* Resume from suspend */
-       if (s->pdata->hw_suspend)
-               s->pdata->hw_suspend(s, 0);
-
-       /* Resume UART port */
-       uart_resume_port(&max3107_uart_driver, &s->port);
-#endif /* CONFIG_PM */
-       return 0;
-}
-EXPORT_SYMBOL_GPL(max3107_resume);
-
-static int max3107_probe_generic(struct spi_device *spi)
-{
-       return max3107_probe(spi, &generic_plat_data);
-}
-
-/* Spi driver data */
-static struct spi_driver max3107_driver = {
-       .driver = {
-               .name           = "max3107",
-               .bus            = &spi_bus_type,
-               .owner          = THIS_MODULE,
-       },
-       .probe          = max3107_probe_generic,
-       .remove         = __devexit_p(max3107_remove),
-       .suspend        = max3107_suspend,
-       .resume         = max3107_resume,
-};
-
-/* Driver init function */
-static int __init max3107_init(void)
-{
-       pr_info("enter max3107 init\n");
-       return spi_register_driver(&max3107_driver);
-}
-
-/* Driver exit function */
-static void __exit max3107_exit(void)
-{
-       pr_info("enter max3107 exit\n");
-       /* Unregister UART driver */
-       if (driver_registered)
-               uart_unregister_driver(&max3107_uart_driver);
-       spi_unregister_driver(&max3107_driver);
-}
-
-module_init(max3107_init);
-module_exit(max3107_exit);
-
-MODULE_DESCRIPTION("MAX3107 driver");
-MODULE_AUTHOR("Aavamobile");
-MODULE_ALIAS("max3107-spi");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/serial/max3107.h b/drivers/serial/max3107.h
deleted file mode 100644 (file)
index 7ab6323..0000000
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
- * max3107.h - spi uart protocol driver header for Maxim 3107
- *
- * Copyright (C) Aavamobile 2009
- * Based on serial_max3100.h by Christian Pellegrin
- *
- * 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.
- */
-
-#ifndef _MAX3107_H
-#define _MAX3107_H
-
-/* Serial error status definitions */
-#define MAX3107_PARITY_ERROR   1
-#define MAX3107_FRAME_ERROR    2
-#define MAX3107_OVERRUN_ERROR  4
-#define MAX3107_ALL_ERRORS     (MAX3107_PARITY_ERROR | \
-                                MAX3107_FRAME_ERROR | \
-                                MAX3107_OVERRUN_ERROR)
-
-/* GPIO definitions */
-#define MAX3107_GPIO_BASE      88
-#define MAX3107_GPIO_COUNT     4
-
-
-/* GPIO connected to chip's reset pin */
-#define MAX3107_RESET_GPIO     87
-
-
-/* Chip reset delay */
-#define MAX3107_RESET_DELAY    10
-
-/* Chip wakeup delay */
-#define MAX3107_WAKEUP_DELAY   50
-
-
-/* Sleep mode definitions */
-#define MAX3107_DISABLE_FORCED_SLEEP   0
-#define MAX3107_ENABLE_FORCED_SLEEP    1
-#define MAX3107_DISABLE_AUTOSLEEP      2
-#define MAX3107_ENABLE_AUTOSLEEP       3
-
-
-/* Definitions for register access with SPI transfers
- *
- * SPI transfer format:
- *
- * Master to slave bits xzzzzzzzyyyyyyyy
- * Slave to master bits aaaaaaaabbbbbbbb
- *
- * where:
- * x = 0 for reads, 1 for writes
- * z = register address
- * y = new register value if write, 0 if read
- * a = unspecified
- * b = register value if read, unspecified if write
- */
-
-/* SPI speed */
-#define MAX3107_SPI_SPEED      (3125000 * 2)
-
-/* Write bit */
-#define MAX3107_WRITE_BIT      (1 << 15)
-
-/* SPI TX data mask */
-#define MAX3107_SPI_RX_DATA_MASK       (0x00ff)
-
-/* SPI RX data mask */
-#define MAX3107_SPI_TX_DATA_MASK       (0x00ff)
-
-/* Register access masks */
-#define MAX3107_RHR_REG                        (0x0000) /* RX FIFO */
-#define MAX3107_THR_REG                        (0x0000) /* TX FIFO */
-#define MAX3107_IRQEN_REG              (0x0100) /* IRQ enable */
-#define MAX3107_IRQSTS_REG             (0x0200) /* IRQ status */
-#define MAX3107_LSR_IRQEN_REG          (0x0300) /* LSR IRQ enable */
-#define MAX3107_LSR_IRQSTS_REG         (0x0400) /* LSR IRQ status */
-#define MAX3107_SPCHR_IRQEN_REG                (0x0500) /* Special char IRQ enable */
-#define MAX3107_SPCHR_IRQSTS_REG       (0x0600) /* Special char IRQ status */
-#define MAX3107_STS_IRQEN_REG          (0x0700) /* Status IRQ enable */
-#define MAX3107_STS_IRQSTS_REG         (0x0800) /* Status IRQ status */
-#define MAX3107_MODE1_REG              (0x0900) /* MODE1 */
-#define MAX3107_MODE2_REG              (0x0a00) /* MODE2 */
-#define MAX3107_LCR_REG                        (0x0b00) /* LCR */
-#define MAX3107_RXTO_REG               (0x0c00) /* RX timeout */
-#define MAX3107_HDPIXDELAY_REG         (0x0d00) /* Auto transceiver delays */
-#define MAX3107_IRDA_REG               (0x0e00) /* IRDA settings */
-#define MAX3107_FLOWLVL_REG            (0x0f00) /* Flow control levels */
-#define MAX3107_FIFOTRIGLVL_REG                (0x1000) /* FIFO IRQ trigger levels */
-#define MAX3107_TXFIFOLVL_REG          (0x1100) /* TX FIFO level */
-#define MAX3107_RXFIFOLVL_REG          (0x1200) /* RX FIFO level */
-#define MAX3107_FLOWCTRL_REG           (0x1300) /* Flow control */
-#define MAX3107_XON1_REG               (0x1400) /* XON1 character */
-#define MAX3107_XON2_REG               (0x1500) /* XON2 character */
-#define MAX3107_XOFF1_REG              (0x1600) /* XOFF1 character */
-#define MAX3107_XOFF2_REG              (0x1700) /* XOFF2 character */
-#define MAX3107_GPIOCFG_REG            (0x1800) /* GPIO config */
-#define MAX3107_GPIODATA_REG           (0x1900) /* GPIO data */
-#define MAX3107_PLLCFG_REG             (0x1a00) /* PLL config */
-#define MAX3107_BRGCFG_REG             (0x1b00) /* Baud rate generator conf */
-#define MAX3107_BRGDIVLSB_REG          (0x1c00) /* Baud rate divisor LSB */
-#define MAX3107_BRGDIVMSB_REG          (0x1d00) /* Baud rate divisor MSB */
-#define MAX3107_CLKSRC_REG             (0x1e00) /* Clock source */
-#define MAX3107_REVID_REG              (0x1f00) /* Revision identification */
-
-/* IRQ register bits */
-#define MAX3107_IRQ_LSR_BIT    (1 << 0) /* LSR interrupt */
-#define MAX3107_IRQ_SPCHR_BIT  (1 << 1) /* Special char interrupt */
-#define MAX3107_IRQ_STS_BIT    (1 << 2) /* Status interrupt */
-#define MAX3107_IRQ_RXFIFO_BIT (1 << 3) /* RX FIFO interrupt */
-#define MAX3107_IRQ_TXFIFO_BIT (1 << 4) /* TX FIFO interrupt */
-#define MAX3107_IRQ_TXEMPTY_BIT        (1 << 5) /* TX FIFO empty interrupt */
-#define MAX3107_IRQ_RXEMPTY_BIT        (1 << 6) /* RX FIFO empty interrupt */
-#define MAX3107_IRQ_CTS_BIT    (1 << 7) /* CTS interrupt */
-
-/* LSR register bits */
-#define MAX3107_LSR_RXTO_BIT   (1 << 0) /* RX timeout */
-#define MAX3107_LSR_RXOVR_BIT  (1 << 1) /* RX overrun */
-#define MAX3107_LSR_RXPAR_BIT  (1 << 2) /* RX parity error */
-#define MAX3107_LSR_FRERR_BIT  (1 << 3) /* Frame error */
-#define MAX3107_LSR_RXBRK_BIT  (1 << 4) /* RX break */
-#define MAX3107_LSR_RXNOISE_BIT        (1 << 5) /* RX noise */
-#define MAX3107_LSR_UNDEF6_BIT (1 << 6) /* Undefined/not used */
-#define MAX3107_LSR_CTS_BIT    (1 << 7) /* CTS pin state */
-
-/* Special character register bits */
-#define MAX3107_SPCHR_XON1_BIT         (1 << 0) /* XON1 character */
-#define MAX3107_SPCHR_XON2_BIT         (1 << 1) /* XON2 character */
-#define MAX3107_SPCHR_XOFF1_BIT                (1 << 2) /* XOFF1 character */
-#define MAX3107_SPCHR_XOFF2_BIT                (1 << 3) /* XOFF2 character */
-#define MAX3107_SPCHR_BREAK_BIT                (1 << 4) /* RX break */
-#define MAX3107_SPCHR_MULTIDROP_BIT    (1 << 5) /* 9-bit multidrop addr char */
-#define MAX3107_SPCHR_UNDEF6_BIT       (1 << 6) /* Undefined/not used */
-#define MAX3107_SPCHR_UNDEF7_BIT       (1 << 7) /* Undefined/not used */
-
-/* Status register bits */
-#define MAX3107_STS_GPIO0_BIT          (1 << 0) /* GPIO 0 interrupt */
-#define MAX3107_STS_GPIO1_BIT          (1 << 1) /* GPIO 1 interrupt */
-#define MAX3107_STS_GPIO2_BIT          (1 << 2) /* GPIO 2 interrupt */
-#define MAX3107_STS_GPIO3_BIT          (1 << 3) /* GPIO 3 interrupt */
-#define MAX3107_STS_UNDEF4_BIT         (1 << 4) /* Undefined/not used */
-#define MAX3107_STS_CLKREADY_BIT       (1 << 5) /* Clock ready */
-#define MAX3107_STS_SLEEP_BIT          (1 << 6) /* Sleep interrupt */
-#define MAX3107_STS_UNDEF7_BIT         (1 << 7) /* Undefined/not used */
-
-/* MODE1 register bits */
-#define MAX3107_MODE1_RXDIS_BIT                (1 << 0) /* RX disable */
-#define MAX3107_MODE1_TXDIS_BIT                (1 << 1) /* TX disable */
-#define MAX3107_MODE1_TXHIZ_BIT                (1 << 2) /* TX pin three-state */
-#define MAX3107_MODE1_RTSHIZ_BIT       (1 << 3) /* RTS pin three-state */
-#define MAX3107_MODE1_TRNSCVCTRL_BIT   (1 << 4) /* Transceiver ctrl enable */
-#define MAX3107_MODE1_FORCESLEEP_BIT   (1 << 5) /* Force sleep mode */
-#define MAX3107_MODE1_AUTOSLEEP_BIT    (1 << 6) /* Auto sleep enable */
-#define MAX3107_MODE1_IRQSEL_BIT       (1 << 7) /* IRQ pin enable */
-
-/* MODE2 register bits */
-#define MAX3107_MODE2_RST_BIT          (1 << 0) /* Chip reset */
-#define MAX3107_MODE2_FIFORST_BIT      (1 << 1) /* FIFO reset */
-#define MAX3107_MODE2_RXTRIGINV_BIT    (1 << 2) /* RX FIFO INT invert */
-#define MAX3107_MODE2_RXEMPTINV_BIT    (1 << 3) /* RX FIFO empty INT invert */
-#define MAX3107_MODE2_SPCHR_BIT                (1 << 4) /* Special chr detect enable */
-#define MAX3107_MODE2_LOOPBACK_BIT     (1 << 5) /* Internal loopback enable */
-#define MAX3107_MODE2_MULTIDROP_BIT    (1 << 6) /* 9-bit multidrop enable */
-#define MAX3107_MODE2_ECHOSUPR_BIT     (1 << 7) /* ECHO suppression enable */
-
-/* LCR register bits */
-#define MAX3107_LCR_LENGTH0_BIT                (1 << 0) /* Word length bit 0 */
-#define MAX3107_LCR_LENGTH1_BIT                (1 << 1) /* Word length bit 1
-                                                 *
-                                                 * Word length bits table:
-                                                 * 00 -> 5 bit words
-                                                 * 01 -> 6 bit words
-                                                 * 10 -> 7 bit words
-                                                 * 11 -> 8 bit words
-                                                 */
-#define MAX3107_LCR_STOPLEN_BIT                (1 << 2) /* STOP length bit
-                                                 *
-                                                 * STOP length bit table:
-                                                 * 0 -> 1 stop bit
-                                                 * 1 -> 1-1.5 stop bits if
-                                                 *      word length is 5,
-                                                 *      2 stop bits otherwise
-                                                 */
-#define MAX3107_LCR_PARITY_BIT         (1 << 3) /* Parity bit enable */
-#define MAX3107_LCR_EVENPARITY_BIT     (1 << 4) /* Even parity bit enable */
-#define MAX3107_LCR_FORCEPARITY_BIT    (1 << 5) /* 9-bit multidrop parity */
-#define MAX3107_LCR_TXBREAK_BIT                (1 << 6) /* TX break enable */
-#define MAX3107_LCR_RTS_BIT            (1 << 7) /* RTS pin control */
-#define MAX3107_LCR_WORD_LEN_5         (0x0000)
-#define MAX3107_LCR_WORD_LEN_6         (0x0001)
-#define MAX3107_LCR_WORD_LEN_7         (0x0002)
-#define MAX3107_LCR_WORD_LEN_8         (0x0003)
-
-
-/* IRDA register bits */
-#define MAX3107_IRDA_IRDAEN_BIT                (1 << 0) /* IRDA mode enable */
-#define MAX3107_IRDA_SIR_BIT           (1 << 1) /* SIR mode enable */
-#define MAX3107_IRDA_SHORTIR_BIT       (1 << 2) /* Short SIR mode enable */
-#define MAX3107_IRDA_MIR_BIT           (1 << 3) /* MIR mode enable */
-#define MAX3107_IRDA_RXINV_BIT         (1 << 4) /* RX logic inversion enable */
-#define MAX3107_IRDA_TXINV_BIT         (1 << 5) /* TX logic inversion enable */
-#define MAX3107_IRDA_UNDEF6_BIT                (1 << 6) /* Undefined/not used */
-#define MAX3107_IRDA_UNDEF7_BIT                (1 << 7) /* Undefined/not used */
-
-/* Flow control trigger level register masks */
-#define MAX3107_FLOWLVL_HALT_MASK      (0x000f) /* Flow control halt level */
-#define MAX3107_FLOWLVL_RES_MASK       (0x00f0) /* Flow control resume level */
-#define MAX3107_FLOWLVL_HALT(words)    ((words/8) & 0x000f)
-#define MAX3107_FLOWLVL_RES(words)     (((words/8) & 0x000f) << 4)
-
-/* FIFO interrupt trigger level register masks */
-#define MAX3107_FIFOTRIGLVL_TX_MASK    (0x000f) /* TX FIFO trigger level */
-#define MAX3107_FIFOTRIGLVL_RX_MASK    (0x00f0) /* RX FIFO trigger level */
-#define MAX3107_FIFOTRIGLVL_TX(words)  ((words/8) & 0x000f)
-#define MAX3107_FIFOTRIGLVL_RX(words)  (((words/8) & 0x000f) << 4)
-
-/* Flow control register bits */
-#define MAX3107_FLOWCTRL_AUTORTS_BIT   (1 << 0) /* Auto RTS flow ctrl enable */
-#define MAX3107_FLOWCTRL_AUTOCTS_BIT   (1 << 1) /* Auto CTS flow ctrl enable */
-#define MAX3107_FLOWCTRL_GPIADDR_BIT   (1 << 2) /* Enables that GPIO inputs
-                                                 * are used in conjunction with
-                                                 * XOFF2 for definition of
-                                                 * special character */
-#define MAX3107_FLOWCTRL_SWFLOWEN_BIT  (1 << 3) /* Auto SW flow ctrl enable */
-#define MAX3107_FLOWCTRL_SWFLOW0_BIT   (1 << 4) /* SWFLOW bit 0 */
-#define MAX3107_FLOWCTRL_SWFLOW1_BIT   (1 << 5) /* SWFLOW bit 1
-                                                 *
-                                                 * SWFLOW bits 1 & 0 table:
-                                                 * 00 -> no transmitter flow
-                                                 *       control
-                                                 * 01 -> receiver compares
-                                                 *       XON2 and XOFF2
-                                                 *       and controls
-                                                 *       transmitter
-                                                 * 10 -> receiver compares
-                                                 *       XON1 and XOFF1
-                                                 *       and controls
-                                                 *       transmitter
-                                                 * 11 -> receiver compares
-                                                 *       XON1, XON2, XOFF1 and
-                                                 *       XOFF2 and controls
-                                                 *       transmitter
-                                                 */
-#define MAX3107_FLOWCTRL_SWFLOW2_BIT   (1 << 6) /* SWFLOW bit 2 */
-#define MAX3107_FLOWCTRL_SWFLOW3_BIT   (1 << 7) /* SWFLOW bit 3
-                                                 *
-                                                 * SWFLOW bits 3 & 2 table:
-                                                 * 00 -> no received flow
-                                                 *       control
-                                                 * 01 -> transmitter generates
-                                                 *       XON2 and XOFF2
-                                                 * 10 -> transmitter generates
-                                                 *       XON1 and XOFF1
-                                                 * 11 -> transmitter generates
-                                                 *       XON1, XON2, XOFF1 and
-                                                 *       XOFF2
-                                                 */
-
-/* GPIO configuration register bits */
-#define MAX3107_GPIOCFG_GP0OUT_BIT     (1 << 0) /* GPIO 0 output enable */
-#define MAX3107_GPIOCFG_GP1OUT_BIT     (1 << 1) /* GPIO 1 output enable */
-#define MAX3107_GPIOCFG_GP2OUT_BIT     (1 << 2) /* GPIO 2 output enable */
-#define MAX3107_GPIOCFG_GP3OUT_BIT     (1 << 3) /* GPIO 3 output enable */
-#define MAX3107_GPIOCFG_GP0OD_BIT      (1 << 4) /* GPIO 0 open-drain enable */
-#define MAX3107_GPIOCFG_GP1OD_BIT      (1 << 5) /* GPIO 1 open-drain enable */
-#define MAX3107_GPIOCFG_GP2OD_BIT      (1 << 6) /* GPIO 2 open-drain enable */
-#define MAX3107_GPIOCFG_GP3OD_BIT      (1 << 7) /* GPIO 3 open-drain enable */
-
-/* GPIO DATA register bits */
-#define MAX3107_GPIODATA_GP0OUT_BIT    (1 << 0) /* GPIO 0 output value */
-#define MAX3107_GPIODATA_GP1OUT_BIT    (1 << 1) /* GPIO 1 output value */
-#define MAX3107_GPIODATA_GP2OUT_BIT    (1 << 2) /* GPIO 2 output value */
-#define MAX3107_GPIODATA_GP3OUT_BIT    (1 << 3) /* GPIO 3 output value */
-#define MAX3107_GPIODATA_GP0IN_BIT     (1 << 4) /* GPIO 0 input value */
-#define MAX3107_GPIODATA_GP1IN_BIT     (1 << 5) /* GPIO 1 input value */
-#define MAX3107_GPIODATA_GP2IN_BIT     (1 << 6) /* GPIO 2 input value */
-#define MAX3107_GPIODATA_GP3IN_BIT     (1 << 7) /* GPIO 3 input value */
-
-/* PLL configuration register masks */
-#define MAX3107_PLLCFG_PREDIV_MASK     (0x003f) /* PLL predivision value */
-#define MAX3107_PLLCFG_PLLFACTOR_MASK  (0x00c0) /* PLL multiplication factor */
-
-/* Baud rate generator configuration register masks and bits */
-#define MAX3107_BRGCFG_FRACT_MASK      (0x000f) /* Fractional portion of
-                                                 * Baud rate generator divisor
-                                                 */
-#define MAX3107_BRGCFG_2XMODE_BIT      (1 << 4) /* Double baud rate */
-#define MAX3107_BRGCFG_4XMODE_BIT      (1 << 5) /* Quadruple baud rate */
-#define MAX3107_BRGCFG_UNDEF6_BIT      (1 << 6) /* Undefined/not used */
-#define MAX3107_BRGCFG_UNDEF7_BIT      (1 << 7) /* Undefined/not used */
-
-/* Clock source register bits */
-#define MAX3107_CLKSRC_INTOSC_BIT      (1 << 0) /* Internal osc enable */
-#define MAX3107_CLKSRC_CRYST_BIT       (1 << 1) /* Crystal osc enable */
-#define MAX3107_CLKSRC_PLL_BIT         (1 << 2) /* PLL enable */
-#define MAX3107_CLKSRC_PLLBYP_BIT      (1 << 3) /* PLL bypass */
-#define MAX3107_CLKSRC_EXTCLK_BIT      (1 << 4) /* External clock enable */
-#define MAX3107_CLKSRC_UNDEF5_BIT      (1 << 5) /* Undefined/not used */
-#define MAX3107_CLKSRC_UNDEF6_BIT      (1 << 6) /* Undefined/not used */
-#define MAX3107_CLKSRC_CLK2RTS_BIT     (1 << 7) /* Baud clk to RTS pin */
-
-
-/* HW definitions */
-#define MAX3107_RX_FIFO_SIZE   128
-#define MAX3107_TX_FIFO_SIZE   128
-#define MAX3107_REVID1         0x00a0
-#define MAX3107_REVID2         0x00a1
-
-
-/* Baud rate generator configuration values for external clock 13MHz */
-#define MAX3107_BRG13_B300     (0x0A9400 | 0x05)
-#define MAX3107_BRG13_B600     (0x054A00 | 0x03)
-#define MAX3107_BRG13_B1200    (0x02A500 | 0x01)
-#define MAX3107_BRG13_B2400    (0x015200 | 0x09)
-#define MAX3107_BRG13_B4800    (0x00A900 | 0x04)
-#define MAX3107_BRG13_B9600    (0x005400 | 0x0A)
-#define MAX3107_BRG13_B19200   (0x002A00 | 0x05)
-#define MAX3107_BRG13_B38400   (0x001500 | 0x03)
-#define MAX3107_BRG13_B57600   (0x000E00 | 0x02)
-#define MAX3107_BRG13_B115200  (0x000700 | 0x01)
-#define MAX3107_BRG13_B230400  (0x000300 | 0x08)
-#define MAX3107_BRG13_B460800  (0x000100 | 0x0c)
-#define MAX3107_BRG13_B921600  (0x000100 | 0x1c)
-
-/* Baud rate generator configuration values for external clock 26MHz */
-#define MAX3107_BRG26_B300     (0x152800 | 0x0A)
-#define MAX3107_BRG26_B600     (0x0A9400 | 0x05)
-#define MAX3107_BRG26_B1200    (0x054A00 | 0x03)
-#define MAX3107_BRG26_B2400    (0x02A500 | 0x01)
-#define MAX3107_BRG26_B4800    (0x015200 | 0x09)
-#define MAX3107_BRG26_B9600    (0x00A900 | 0x04)
-#define MAX3107_BRG26_B19200   (0x005400 | 0x0A)
-#define MAX3107_BRG26_B38400   (0x002A00 | 0x05)
-#define MAX3107_BRG26_B57600   (0x001C00 | 0x03)
-#define MAX3107_BRG26_B115200  (0x000E00 | 0x02)
-#define MAX3107_BRG26_B230400  (0x000700 | 0x01)
-#define MAX3107_BRG26_B460800  (0x000300 | 0x08)
-#define MAX3107_BRG26_B921600  (0x000100 | 0x0C)
-
-/* Baud rate generator configuration values for internal clock */
-#define MAX3107_BRG13_IB300    (0x008000 | 0x00)
-#define MAX3107_BRG13_IB600    (0x004000 | 0x00)
-#define MAX3107_BRG13_IB1200   (0x002000 | 0x00)
-#define MAX3107_BRG13_IB2400   (0x001000 | 0x00)
-#define MAX3107_BRG13_IB4800   (0x000800 | 0x00)
-#define MAX3107_BRG13_IB9600   (0x000400 | 0x00)
-#define MAX3107_BRG13_IB19200  (0x000200 | 0x00)
-#define MAX3107_BRG13_IB38400  (0x000100 | 0x00)
-#define MAX3107_BRG13_IB57600  (0x000000 | 0x0B)
-#define MAX3107_BRG13_IB115200 (0x000000 | 0x05)
-#define MAX3107_BRG13_IB230400 (0x000000 | 0x03)
-#define MAX3107_BRG13_IB460800 (0x000000 | 0x00)
-#define MAX3107_BRG13_IB921600 (0x000000 | 0x00)
-
-
-struct baud_table {
-       int baud;
-       u32 new_brg;
-};
-
-struct max3107_port {
-       /* UART port structure */
-       struct uart_port port;
-
-       /* SPI device structure */
-       struct spi_device *spi;
-
-#if defined(CONFIG_GPIOLIB)
-       /* GPIO chip stucture */
-       struct gpio_chip chip;
-#endif
-
-       /* Workqueue that does all the magic */
-       struct workqueue_struct *workqueue;
-       struct work_struct work;
-
-       /* Lock for shared data */
-       spinlock_t data_lock;
-
-       /* Device configuration */
-       int ext_clk;            /* 1 if external clock used */
-       int loopback;           /* Current loopback mode state */
-       int baud;                       /* Current baud rate */
-
-       /* State flags */
-       int suspended;          /* Indicates suspend mode */
-       int tx_fifo_empty;      /* Flag for TX FIFO state */
-       int rx_enabled;         /* Flag for receiver state */
-       int tx_enabled;         /* Flag for transmitter state */
-
-       u16 irqen_reg;          /* Current IRQ enable register value */
-       /* Shared data */
-       u16 mode1_reg;          /* Current mode1 register value*/
-       int mode1_commit;       /* Flag for setting new mode1 register value */
-       u16 lcr_reg;            /* Current LCR register value */
-       int lcr_commit;         /* Flag for setting new LCR register value */
-       u32 brg_cfg;            /* Current Baud rate generator config  */
-       int brg_commit;         /* Flag for setting new baud rate generator
-                                * config
-                                */
-       struct baud_table *baud_tbl;
-       int handle_irq;         /* Indicates that IRQ should be handled */
-
-       /* Rx buffer and str*/
-       u16 *rxbuf;
-       u8  *rxstr;
-       /* Tx buffer*/
-       u16 *txbuf;
-
-       struct max3107_plat *pdata;     /* Platform data */
-};
-
-/* Platform data structure */
-struct max3107_plat {
-       /* Loopback mode enable */
-       int loopback;
-       /* External clock enable */
-       int ext_clk;
-       /* Called during the register initialisation */
-       void (*init)(struct max3107_port *s);
-       /* Called when the port is found and configured */
-       int (*configure)(struct max3107_port *s);
-       /* HW suspend function */
-       void (*hw_suspend) (struct max3107_port *s, int suspend);
-       /* Polling mode enable */
-       int polled_mode;
-       /* Polling period if polling mode enabled */
-       int poll_time;
-};
-
-extern int max3107_rw(struct max3107_port *s, u8 *tx, u8 *rx, int len);
-extern void max3107_hw_susp(struct max3107_port *s, int suspend);
-extern int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata);
-extern int max3107_remove(struct spi_device *spi);
-extern int max3107_suspend(struct spi_device *spi, pm_message_t state);
-extern int max3107_resume(struct spi_device *spi);
-
-#endif /* _LINUX_SERIAL_MAX3107_H */
diff --git a/drivers/serial/mcf.c b/drivers/serial/mcf.c
deleted file mode 100644 (file)
index 3394b7c..0000000
+++ /dev/null
@@ -1,662 +0,0 @@
-/****************************************************************************/
-
-/*
- *     mcf.c -- Freescale ColdFire UART driver
- *
- *     (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
- *
- * 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.
- */
-
-/****************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/console.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <linux/io.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-#include <asm/nettel.h>
-
-/****************************************************************************/
-
-/*
- *     Some boards implement the DTR/DCD lines using GPIO lines, most
- *     don't. Dummy out the access macros for those that don't. Those
- *     that do should define these macros somewhere in there board
- *     specific inlude files.
- */
-#if !defined(mcf_getppdcd)
-#define        mcf_getppdcd(p)         (1)
-#endif
-#if !defined(mcf_getppdtr)
-#define        mcf_getppdtr(p)         (1)
-#endif
-#if !defined(mcf_setppdtr)
-#define        mcf_setppdtr(p, v)      do { } while (0)
-#endif
-
-/****************************************************************************/
-
-/*
- *     Local per-uart structure.
- */
-struct mcf_uart {
-       struct uart_port        port;
-       unsigned int            sigs;           /* Local copy of line sigs */
-       unsigned char           imr;            /* Local IMR mirror */
-};
-
-/****************************************************************************/
-
-static unsigned int mcf_tx_empty(struct uart_port *port)
-{
-       return (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXEMPTY) ?
-               TIOCSER_TEMT : 0;
-}
-
-/****************************************************************************/
-
-static unsigned int mcf_get_mctrl(struct uart_port *port)
-{
-       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
-       unsigned int sigs;
-
-       sigs = (readb(port->membase + MCFUART_UIPR) & MCFUART_UIPR_CTS) ?
-               0 : TIOCM_CTS;
-       sigs |= (pp->sigs & TIOCM_RTS);
-       sigs |= (mcf_getppdcd(port->line) ? TIOCM_CD : 0);
-       sigs |= (mcf_getppdtr(port->line) ? TIOCM_DTR : 0);
-
-       return sigs;
-}
-
-/****************************************************************************/
-
-static void mcf_set_mctrl(struct uart_port *port, unsigned int sigs)
-{
-       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
-
-       pp->sigs = sigs;
-       mcf_setppdtr(port->line, (sigs & TIOCM_DTR));
-       if (sigs & TIOCM_RTS)
-               writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP1);
-       else
-               writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP0);
-}
-
-/****************************************************************************/
-
-static void mcf_start_tx(struct uart_port *port)
-{
-       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
-
-       pp->imr |= MCFUART_UIR_TXREADY;
-       writeb(pp->imr, port->membase + MCFUART_UIMR);
-}
-
-/****************************************************************************/
-
-static void mcf_stop_tx(struct uart_port *port)
-{
-       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
-
-       pp->imr &= ~MCFUART_UIR_TXREADY;
-       writeb(pp->imr, port->membase + MCFUART_UIMR);
-}
-
-/****************************************************************************/
-
-static void mcf_stop_rx(struct uart_port *port)
-{
-       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
-
-       pp->imr &= ~MCFUART_UIR_RXREADY;
-       writeb(pp->imr, port->membase + MCFUART_UIMR);
-}
-
-/****************************************************************************/
-
-static void mcf_break_ctl(struct uart_port *port, int break_state)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       if (break_state == -1)
-               writeb(MCFUART_UCR_CMDBREAKSTART, port->membase + MCFUART_UCR);
-       else
-               writeb(MCFUART_UCR_CMDBREAKSTOP, port->membase + MCFUART_UCR);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/****************************************************************************/
-
-static void mcf_enable_ms(struct uart_port *port)
-{
-}
-
-/****************************************************************************/
-
-static int mcf_startup(struct uart_port *port)
-{
-       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /* Reset UART, get it into known state... */
-       writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
-       writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
-
-       /* Enable the UART transmitter and receiver */
-       writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE,
-               port->membase + MCFUART_UCR);
-
-       /* Enable RX interrupts now */
-       pp->imr = MCFUART_UIR_RXREADY;
-       writeb(pp->imr, port->membase + MCFUART_UIMR);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       return 0;
-}
-
-/****************************************************************************/
-
-static void mcf_shutdown(struct uart_port *port)
-{
-       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /* Disable all interrupts now */
-       pp->imr = 0;
-       writeb(pp->imr, port->membase + MCFUART_UIMR);
-
-       /* Disable UART transmitter and receiver */
-       writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
-       writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/****************************************************************************/
-
-static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
-       struct ktermios *old)
-{
-       unsigned long flags;
-       unsigned int baud, baudclk;
-#if defined(CONFIG_M5272)
-       unsigned int baudfr;
-#endif
-       unsigned char mr1, mr2;
-
-       baud = uart_get_baud_rate(port, termios, old, 0, 230400);
-#if defined(CONFIG_M5272)
-       baudclk = (MCF_BUSCLK / baud) / 32;
-       baudfr = (((MCF_BUSCLK / baud) + 1) / 2) % 16;
-#else
-       baudclk = ((MCF_BUSCLK / baud) + 16) / 32;
-#endif
-
-       mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR;
-       mr2 = 0;
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5: mr1 |= MCFUART_MR1_CS5; break;
-       case CS6: mr1 |= MCFUART_MR1_CS6; break;
-       case CS7: mr1 |= MCFUART_MR1_CS7; break;
-       case CS8:
-       default:  mr1 |= MCFUART_MR1_CS8; break;
-       }
-
-       if (termios->c_cflag & PARENB) {
-               if (termios->c_cflag & CMSPAR) {
-                       if (termios->c_cflag & PARODD)
-                               mr1 |= MCFUART_MR1_PARITYMARK;
-                       else
-                               mr1 |= MCFUART_MR1_PARITYSPACE;
-               } else {
-                       if (termios->c_cflag & PARODD)
-                               mr1 |= MCFUART_MR1_PARITYODD;
-                       else
-                               mr1 |= MCFUART_MR1_PARITYEVEN;
-               }
-       } else {
-               mr1 |= MCFUART_MR1_PARITYNONE;
-       }
-
-       if (termios->c_cflag & CSTOPB)
-               mr2 |= MCFUART_MR2_STOP2;
-       else
-               mr2 |= MCFUART_MR2_STOP1;
-
-       if (termios->c_cflag & CRTSCTS) {
-               mr1 |= MCFUART_MR1_RXRTS;
-               mr2 |= MCFUART_MR2_TXCTS;
-       }
-
-       spin_lock_irqsave(&port->lock, flags);
-       uart_update_timeout(port, termios->c_cflag, baud);
-       writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
-       writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
-       writeb(MCFUART_UCR_CMDRESETMRPTR, port->membase + MCFUART_UCR);
-       writeb(mr1, port->membase + MCFUART_UMR);
-       writeb(mr2, port->membase + MCFUART_UMR);
-       writeb((baudclk & 0xff00) >> 8, port->membase + MCFUART_UBG1);
-       writeb((baudclk & 0xff), port->membase + MCFUART_UBG2);
-#if defined(CONFIG_M5272)
-       writeb((baudfr & 0x0f), port->membase + MCFUART_UFPD);
-#endif
-       writeb(MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER,
-               port->membase + MCFUART_UCSR);
-       writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE,
-               port->membase + MCFUART_UCR);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/****************************************************************************/
-
-static void mcf_rx_chars(struct mcf_uart *pp)
-{
-       struct uart_port *port = &pp->port;
-       unsigned char status, ch, flag;
-
-       while ((status = readb(port->membase + MCFUART_USR)) & MCFUART_USR_RXREADY) {
-               ch = readb(port->membase + MCFUART_URB);
-               flag = TTY_NORMAL;
-               port->icount.rx++;
-
-               if (status & MCFUART_USR_RXERR) {
-                       writeb(MCFUART_UCR_CMDRESETERR,
-                               port->membase + MCFUART_UCR);
-
-                       if (status & MCFUART_USR_RXBREAK) {
-                               port->icount.brk++;
-                               if (uart_handle_break(port))
-                                       continue;
-                       } else if (status & MCFUART_USR_RXPARITY) {
-                               port->icount.parity++;
-                       } else if (status & MCFUART_USR_RXOVERRUN) {
-                               port->icount.overrun++;
-                       } else if (status & MCFUART_USR_RXFRAMING) {
-                               port->icount.frame++;
-                       }
-
-                       status &= port->read_status_mask;
-
-                       if (status & MCFUART_USR_RXBREAK)
-                               flag = TTY_BREAK;
-                       else if (status & MCFUART_USR_RXPARITY)
-                               flag = TTY_PARITY;
-                       else if (status & MCFUART_USR_RXFRAMING)
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(port, ch))
-                       continue;
-               uart_insert_char(port, status, MCFUART_USR_RXOVERRUN, ch, flag);
-       }
-
-       tty_flip_buffer_push(port->state->port.tty);
-}
-
-/****************************************************************************/
-
-static void mcf_tx_chars(struct mcf_uart *pp)
-{
-       struct uart_port *port = &pp->port;
-       struct circ_buf *xmit = &port->state->xmit;
-
-       if (port->x_char) {
-               /* Send special char - probably flow control */
-               writeb(port->x_char, port->membase + MCFUART_UTB);
-               port->x_char = 0;
-               port->icount.tx++;
-               return;
-       }
-
-       while (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) {
-               if (xmit->head == xmit->tail)
-                       break;
-               writeb(xmit->buf[xmit->tail], port->membase + MCFUART_UTB);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1);
-               port->icount.tx++;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (xmit->head == xmit->tail) {
-               pp->imr &= ~MCFUART_UIR_TXREADY;
-               writeb(pp->imr, port->membase + MCFUART_UIMR);
-       }
-}
-
-/****************************************************************************/
-
-static irqreturn_t mcf_interrupt(int irq, void *data)
-{
-       struct uart_port *port = data;
-       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
-       unsigned int isr;
-       irqreturn_t ret = IRQ_NONE;
-
-       isr = readb(port->membase + MCFUART_UISR) & pp->imr;
-
-       spin_lock(&port->lock);
-       if (isr & MCFUART_UIR_RXREADY) {
-               mcf_rx_chars(pp);
-               ret = IRQ_HANDLED;
-       }
-       if (isr & MCFUART_UIR_TXREADY) {
-               mcf_tx_chars(pp);
-               ret = IRQ_HANDLED;
-       }
-       spin_unlock(&port->lock);
-
-       return ret;
-}
-
-/****************************************************************************/
-
-static void mcf_config_port(struct uart_port *port, int flags)
-{
-       port->type = PORT_MCF;
-       port->fifosize = MCFUART_TXFIFOSIZE;
-
-       /* Clear mask, so no surprise interrupts. */
-       writeb(0, port->membase + MCFUART_UIMR);
-
-       if (request_irq(port->irq, mcf_interrupt, IRQF_DISABLED, "UART", port))
-               printk(KERN_ERR "MCF: unable to attach ColdFire UART %d "
-                       "interrupt vector=%d\n", port->line, port->irq);
-}
-
-/****************************************************************************/
-
-static const char *mcf_type(struct uart_port *port)
-{
-       return (port->type == PORT_MCF) ? "ColdFire UART" : NULL;
-}
-
-/****************************************************************************/
-
-static int mcf_request_port(struct uart_port *port)
-{
-       /* UARTs always present */
-       return 0;
-}
-
-/****************************************************************************/
-
-static void mcf_release_port(struct uart_port *port)
-{
-       /* Nothing to release... */
-}
-
-/****************************************************************************/
-
-static int mcf_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_MCF))
-               return -EINVAL;
-       return 0;
-}
-
-/****************************************************************************/
-
-/*
- *     Define the basic serial functions we support.
- */
-static const struct uart_ops mcf_uart_ops = {
-       .tx_empty       = mcf_tx_empty,
-       .get_mctrl      = mcf_get_mctrl,
-       .set_mctrl      = mcf_set_mctrl,
-       .start_tx       = mcf_start_tx,
-       .stop_tx        = mcf_stop_tx,
-       .stop_rx        = mcf_stop_rx,
-       .enable_ms      = mcf_enable_ms,
-       .break_ctl      = mcf_break_ctl,
-       .startup        = mcf_startup,
-       .shutdown       = mcf_shutdown,
-       .set_termios    = mcf_set_termios,
-       .type           = mcf_type,
-       .request_port   = mcf_request_port,
-       .release_port   = mcf_release_port,
-       .config_port    = mcf_config_port,
-       .verify_port    = mcf_verify_port,
-};
-
-static struct mcf_uart mcf_ports[4];
-
-#define        MCF_MAXPORTS    ARRAY_SIZE(mcf_ports)
-
-/****************************************************************************/
-#if defined(CONFIG_SERIAL_MCF_CONSOLE)
-/****************************************************************************/
-
-int __init early_mcf_setup(struct mcf_platform_uart *platp)
-{
-       struct uart_port *port;
-       int i;
-
-       for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) {
-               port = &mcf_ports[i].port;
-
-               port->line = i;
-               port->type = PORT_MCF;
-               port->mapbase = platp[i].mapbase;
-               port->membase = (platp[i].membase) ? platp[i].membase :
-                       (unsigned char __iomem *) port->mapbase;
-               port->iotype = SERIAL_IO_MEM;
-               port->irq = platp[i].irq;
-               port->uartclk = MCF_BUSCLK;
-               port->flags = ASYNC_BOOT_AUTOCONF;
-               port->ops = &mcf_uart_ops;
-       }
-
-       return 0;
-}
-
-/****************************************************************************/
-
-static void mcf_console_putc(struct console *co, const char c)
-{
-       struct uart_port *port = &(mcf_ports + co->index)->port;
-       int i;
-
-       for (i = 0; (i < 0x10000); i++) {
-               if (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY)
-                       break;
-       }
-       writeb(c, port->membase + MCFUART_UTB);
-       for (i = 0; (i < 0x10000); i++) {
-               if (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY)
-                       break;
-       }
-}
-
-/****************************************************************************/
-
-static void mcf_console_write(struct console *co, const char *s, unsigned int count)
-{
-       for (; (count); count--, s++) {
-               mcf_console_putc(co, *s);
-               if (*s == '\n')
-                       mcf_console_putc(co, '\r');
-       }
-}
-
-/****************************************************************************/
-
-static int __init mcf_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port;
-       int baud = CONFIG_SERIAL_MCF_BAUDRATE;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       if ((co->index < 0) || (co->index >= MCF_MAXPORTS))
-               co->index = 0;
-       port = &mcf_ports[co->index].port;
-       if (port->membase == 0)
-               return -ENODEV;
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-/****************************************************************************/
-
-static struct uart_driver mcf_driver;
-
-static struct console mcf_console = {
-       .name           = "ttyS",
-       .write          = mcf_console_write,
-       .device         = uart_console_device,
-       .setup          = mcf_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &mcf_driver,
-};
-
-static int __init mcf_console_init(void)
-{
-       register_console(&mcf_console);
-       return 0;
-}
-
-console_initcall(mcf_console_init);
-
-#define        MCF_CONSOLE     &mcf_console
-
-/****************************************************************************/
-#else
-/****************************************************************************/
-
-#define        MCF_CONSOLE     NULL
-
-/****************************************************************************/
-#endif /* CONFIG_MCF_CONSOLE */
-/****************************************************************************/
-
-/*
- *     Define the mcf UART driver structure.
- */
-static struct uart_driver mcf_driver = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "mcf",
-       .dev_name       = "ttyS",
-       .major          = TTY_MAJOR,
-       .minor          = 64,
-       .nr             = MCF_MAXPORTS,
-       .cons           = MCF_CONSOLE,
-};
-
-/****************************************************************************/
-
-static int __devinit mcf_probe(struct platform_device *pdev)
-{
-       struct mcf_platform_uart *platp = pdev->dev.platform_data;
-       struct uart_port *port;
-       int i;
-
-       for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) {
-               port = &mcf_ports[i].port;
-
-               port->line = i;
-               port->type = PORT_MCF;
-               port->mapbase = platp[i].mapbase;
-               port->membase = (platp[i].membase) ? platp[i].membase :
-                       (unsigned char __iomem *) platp[i].mapbase;
-               port->iotype = SERIAL_IO_MEM;
-               port->irq = platp[i].irq;
-               port->uartclk = MCF_BUSCLK;
-               port->ops = &mcf_uart_ops;
-               port->flags = ASYNC_BOOT_AUTOCONF;
-
-               uart_add_one_port(&mcf_driver, port);
-       }
-
-       return 0;
-}
-
-/****************************************************************************/
-
-static int __devexit mcf_remove(struct platform_device *pdev)
-{
-       struct uart_port *port;
-       int i;
-
-       for (i = 0; (i < MCF_MAXPORTS); i++) {
-               port = &mcf_ports[i].port;
-               if (port)
-                       uart_remove_one_port(&mcf_driver, port);
-       }
-
-       return 0;
-}
-
-/****************************************************************************/
-
-static struct platform_driver mcf_platform_driver = {
-       .probe          = mcf_probe,
-       .remove         = __devexit_p(mcf_remove),
-       .driver         = {
-               .name   = "mcfuart",
-               .owner  = THIS_MODULE,
-       },
-};
-
-/****************************************************************************/
-
-static int __init mcf_init(void)
-{
-       int rc;
-
-       printk("ColdFire internal UART serial driver\n");
-
-       rc = uart_register_driver(&mcf_driver);
-       if (rc)
-               return rc;
-       rc = platform_driver_register(&mcf_platform_driver);
-       if (rc)
-               return rc;
-       return 0;
-}
-
-/****************************************************************************/
-
-static void __exit mcf_exit(void)
-{
-       platform_driver_unregister(&mcf_platform_driver);
-       uart_unregister_driver(&mcf_driver);
-}
-
-/****************************************************************************/
-
-module_init(mcf_init);
-module_exit(mcf_exit);
-
-MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>");
-MODULE_DESCRIPTION("Freescale ColdFire UART driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:mcfuart");
-
-/****************************************************************************/
diff --git a/drivers/serial/mfd.c b/drivers/serial/mfd.c
deleted file mode 100644 (file)
index d40010a..0000000
+++ /dev/null
@@ -1,1513 +0,0 @@
-/*
- * mfd.c: driver for High Speed UART device of Intel Medfield platform
- *
- * Refer pxa.c, 8250.c and some other drivers in drivers/serial/
- *
- * (C) Copyright 2010 Intel Corporation
- *
- * 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; version 2
- * of the License.
- */
-
-/* Notes:
- * 1. DMA channel allocation: 0/1 channel are assigned to port 0,
- *    2/3 chan to port 1, 4/5 chan to port 3. Even number chans
- *    are used for RX, odd chans for TX
- *
- * 2. In A0 stepping, UART will not support TX half empty flag
- *
- * 3. The RI/DSR/DCD/DTR are not pinned out, DCD & DSR are always
- *    asserted, only when the HW is reset the DDCD and DDSR will
- *    be triggered
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/slab.h>
-#include <linux/serial_reg.h>
-#include <linux/circ_buf.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial_mfd.h>
-#include <linux/dma-mapping.h>
-#include <linux/pci.h>
-#include <linux/io.h>
-#include <linux/debugfs.h>
-
-#define  MFD_HSU_A0_STEPPING   1
-
-#define HSU_DMA_BUF_SIZE       2048
-
-#define chan_readl(chan, offset)       readl(chan->reg + offset)
-#define chan_writel(chan, offset, val) writel(val, chan->reg + offset)
-
-#define mfd_readl(obj, offset)         readl(obj->reg + offset)
-#define mfd_writel(obj, offset, val)   writel(val, obj->reg + offset)
-
-#define HSU_DMA_TIMEOUT_CHECK_FREQ     (HZ/10)
-
-struct hsu_dma_buffer {
-       u8              *buf;
-       dma_addr_t      dma_addr;
-       u32             dma_size;
-       u32             ofs;
-};
-
-struct hsu_dma_chan {
-       u32     id;
-       enum dma_data_direction dirt;
-       struct uart_hsu_port    *uport;
-       void __iomem            *reg;
-       struct timer_list       rx_timer; /* only needed by RX channel */
-};
-
-struct uart_hsu_port {
-       struct uart_port        port;
-       unsigned char           ier;
-       unsigned char           lcr;
-       unsigned char           mcr;
-       unsigned int            lsr_break_flag;
-       char                    name[12];
-       int                     index;
-       struct device           *dev;
-
-       struct hsu_dma_chan     *txc;
-       struct hsu_dma_chan     *rxc;
-       struct hsu_dma_buffer   txbuf;
-       struct hsu_dma_buffer   rxbuf;
-       int                     use_dma;        /* flag for DMA/PIO */
-       int                     running;
-       int                     dma_tx_on;
-};
-
-/* Top level data structure of HSU */
-struct hsu_port {
-       void __iomem    *reg;
-       unsigned long   paddr;
-       unsigned long   iolen;
-       u32             irq;
-
-       struct uart_hsu_port    port[3];
-       struct hsu_dma_chan     chans[10];
-
-       struct dentry *debugfs;
-};
-
-static inline unsigned int serial_in(struct uart_hsu_port *up, int offset)
-{
-       unsigned int val;
-
-       if (offset > UART_MSR) {
-               offset <<= 2;
-               val = readl(up->port.membase + offset);
-       } else
-               val = (unsigned int)readb(up->port.membase + offset);
-
-       return val;
-}
-
-static inline void serial_out(struct uart_hsu_port *up, int offset, int value)
-{
-       if (offset > UART_MSR) {
-               offset <<= 2;
-               writel(value, up->port.membase + offset);
-       } else {
-               unsigned char val = value & 0xff;
-               writeb(val, up->port.membase + offset);
-       }
-}
-
-#ifdef CONFIG_DEBUG_FS
-
-#define HSU_REGS_BUFSIZE       1024
-
-static int hsu_show_regs_open(struct inode *inode, struct file *file)
-{
-       file->private_data = inode->i_private;
-       return 0;
-}
-
-static ssize_t port_show_regs(struct file *file, char __user *user_buf,
-                               size_t count, loff_t *ppos)
-{
-       struct uart_hsu_port *up = file->private_data;
-       char *buf;
-       u32 len = 0;
-       ssize_t ret;
-
-       buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL);
-       if (!buf)
-               return 0;
-
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "MFD HSU port[%d] regs:\n", up->index);
-
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "=================================\n");
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "IER: \t\t0x%08x\n", serial_in(up, UART_IER));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "IIR: \t\t0x%08x\n", serial_in(up, UART_IIR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "LCR: \t\t0x%08x\n", serial_in(up, UART_LCR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "MCR: \t\t0x%08x\n", serial_in(up, UART_MCR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "LSR: \t\t0x%08x\n", serial_in(up, UART_LSR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "MSR: \t\t0x%08x\n", serial_in(up, UART_MSR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "FOR: \t\t0x%08x\n", serial_in(up, UART_FOR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "PS: \t\t0x%08x\n", serial_in(up, UART_PS));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "MUL: \t\t0x%08x\n", serial_in(up, UART_MUL));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "DIV: \t\t0x%08x\n", serial_in(up, UART_DIV));
-
-       if (len > HSU_REGS_BUFSIZE)
-               len = HSU_REGS_BUFSIZE;
-
-       ret =  simple_read_from_buffer(user_buf, count, ppos, buf, len);
-       kfree(buf);
-       return ret;
-}
-
-static ssize_t dma_show_regs(struct file *file, char __user *user_buf,
-                               size_t count, loff_t *ppos)
-{
-       struct hsu_dma_chan *chan = file->private_data;
-       char *buf;
-       u32 len = 0;
-       ssize_t ret;
-
-       buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL);
-       if (!buf)
-               return 0;
-
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "MFD HSU DMA channel [%d] regs:\n", chan->id);
-
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "=================================\n");
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "CR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_CR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "DCR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_DCR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "BSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_BSR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "MOTSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_MOTSR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0SAR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0TSR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1SAR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1TSR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2SAR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2TSR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3SAR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3TSR));
-
-       if (len > HSU_REGS_BUFSIZE)
-               len = HSU_REGS_BUFSIZE;
-
-       ret =  simple_read_from_buffer(user_buf, count, ppos, buf, len);
-       kfree(buf);
-       return ret;
-}
-
-static const struct file_operations port_regs_ops = {
-       .owner          = THIS_MODULE,
-       .open           = hsu_show_regs_open,
-       .read           = port_show_regs,
-       .llseek         = default_llseek,
-};
-
-static const struct file_operations dma_regs_ops = {
-       .owner          = THIS_MODULE,
-       .open           = hsu_show_regs_open,
-       .read           = dma_show_regs,
-       .llseek         = default_llseek,
-};
-
-static int hsu_debugfs_init(struct hsu_port *hsu)
-{
-       int i;
-       char name[32];
-
-       hsu->debugfs = debugfs_create_dir("hsu", NULL);
-       if (!hsu->debugfs)
-               return -ENOMEM;
-
-       for (i = 0; i < 3; i++) {
-               snprintf(name, sizeof(name), "port_%d_regs", i);
-               debugfs_create_file(name, S_IFREG | S_IRUGO,
-                       hsu->debugfs, (void *)(&hsu->port[i]), &port_regs_ops);
-       }
-
-       for (i = 0; i < 6; i++) {
-               snprintf(name, sizeof(name), "dma_chan_%d_regs", i);
-               debugfs_create_file(name, S_IFREG | S_IRUGO,
-                       hsu->debugfs, (void *)&hsu->chans[i], &dma_regs_ops);
-       }
-
-       return 0;
-}
-
-static void hsu_debugfs_remove(struct hsu_port *hsu)
-{
-       if (hsu->debugfs)
-               debugfs_remove_recursive(hsu->debugfs);
-}
-
-#else
-static inline int hsu_debugfs_init(struct hsu_port *hsu)
-{
-       return 0;
-}
-
-static inline void hsu_debugfs_remove(struct hsu_port *hsu)
-{
-}
-#endif /* CONFIG_DEBUG_FS */
-
-static void serial_hsu_enable_ms(struct uart_port *port)
-{
-       struct uart_hsu_port *up =
-               container_of(port, struct uart_hsu_port, port);
-
-       up->ier |= UART_IER_MSI;
-       serial_out(up, UART_IER, up->ier);
-}
-
-void hsu_dma_tx(struct uart_hsu_port *up)
-{
-       struct circ_buf *xmit = &up->port.state->xmit;
-       struct hsu_dma_buffer *dbuf = &up->txbuf;
-       int count;
-
-       /* test_and_set_bit may be better, but anyway it's in lock protected mode */
-       if (up->dma_tx_on)
-               return;
-
-       /* Update the circ buf info */
-       xmit->tail += dbuf->ofs;
-       xmit->tail &= UART_XMIT_SIZE - 1;
-
-       up->port.icount.tx += dbuf->ofs;
-       dbuf->ofs = 0;
-
-       /* Disable the channel */
-       chan_writel(up->txc, HSU_CH_CR, 0x0);
-
-       if (!uart_circ_empty(xmit) && !uart_tx_stopped(&up->port)) {
-               dma_sync_single_for_device(up->port.dev,
-                                          dbuf->dma_addr,
-                                          dbuf->dma_size,
-                                          DMA_TO_DEVICE);
-
-               count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
-               dbuf->ofs = count;
-
-               /* Reprogram the channel */
-               chan_writel(up->txc, HSU_CH_D0SAR, dbuf->dma_addr + xmit->tail);
-               chan_writel(up->txc, HSU_CH_D0TSR, count);
-
-               /* Reenable the channel */
-               chan_writel(up->txc, HSU_CH_DCR, 0x1
-                                                | (0x1 << 8)
-                                                | (0x1 << 16)
-                                                | (0x1 << 24));
-               up->dma_tx_on = 1;
-               chan_writel(up->txc, HSU_CH_CR, 0x1);
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&up->port);
-}
-
-/* The buffer is already cache coherent */
-void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc, struct hsu_dma_buffer *dbuf)
-{
-       dbuf->ofs = 0;
-
-       chan_writel(rxc, HSU_CH_BSR, 32);
-       chan_writel(rxc, HSU_CH_MOTSR, 4);
-
-       chan_writel(rxc, HSU_CH_D0SAR, dbuf->dma_addr);
-       chan_writel(rxc, HSU_CH_D0TSR, dbuf->dma_size);
-       chan_writel(rxc, HSU_CH_DCR, 0x1 | (0x1 << 8)
-                                        | (0x1 << 16)
-                                        | (0x1 << 24)  /* timeout bit, see HSU Errata 1 */
-                                        );
-       chan_writel(rxc, HSU_CH_CR, 0x3);
-
-       mod_timer(&rxc->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ);
-}
-
-/* Protected by spin_lock_irqsave(port->lock) */
-static void serial_hsu_start_tx(struct uart_port *port)
-{
-       struct uart_hsu_port *up =
-               container_of(port, struct uart_hsu_port, port);
-
-       if (up->use_dma) {
-               hsu_dma_tx(up);
-       } else if (!(up->ier & UART_IER_THRI)) {
-               up->ier |= UART_IER_THRI;
-               serial_out(up, UART_IER, up->ier);
-       }
-}
-
-static void serial_hsu_stop_tx(struct uart_port *port)
-{
-       struct uart_hsu_port *up =
-               container_of(port, struct uart_hsu_port, port);
-       struct hsu_dma_chan *txc = up->txc;
-
-       if (up->use_dma)
-               chan_writel(txc, HSU_CH_CR, 0x0);
-       else if (up->ier & UART_IER_THRI) {
-               up->ier &= ~UART_IER_THRI;
-               serial_out(up, UART_IER, up->ier);
-       }
-}
-
-/* This is always called in spinlock protected mode, so
- * modify timeout timer is safe here */
-void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts)
-{
-       struct hsu_dma_buffer *dbuf = &up->rxbuf;
-       struct hsu_dma_chan *chan = up->rxc;
-       struct uart_port *port = &up->port;
-       struct tty_struct *tty = port->state->port.tty;
-       int count;
-
-       if (!tty)
-               return;
-
-       /*
-        * First need to know how many is already transferred,
-        * then check if its a timeout DMA irq, and return
-        * the trail bytes out, push them up and reenable the
-        * channel
-        */
-
-       /* Timeout IRQ, need wait some time, see Errata 2 */
-       if (int_sts & 0xf00)
-               udelay(2);
-
-       /* Stop the channel */
-       chan_writel(chan, HSU_CH_CR, 0x0);
-
-       count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr;
-       if (!count) {
-               /* Restart the channel before we leave */
-               chan_writel(chan, HSU_CH_CR, 0x3);
-               return;
-       }
-       del_timer(&chan->rx_timer);
-
-       dma_sync_single_for_cpu(port->dev, dbuf->dma_addr,
-                       dbuf->dma_size, DMA_FROM_DEVICE);
-
-       /*
-        * Head will only wrap around when we recycle
-        * the DMA buffer, and when that happens, we
-        * explicitly set tail to 0. So head will
-        * always be greater than tail.
-        */
-       tty_insert_flip_string(tty, dbuf->buf, count);
-       port->icount.rx += count;
-
-       dma_sync_single_for_device(up->port.dev, dbuf->dma_addr,
-                       dbuf->dma_size, DMA_FROM_DEVICE);
-
-       /* Reprogram the channel */
-       chan_writel(chan, HSU_CH_D0SAR, dbuf->dma_addr);
-       chan_writel(chan, HSU_CH_D0TSR, dbuf->dma_size);
-       chan_writel(chan, HSU_CH_DCR, 0x1
-                                        | (0x1 << 8)
-                                        | (0x1 << 16)
-                                        | (0x1 << 24)  /* timeout bit, see HSU Errata 1 */
-                                        );
-       tty_flip_buffer_push(tty);
-
-       chan_writel(chan, HSU_CH_CR, 0x3);
-       chan->rx_timer.expires = jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ;
-       add_timer(&chan->rx_timer);
-
-}
-
-static void serial_hsu_stop_rx(struct uart_port *port)
-{
-       struct uart_hsu_port *up =
-               container_of(port, struct uart_hsu_port, port);
-       struct hsu_dma_chan *chan = up->rxc;
-
-       if (up->use_dma)
-               chan_writel(chan, HSU_CH_CR, 0x2);
-       else {
-               up->ier &= ~UART_IER_RLSI;
-               up->port.read_status_mask &= ~UART_LSR_DR;
-               serial_out(up, UART_IER, up->ier);
-       }
-}
-
-static inline void receive_chars(struct uart_hsu_port *up, int *status)
-{
-       struct tty_struct *tty = up->port.state->port.tty;
-       unsigned int ch, flag;
-       unsigned int max_count = 256;
-
-       if (!tty)
-               return;
-
-       do {
-               ch = serial_in(up, UART_RX);
-               flag = TTY_NORMAL;
-               up->port.icount.rx++;
-
-               if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
-                                      UART_LSR_FE | UART_LSR_OE))) {
-
-                       dev_warn(up->dev, "We really rush into ERR/BI case"
-                               "status = 0x%02x", *status);
-                       /* For statistics only */
-                       if (*status & UART_LSR_BI) {
-                               *status &= ~(UART_LSR_FE | UART_LSR_PE);
-                               up->port.icount.brk++;
-                               /*
-                                * We do the SysRQ and SAK checking
-                                * here because otherwise the break
-                                * may get masked by ignore_status_mask
-                                * or read_status_mask.
-                                */
-                               if (uart_handle_break(&up->port))
-                                       goto ignore_char;
-                       } else if (*status & UART_LSR_PE)
-                               up->port.icount.parity++;
-                       else if (*status & UART_LSR_FE)
-                               up->port.icount.frame++;
-                       if (*status & UART_LSR_OE)
-                               up->port.icount.overrun++;
-
-                       /* Mask off conditions which should be ignored. */
-                       *status &= up->port.read_status_mask;
-
-#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE
-                       if (up->port.cons &&
-                               up->port.cons->index == up->port.line) {
-                               /* Recover the break flag from console xmit */
-                               *status |= up->lsr_break_flag;
-                               up->lsr_break_flag = 0;
-                       }
-#endif
-                       if (*status & UART_LSR_BI) {
-                               flag = TTY_BREAK;
-                       } else if (*status & UART_LSR_PE)
-                               flag = TTY_PARITY;
-                       else if (*status & UART_LSR_FE)
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(&up->port, ch))
-                       goto ignore_char;
-
-               uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag);
-       ignore_char:
-               *status = serial_in(up, UART_LSR);
-       } while ((*status & UART_LSR_DR) && max_count--);
-       tty_flip_buffer_push(tty);
-}
-
-static void transmit_chars(struct uart_hsu_port *up)
-{
-       struct circ_buf *xmit = &up->port.state->xmit;
-       int count;
-
-       if (up->port.x_char) {
-               serial_out(up, UART_TX, up->port.x_char);
-               up->port.icount.tx++;
-               up->port.x_char = 0;
-               return;
-       }
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
-               serial_hsu_stop_tx(&up->port);
-               return;
-       }
-
-#ifndef MFD_HSU_A0_STEPPING
-       count = up->port.fifosize / 2;
-#else
-       /*
-        * A0 only supports fully empty IRQ, and the first char written
-        * into it won't clear the EMPT bit, so we may need be cautious
-        * by useing a shorter buffer
-        */
-       count = up->port.fifosize - 4;
-#endif
-       do {
-               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-
-               up->port.icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (--count > 0);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&up->port);
-
-       if (uart_circ_empty(xmit))
-               serial_hsu_stop_tx(&up->port);
-}
-
-static inline void check_modem_status(struct uart_hsu_port *up)
-{
-       int status;
-
-       status = serial_in(up, UART_MSR);
-
-       if ((status & UART_MSR_ANY_DELTA) == 0)
-               return;
-
-       if (status & UART_MSR_TERI)
-               up->port.icount.rng++;
-       if (status & UART_MSR_DDSR)
-               up->port.icount.dsr++;
-       /* We may only get DDCD when HW init and reset */
-       if (status & UART_MSR_DDCD)
-               uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
-       /* Will start/stop_tx accordingly */
-       if (status & UART_MSR_DCTS)
-               uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
-
-       wake_up_interruptible(&up->port.state->port.delta_msr_wait);
-}
-
-/*
- * This handles the interrupt from one port.
- */
-static irqreturn_t port_irq(int irq, void *dev_id)
-{
-       struct uart_hsu_port *up = dev_id;
-       unsigned int iir, lsr;
-       unsigned long flags;
-
-       if (unlikely(!up->running))
-               return IRQ_NONE;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       if (up->use_dma) {
-               lsr = serial_in(up, UART_LSR);
-               if (unlikely(lsr & (UART_LSR_BI | UART_LSR_PE |
-                                      UART_LSR_FE | UART_LSR_OE)))
-                       dev_warn(up->dev,
-                               "Got lsr irq while using DMA, lsr = 0x%2x\n",
-                               lsr);
-               check_modem_status(up);
-               spin_unlock_irqrestore(&up->port.lock, flags);
-               return IRQ_HANDLED;
-       }
-
-       iir = serial_in(up, UART_IIR);
-       if (iir & UART_IIR_NO_INT) {
-               spin_unlock_irqrestore(&up->port.lock, flags);
-               return IRQ_NONE;
-       }
-
-       lsr = serial_in(up, UART_LSR);
-       if (lsr & UART_LSR_DR)
-               receive_chars(up, &lsr);
-       check_modem_status(up);
-
-       /* lsr will be renewed during the receive_chars */
-       if (lsr & UART_LSR_THRE)
-               transmit_chars(up);
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-       return IRQ_HANDLED;
-}
-
-static inline void dma_chan_irq(struct hsu_dma_chan *chan)
-{
-       struct uart_hsu_port *up = chan->uport;
-       unsigned long flags;
-       u32 int_sts;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       if (!up->use_dma || !up->running)
-               goto exit;
-
-       /*
-        * No matter what situation, need read clear the IRQ status
-        * There is a bug, see Errata 5, HSD 2900918
-        */
-       int_sts = chan_readl(chan, HSU_CH_SR);
-
-       /* Rx channel */
-       if (chan->dirt == DMA_FROM_DEVICE)
-               hsu_dma_rx(up, int_sts);
-
-       /* Tx channel */
-       if (chan->dirt == DMA_TO_DEVICE) {
-               chan_writel(chan, HSU_CH_CR, 0x0);
-               up->dma_tx_on = 0;
-               hsu_dma_tx(up);
-       }
-
-exit:
-       spin_unlock_irqrestore(&up->port.lock, flags);
-       return;
-}
-
-static irqreturn_t dma_irq(int irq, void *dev_id)
-{
-       struct hsu_port *hsu = dev_id;
-       u32 int_sts, i;
-
-       int_sts = mfd_readl(hsu, HSU_GBL_DMAISR);
-
-       /* Currently we only have 6 channels may be used */
-       for (i = 0; i < 6; i++) {
-               if (int_sts & 0x1)
-                       dma_chan_irq(&hsu->chans[i]);
-               int_sts >>= 1;
-       }
-
-       return IRQ_HANDLED;
-}
-
-static unsigned int serial_hsu_tx_empty(struct uart_port *port)
-{
-       struct uart_hsu_port *up =
-               container_of(port, struct uart_hsu_port, port);
-       unsigned long flags;
-       unsigned int ret;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       return ret;
-}
-
-static unsigned int serial_hsu_get_mctrl(struct uart_port *port)
-{
-       struct uart_hsu_port *up =
-               container_of(port, struct uart_hsu_port, port);
-       unsigned char status;
-       unsigned int ret;
-
-       status = serial_in(up, UART_MSR);
-
-       ret = 0;
-       if (status & UART_MSR_DCD)
-               ret |= TIOCM_CAR;
-       if (status & UART_MSR_RI)
-               ret |= TIOCM_RNG;
-       if (status & UART_MSR_DSR)
-               ret |= TIOCM_DSR;
-       if (status & UART_MSR_CTS)
-               ret |= TIOCM_CTS;
-       return ret;
-}
-
-static void serial_hsu_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_hsu_port *up =
-               container_of(port, struct uart_hsu_port, port);
-       unsigned char mcr = 0;
-
-       if (mctrl & TIOCM_RTS)
-               mcr |= UART_MCR_RTS;
-       if (mctrl & TIOCM_DTR)
-               mcr |= UART_MCR_DTR;
-       if (mctrl & TIOCM_OUT1)
-               mcr |= UART_MCR_OUT1;
-       if (mctrl & TIOCM_OUT2)
-               mcr |= UART_MCR_OUT2;
-       if (mctrl & TIOCM_LOOP)
-               mcr |= UART_MCR_LOOP;
-
-       mcr |= up->mcr;
-
-       serial_out(up, UART_MCR, mcr);
-}
-
-static void serial_hsu_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_hsu_port *up =
-               container_of(port, struct uart_hsu_port, port);
-       unsigned long flags;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       if (break_state == -1)
-               up->lcr |= UART_LCR_SBC;
-       else
-               up->lcr &= ~UART_LCR_SBC;
-       serial_out(up, UART_LCR, up->lcr);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-/*
- * What special to do:
- * 1. chose the 64B fifo mode
- * 2. make sure not to select half empty mode for A0 stepping
- * 3. start dma or pio depends on configuration
- * 4. we only allocate dma memory when needed
- */
-static int serial_hsu_startup(struct uart_port *port)
-{
-       struct uart_hsu_port *up =
-               container_of(port, struct uart_hsu_port, port);
-       unsigned long flags;
-
-       /*
-        * Clear the FIFO buffers and disable them.
-        * (they will be reenabled in set_termios())
-        */
-       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
-                       UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
-       serial_out(up, UART_FCR, 0);
-
-       /* Clear the interrupt registers. */
-       (void) serial_in(up, UART_LSR);
-       (void) serial_in(up, UART_RX);
-       (void) serial_in(up, UART_IIR);
-       (void) serial_in(up, UART_MSR);
-
-       /* Now, initialize the UART, default is 8n1 */
-       serial_out(up, UART_LCR, UART_LCR_WLEN8);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       up->port.mctrl |= TIOCM_OUT2;
-       serial_hsu_set_mctrl(&up->port, up->port.mctrl);
-
-       /*
-        * Finally, enable interrupts.  Note: Modem status interrupts
-        * are set via set_termios(), which will be occurring imminently
-        * anyway, so we don't enable them here.
-        */
-       if (!up->use_dma)
-               up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE;
-       else
-               up->ier = 0;
-       serial_out(up, UART_IER, up->ier);
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       /* DMA init */
-       if (up->use_dma) {
-               struct hsu_dma_buffer *dbuf;
-               struct circ_buf *xmit = &port->state->xmit;
-
-               up->dma_tx_on = 0;
-
-               /* First allocate the RX buffer */
-               dbuf = &up->rxbuf;
-               dbuf->buf = kzalloc(HSU_DMA_BUF_SIZE, GFP_KERNEL);
-               if (!dbuf->buf) {
-                       up->use_dma = 0;
-                       goto exit;
-               }
-               dbuf->dma_addr = dma_map_single(port->dev,
-                                               dbuf->buf,
-                                               HSU_DMA_BUF_SIZE,
-                                               DMA_FROM_DEVICE);
-               dbuf->dma_size = HSU_DMA_BUF_SIZE;
-
-               /* Start the RX channel right now */
-               hsu_dma_start_rx_chan(up->rxc, dbuf);
-
-               /* Next init the TX DMA */
-               dbuf = &up->txbuf;
-               dbuf->buf = xmit->buf;
-               dbuf->dma_addr = dma_map_single(port->dev,
-                                              dbuf->buf,
-                                              UART_XMIT_SIZE,
-                                              DMA_TO_DEVICE);
-               dbuf->dma_size = UART_XMIT_SIZE;
-
-               /* This should not be changed all around */
-               chan_writel(up->txc, HSU_CH_BSR, 32);
-               chan_writel(up->txc, HSU_CH_MOTSR, 4);
-               dbuf->ofs = 0;
-       }
-
-exit:
-        /* And clear the interrupt registers again for luck. */
-       (void) serial_in(up, UART_LSR);
-       (void) serial_in(up, UART_RX);
-       (void) serial_in(up, UART_IIR);
-       (void) serial_in(up, UART_MSR);
-
-       up->running = 1;
-       return 0;
-}
-
-static void serial_hsu_shutdown(struct uart_port *port)
-{
-       struct uart_hsu_port *up =
-               container_of(port, struct uart_hsu_port, port);
-       unsigned long flags;
-
-       del_timer_sync(&up->rxc->rx_timer);
-
-       /* Disable interrupts from this port */
-       up->ier = 0;
-       serial_out(up, UART_IER, 0);
-       up->running = 0;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       up->port.mctrl &= ~TIOCM_OUT2;
-       serial_hsu_set_mctrl(&up->port, up->port.mctrl);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       /* Disable break condition and FIFOs */
-       serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
-       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
-                                 UART_FCR_CLEAR_RCVR |
-                                 UART_FCR_CLEAR_XMIT);
-       serial_out(up, UART_FCR, 0);
-}
-
-static void
-serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios,
-                      struct ktermios *old)
-{
-       struct uart_hsu_port *up =
-                       container_of(port, struct uart_hsu_port, port);
-       struct tty_struct *tty = port->state->port.tty;
-       unsigned char cval, fcr = 0;
-       unsigned long flags;
-       unsigned int baud, quot;
-       u32 ps, mul;
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               cval = UART_LCR_WLEN5;
-               break;
-       case CS6:
-               cval = UART_LCR_WLEN6;
-               break;
-       case CS7:
-               cval = UART_LCR_WLEN7;
-               break;
-       default:
-       case CS8:
-               cval = UART_LCR_WLEN8;
-               break;
-       }
-
-       /* CMSPAR isn't supported by this driver */
-       if (tty)
-               tty->termios->c_cflag &= ~CMSPAR;
-
-       if (termios->c_cflag & CSTOPB)
-               cval |= UART_LCR_STOP;
-       if (termios->c_cflag & PARENB)
-               cval |= UART_LCR_PARITY;
-       if (!(termios->c_cflag & PARODD))
-               cval |= UART_LCR_EPAR;
-
-       /*
-        * The base clk is 50Mhz, and the baud rate come from:
-        *      baud = 50M * MUL / (DIV * PS * DLAB)
-        *
-        * For those basic low baud rate we can get the direct
-        * scalar from 2746800, like 115200 = 2746800/24. For those
-        * higher baud rate, we handle them case by case, mainly by
-        * adjusting the MUL/PS registers, and DIV register is kept
-        * as default value 0x3d09 to make things simple
-        */
-       baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
-
-       quot = 1;
-       ps = 0x10;
-       mul = 0x3600;
-       switch (baud) {
-       case 3500000:
-               mul = 0x3345;
-               ps = 0xC;
-               break;
-       case 1843200:
-               mul = 0x2400;
-               break;
-       case 3000000:
-       case 2500000:
-       case 2000000:
-       case 1500000:
-       case 1000000:
-       case 500000:
-               /* mul/ps/quot = 0x9C4/0x10/0x1 will make a 500000 bps */
-               mul = baud / 500000 * 0x9C4;
-               break;
-       default:
-               /* Use uart_get_divisor to get quot for other baud rates */
-               quot = 0;
-       }
-
-       if (!quot)
-               quot = uart_get_divisor(port, baud);
-
-       if ((up->port.uartclk / quot) < (2400 * 16))
-               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_1B;
-       else if ((up->port.uartclk / quot) < (230400 * 16))
-               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_16B;
-       else
-               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_32B;
-
-       fcr |= UART_FCR_HSU_64B_FIFO;
-#ifdef MFD_HSU_A0_STEPPING
-       /* A0 doesn't support half empty IRQ */
-       fcr |= UART_FCR_FULL_EMPT_TXI;
-#endif
-
-       /*
-        * Ok, we're now changing the port state.  Do it with
-        * interrupts disabled.
-        */
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       /* Update the per-port timeout */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
-       if (termios->c_iflag & INPCK)
-               up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               up->port.read_status_mask |= UART_LSR_BI;
-
-       /* Characters to ignore */
-       up->port.ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
-       if (termios->c_iflag & IGNBRK) {
-               up->port.ignore_status_mask |= UART_LSR_BI;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       up->port.ignore_status_mask |= UART_LSR_OE;
-       }
-
-       /* Ignore all characters if CREAD is not set */
-       if ((termios->c_cflag & CREAD) == 0)
-               up->port.ignore_status_mask |= UART_LSR_DR;
-
-       /*
-        * CTS flow control flag and modem status interrupts, disable
-        * MSI by default
-        */
-       up->ier &= ~UART_IER_MSI;
-       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
-               up->ier |= UART_IER_MSI;
-
-       serial_out(up, UART_IER, up->ier);
-
-       if (termios->c_cflag & CRTSCTS)
-               up->mcr |= UART_MCR_AFE | UART_MCR_RTS;
-       else
-               up->mcr &= ~UART_MCR_AFE;
-
-       serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
-       serial_out(up, UART_DLL, quot & 0xff);          /* LS of divisor */
-       serial_out(up, UART_DLM, quot >> 8);            /* MS of divisor */
-       serial_out(up, UART_LCR, cval);                 /* reset DLAB */
-       serial_out(up, UART_MUL, mul);                  /* set MUL */
-       serial_out(up, UART_PS, ps);                    /* set PS */
-       up->lcr = cval;                                 /* Save LCR */
-       serial_hsu_set_mctrl(&up->port, up->port.mctrl);
-       serial_out(up, UART_FCR, fcr);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static void
-serial_hsu_pm(struct uart_port *port, unsigned int state,
-             unsigned int oldstate)
-{
-}
-
-static void serial_hsu_release_port(struct uart_port *port)
-{
-}
-
-static int serial_hsu_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-static void serial_hsu_config_port(struct uart_port *port, int flags)
-{
-       struct uart_hsu_port *up =
-               container_of(port, struct uart_hsu_port, port);
-       up->port.type = PORT_MFD;
-}
-
-static int
-serial_hsu_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       /* We don't want the core code to modify any port params */
-       return -EINVAL;
-}
-
-static const char *
-serial_hsu_type(struct uart_port *port)
-{
-       struct uart_hsu_port *up =
-               container_of(port, struct uart_hsu_port, port);
-       return up->name;
-}
-
-/* Mainly for uart console use */
-static struct uart_hsu_port *serial_hsu_ports[3];
-static struct uart_driver serial_hsu_reg;
-
-#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE
-
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-
-/* Wait for transmitter & holding register to empty */
-static inline void wait_for_xmitr(struct uart_hsu_port *up)
-{
-       unsigned int status, tmout = 1000;
-
-       /* Wait up to 1ms for the character to be sent. */
-       do {
-               status = serial_in(up, UART_LSR);
-
-               if (status & UART_LSR_BI)
-                       up->lsr_break_flag = UART_LSR_BI;
-
-               if (--tmout == 0)
-                       break;
-               udelay(1);
-       } while (!(status & BOTH_EMPTY));
-
-       /* Wait up to 1s for flow control if necessary */
-       if (up->port.flags & UPF_CONS_FLOW) {
-               tmout = 1000000;
-               while (--tmout &&
-                      ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
-                       udelay(1);
-       }
-}
-
-static void serial_hsu_console_putchar(struct uart_port *port, int ch)
-{
-       struct uart_hsu_port *up =
-               container_of(port, struct uart_hsu_port, port);
-
-       wait_for_xmitr(up);
-       serial_out(up, UART_TX, ch);
-}
-
-/*
- * 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.
- */
-static void
-serial_hsu_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct uart_hsu_port *up = serial_hsu_ports[co->index];
-       unsigned long flags;
-       unsigned int ier;
-       int locked = 1;
-
-       local_irq_save(flags);
-       if (up->port.sysrq)
-               locked = 0;
-       else if (oops_in_progress) {
-               locked = spin_trylock(&up->port.lock);
-       } else
-               spin_lock(&up->port.lock);
-
-       /* First save the IER then disable the interrupts */
-       ier = serial_in(up, UART_IER);
-       serial_out(up, UART_IER, 0);
-
-       uart_console_write(&up->port, s, count, serial_hsu_console_putchar);
-
-       /*
-        * Finally, wait for transmitter to become empty
-        * and restore the IER
-        */
-       wait_for_xmitr(up);
-       serial_out(up, UART_IER, ier);
-
-       if (locked)
-               spin_unlock(&up->port.lock);
-       local_irq_restore(flags);
-}
-
-static struct console serial_hsu_console;
-
-static int __init
-serial_hsu_console_setup(struct console *co, char *options)
-{
-       struct uart_hsu_port *up;
-       int baud = 115200;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-       int ret;
-
-       if (co->index == -1 || co->index >= serial_hsu_reg.nr)
-               co->index = 0;
-       up = serial_hsu_ports[co->index];
-       if (!up)
-               return -ENODEV;
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       ret = uart_set_options(&up->port, co, baud, parity, bits, flow);
-
-       return ret;
-}
-
-static struct console serial_hsu_console = {
-       .name           = "ttyMFD",
-       .write          = serial_hsu_console_write,
-       .device         = uart_console_device,
-       .setup          = serial_hsu_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = 2,
-       .data           = &serial_hsu_reg,
-};
-#endif
-
-struct uart_ops serial_hsu_pops = {
-       .tx_empty       = serial_hsu_tx_empty,
-       .set_mctrl      = serial_hsu_set_mctrl,
-       .get_mctrl      = serial_hsu_get_mctrl,
-       .stop_tx        = serial_hsu_stop_tx,
-       .start_tx       = serial_hsu_start_tx,
-       .stop_rx        = serial_hsu_stop_rx,
-       .enable_ms      = serial_hsu_enable_ms,
-       .break_ctl      = serial_hsu_break_ctl,
-       .startup        = serial_hsu_startup,
-       .shutdown       = serial_hsu_shutdown,
-       .set_termios    = serial_hsu_set_termios,
-       .pm             = serial_hsu_pm,
-       .type           = serial_hsu_type,
-       .release_port   = serial_hsu_release_port,
-       .request_port   = serial_hsu_request_port,
-       .config_port    = serial_hsu_config_port,
-       .verify_port    = serial_hsu_verify_port,
-};
-
-static struct uart_driver serial_hsu_reg = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "MFD serial",
-       .dev_name       = "ttyMFD",
-       .major          = TTY_MAJOR,
-       .minor          = 128,
-       .nr             = 3,
-};
-
-#ifdef CONFIG_PM
-static int serial_hsu_suspend(struct pci_dev *pdev, pm_message_t state)
-{
-       void *priv = pci_get_drvdata(pdev);
-       struct uart_hsu_port *up;
-
-       /* Make sure this is not the internal dma controller */
-       if (priv && (pdev->device != 0x081E)) {
-               up = priv;
-               uart_suspend_port(&serial_hsu_reg, &up->port);
-       }
-
-       pci_save_state(pdev);
-       pci_set_power_state(pdev, pci_choose_state(pdev, state));
-        return 0;
-}
-
-static int serial_hsu_resume(struct pci_dev *pdev)
-{
-       void *priv = pci_get_drvdata(pdev);
-       struct uart_hsu_port *up;
-       int ret;
-
-       pci_set_power_state(pdev, PCI_D0);
-       pci_restore_state(pdev);
-
-       ret = pci_enable_device(pdev);
-       if (ret)
-               dev_warn(&pdev->dev,
-                       "HSU: can't re-enable device, try to continue\n");
-
-       if (priv && (pdev->device != 0x081E)) {
-               up = priv;
-               uart_resume_port(&serial_hsu_reg, &up->port);
-       }
-       return 0;
-}
-#else
-#define serial_hsu_suspend     NULL
-#define serial_hsu_resume      NULL
-#endif
-
-/* temp global pointer before we settle down on using one or four PCI dev */
-static struct hsu_port *phsu;
-
-static int serial_hsu_probe(struct pci_dev *pdev,
-                               const struct pci_device_id *ent)
-{
-       struct uart_hsu_port *uport;
-       int index, ret;
-
-       printk(KERN_INFO "HSU: found PCI Serial controller(ID: %04x:%04x)\n",
-               pdev->vendor, pdev->device);
-
-       switch (pdev->device) {
-       case 0x081B:
-               index = 0;
-               break;
-       case 0x081C:
-               index = 1;
-               break;
-       case 0x081D:
-               index = 2;
-               break;
-       case 0x081E:
-               /* internal DMA controller */
-               index = 3;
-               break;
-       default:
-               dev_err(&pdev->dev, "HSU: out of index!");
-               return -ENODEV;
-       }
-
-       ret = pci_enable_device(pdev);
-       if (ret)
-               return ret;
-
-       if (index == 3) {
-               /* DMA controller */
-               ret = request_irq(pdev->irq, dma_irq, 0, "hsu_dma", phsu);
-               if (ret) {
-                       dev_err(&pdev->dev, "can not get IRQ\n");
-                       goto err_disable;
-               }
-               pci_set_drvdata(pdev, phsu);
-       } else {
-               /* UART port 0~2 */
-               uport = &phsu->port[index];
-               uport->port.irq = pdev->irq;
-               uport->port.dev = &pdev->dev;
-               uport->dev = &pdev->dev;
-
-               ret = request_irq(pdev->irq, port_irq, 0, uport->name, uport);
-               if (ret) {
-                       dev_err(&pdev->dev, "can not get IRQ\n");
-                       goto err_disable;
-               }
-               uart_add_one_port(&serial_hsu_reg, &uport->port);
-
-#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE
-               if (index == 2) {
-                       register_console(&serial_hsu_console);
-                       uport->port.cons = &serial_hsu_console;
-               }
-#endif
-               pci_set_drvdata(pdev, uport);
-       }
-
-       return 0;
-
-err_disable:
-       pci_disable_device(pdev);
-       return ret;
-}
-
-static void hsu_dma_rx_timeout(unsigned long data)
-{
-       struct hsu_dma_chan *chan = (void *)data;
-       struct uart_hsu_port *up = chan->uport;
-       struct hsu_dma_buffer *dbuf = &up->rxbuf;
-       int count = 0;
-       unsigned long flags;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr;
-
-       if (!count) {
-               mod_timer(&chan->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ);
-               goto exit;
-       }
-
-       hsu_dma_rx(up, 0);
-exit:
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static void hsu_global_init(void)
-{
-       struct hsu_port *hsu;
-       struct uart_hsu_port *uport;
-       struct hsu_dma_chan *dchan;
-       int i, ret;
-
-       hsu = kzalloc(sizeof(struct hsu_port), GFP_KERNEL);
-       if (!hsu)
-               return;
-
-       /* Get basic io resource and map it */
-       hsu->paddr = 0xffa28000;
-       hsu->iolen = 0x1000;
-
-       if (!(request_mem_region(hsu->paddr, hsu->iolen, "HSU global")))
-               pr_warning("HSU: error in request mem region\n");
-
-       hsu->reg = ioremap_nocache((unsigned long)hsu->paddr, hsu->iolen);
-       if (!hsu->reg) {
-               pr_err("HSU: error in ioremap\n");
-               ret = -ENOMEM;
-               goto err_free_region;
-       }
-
-       /* Initialise the 3 UART ports */
-       uport = hsu->port;
-       for (i = 0; i < 3; i++) {
-               uport->port.type = PORT_MFD;
-               uport->port.iotype = UPIO_MEM;
-               uport->port.mapbase = (resource_size_t)hsu->paddr
-                                       + HSU_PORT_REG_OFFSET
-                                       + i * HSU_PORT_REG_LENGTH;
-               uport->port.membase = hsu->reg + HSU_PORT_REG_OFFSET
-                                       + i * HSU_PORT_REG_LENGTH;
-
-               sprintf(uport->name, "hsu_port%d", i);
-               uport->port.fifosize = 64;
-               uport->port.ops = &serial_hsu_pops;
-               uport->port.line = i;
-               uport->port.flags = UPF_IOREMAP;
-               /* set the scalable maxim support rate to 2746800 bps */
-               uport->port.uartclk = 115200 * 24 * 16;
-
-               uport->running = 0;
-               uport->txc = &hsu->chans[i * 2];
-               uport->rxc = &hsu->chans[i * 2 + 1];
-
-               serial_hsu_ports[i] = uport;
-               uport->index = i;
-               uport++;
-       }
-
-       /* Initialise 6 dma channels */
-       dchan = hsu->chans;
-       for (i = 0; i < 6; i++) {
-               dchan->id = i;
-               dchan->dirt = (i & 0x1) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
-               dchan->uport = &hsu->port[i/2];
-               dchan->reg = hsu->reg + HSU_DMA_CHANS_REG_OFFSET +
-                               i * HSU_DMA_CHANS_REG_LENGTH;
-
-               /* Work around for RX */
-               if (dchan->dirt == DMA_FROM_DEVICE) {
-                       init_timer(&dchan->rx_timer);
-                       dchan->rx_timer.function = hsu_dma_rx_timeout;
-                       dchan->rx_timer.data = (unsigned long)dchan;
-               }
-               dchan++;
-       }
-
-       phsu = hsu;
-       hsu_debugfs_init(hsu);
-       return;
-
-err_free_region:
-       release_mem_region(hsu->paddr, hsu->iolen);
-       kfree(hsu);
-       return;
-}
-
-static void serial_hsu_remove(struct pci_dev *pdev)
-{
-       void *priv = pci_get_drvdata(pdev);
-       struct uart_hsu_port *up;
-
-       if (!priv)
-               return;
-
-       /* For port 0/1/2, priv is the address of uart_hsu_port */
-       if (pdev->device != 0x081E) {
-               up = priv;
-               uart_remove_one_port(&serial_hsu_reg, &up->port);
-       }
-
-       pci_set_drvdata(pdev, NULL);
-       free_irq(pdev->irq, priv);
-       pci_disable_device(pdev);
-}
-
-/* First 3 are UART ports, and the 4th is the DMA */
-static const struct pci_device_id pci_ids[] __devinitdata = {
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081B) },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081C) },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081D) },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081E) },
-       {},
-};
-
-static struct pci_driver hsu_pci_driver = {
-       .name =         "HSU serial",
-       .id_table =     pci_ids,
-       .probe =        serial_hsu_probe,
-       .remove =       __devexit_p(serial_hsu_remove),
-       .suspend =      serial_hsu_suspend,
-       .resume =       serial_hsu_resume,
-};
-
-static int __init hsu_pci_init(void)
-{
-       int ret;
-
-       hsu_global_init();
-
-       ret = uart_register_driver(&serial_hsu_reg);
-       if (ret)
-               return ret;
-
-       return pci_register_driver(&hsu_pci_driver);
-}
-
-static void __exit hsu_pci_exit(void)
-{
-       pci_unregister_driver(&hsu_pci_driver);
-       uart_unregister_driver(&serial_hsu_reg);
-
-       hsu_debugfs_remove(phsu);
-
-       kfree(phsu);
-}
-
-module_init(hsu_pci_init);
-module_exit(hsu_pci_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:medfield-hsu");
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
deleted file mode 100644 (file)
index 126ec7f..0000000
+++ /dev/null
@@ -1,1527 +0,0 @@
-/*
- * Driver for the PSC of the Freescale MPC52xx PSCs configured as UARTs.
- *
- * FIXME According to the usermanual the status bits in the status register
- * are only updated when the peripherals access the FIFO and not when the
- * CPU access them. So since we use this bits to know when we stop writing
- * and reading, they may not be updated in-time and a race condition may
- * exists. But I haven't be able to prove this and I don't care. But if
- * any problem arises, it might worth checking. The TX/RX FIFO Stats
- * registers should be used in addition.
- * Update: Actually, they seem updated ... At least the bits we use.
- *
- *
- * Maintainer : Sylvain Munaut <tnt@246tNt.com>
- *
- * Some of the code has been inspired/copied from the 2.4 code written
- * by Dale Farnsworth <dfarnsworth@mvista.com>.
- *
- * Copyright (C) 2008 Freescale Semiconductor Inc.
- *                    John Rigby <jrigby@gmail.com>
- * Added support for MPC5121
- * Copyright (C) 2006 Secret Lab Technologies Ltd.
- *                    Grant Likely <grant.likely@secretlab.ca>
- * Copyright (C) 2004-2006 Sylvain Munaut <tnt@246tNt.com>
- * Copyright (C) 2003 MontaVista, Software, Inc.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#undef DEBUG
-
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/serial.h>
-#include <linux/sysrq.h>
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/clk.h>
-
-#include <asm/mpc52xx.h>
-#include <asm/mpc52xx_psc.h>
-
-#if defined(CONFIG_SERIAL_MPC52xx_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
-
-/* We've been assigned a range on the "Low-density serial ports" major */
-#define SERIAL_PSC_MAJOR       204
-#define SERIAL_PSC_MINOR       148
-
-
-#define ISR_PASS_LIMIT 256     /* Max number of iteration in the interrupt */
-
-
-static struct uart_port mpc52xx_uart_ports[MPC52xx_PSC_MAXNUM];
-       /* Rem: - We use the read_status_mask as a shadow of
-        *        psc->mpc52xx_psc_imr
-        *      - It's important that is array is all zero on start as we
-        *        use it to know if it's initialized or not ! If it's not sure
-        *        it's cleared, then a memset(...,0,...) should be added to
-        *        the console_init
-        */
-
-/* lookup table for matching device nodes to index numbers */
-static struct device_node *mpc52xx_uart_nodes[MPC52xx_PSC_MAXNUM];
-
-static void mpc52xx_uart_of_enumerate(void);
-
-
-#define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase))
-
-
-/* Forward declaration of the interruption handling routine */
-static irqreturn_t mpc52xx_uart_int(int irq, void *dev_id);
-static irqreturn_t mpc5xxx_uart_process_int(struct uart_port *port);
-
-
-/* Simple macro to test if a port is console or not. This one is taken
- * for serial_core.c and maybe should be moved to serial_core.h ? */
-#ifdef CONFIG_SERIAL_CORE_CONSOLE
-#define uart_console(port) \
-       ((port)->cons && (port)->cons->index == (port)->line)
-#else
-#define uart_console(port)     (0)
-#endif
-
-/* ======================================================================== */
-/* PSC fifo operations for isolating differences between 52xx and 512x      */
-/* ======================================================================== */
-
-struct psc_ops {
-       void            (*fifo_init)(struct uart_port *port);
-       int             (*raw_rx_rdy)(struct uart_port *port);
-       int             (*raw_tx_rdy)(struct uart_port *port);
-       int             (*rx_rdy)(struct uart_port *port);
-       int             (*tx_rdy)(struct uart_port *port);
-       int             (*tx_empty)(struct uart_port *port);
-       void            (*stop_rx)(struct uart_port *port);
-       void            (*start_tx)(struct uart_port *port);
-       void            (*stop_tx)(struct uart_port *port);
-       void            (*rx_clr_irq)(struct uart_port *port);
-       void            (*tx_clr_irq)(struct uart_port *port);
-       void            (*write_char)(struct uart_port *port, unsigned char c);
-       unsigned char   (*read_char)(struct uart_port *port);
-       void            (*cw_disable_ints)(struct uart_port *port);
-       void            (*cw_restore_ints)(struct uart_port *port);
-       unsigned int    (*set_baudrate)(struct uart_port *port,
-                                       struct ktermios *new,
-                                       struct ktermios *old);
-       int             (*clock)(struct uart_port *port, int enable);
-       int             (*fifoc_init)(void);
-       void            (*fifoc_uninit)(void);
-       void            (*get_irq)(struct uart_port *, struct device_node *);
-       irqreturn_t     (*handle_irq)(struct uart_port *port);
-};
-
-/* setting the prescaler and divisor reg is common for all chips */
-static inline void mpc52xx_set_divisor(struct mpc52xx_psc __iomem *psc,
-                                      u16 prescaler, unsigned int divisor)
-{
-       /* select prescaler */
-       out_be16(&psc->mpc52xx_psc_clock_select, prescaler);
-       out_8(&psc->ctur, divisor >> 8);
-       out_8(&psc->ctlr, divisor & 0xff);
-}
-
-#ifdef CONFIG_PPC_MPC52xx
-#define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1))
-static void mpc52xx_psc_fifo_init(struct uart_port *port)
-{
-       struct mpc52xx_psc __iomem *psc = PSC(port);
-       struct mpc52xx_psc_fifo __iomem *fifo = FIFO_52xx(port);
-
-       out_8(&fifo->rfcntl, 0x00);
-       out_be16(&fifo->rfalarm, 0x1ff);
-       out_8(&fifo->tfcntl, 0x07);
-       out_be16(&fifo->tfalarm, 0x80);
-
-       port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY;
-       out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
-}
-
-static int mpc52xx_psc_raw_rx_rdy(struct uart_port *port)
-{
-       return in_be16(&PSC(port)->mpc52xx_psc_status)
-           & MPC52xx_PSC_SR_RXRDY;
-}
-
-static int mpc52xx_psc_raw_tx_rdy(struct uart_port *port)
-{
-       return in_be16(&PSC(port)->mpc52xx_psc_status)
-           & MPC52xx_PSC_SR_TXRDY;
-}
-
-
-static int mpc52xx_psc_rx_rdy(struct uart_port *port)
-{
-       return in_be16(&PSC(port)->mpc52xx_psc_isr)
-           & port->read_status_mask
-           & MPC52xx_PSC_IMR_RXRDY;
-}
-
-static int mpc52xx_psc_tx_rdy(struct uart_port *port)
-{
-       return in_be16(&PSC(port)->mpc52xx_psc_isr)
-           & port->read_status_mask
-           & MPC52xx_PSC_IMR_TXRDY;
-}
-
-static int mpc52xx_psc_tx_empty(struct uart_port *port)
-{
-       return in_be16(&PSC(port)->mpc52xx_psc_status)
-           & MPC52xx_PSC_SR_TXEMP;
-}
-
-static void mpc52xx_psc_start_tx(struct uart_port *port)
-{
-       port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
-       out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
-}
-
-static void mpc52xx_psc_stop_tx(struct uart_port *port)
-{
-       port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY;
-       out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
-}
-
-static void mpc52xx_psc_stop_rx(struct uart_port *port)
-{
-       port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY;
-       out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
-}
-
-static void mpc52xx_psc_rx_clr_irq(struct uart_port *port)
-{
-}
-
-static void mpc52xx_psc_tx_clr_irq(struct uart_port *port)
-{
-}
-
-static void mpc52xx_psc_write_char(struct uart_port *port, unsigned char c)
-{
-       out_8(&PSC(port)->mpc52xx_psc_buffer_8, c);
-}
-
-static unsigned char mpc52xx_psc_read_char(struct uart_port *port)
-{
-       return in_8(&PSC(port)->mpc52xx_psc_buffer_8);
-}
-
-static void mpc52xx_psc_cw_disable_ints(struct uart_port *port)
-{
-       out_be16(&PSC(port)->mpc52xx_psc_imr, 0);
-}
-
-static void mpc52xx_psc_cw_restore_ints(struct uart_port *port)
-{
-       out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
-}
-
-static unsigned int mpc5200_psc_set_baudrate(struct uart_port *port,
-                                            struct ktermios *new,
-                                            struct ktermios *old)
-{
-       unsigned int baud;
-       unsigned int divisor;
-
-       /* The 5200 has a fixed /32 prescaler, uartclk contains the ipb freq */
-       baud = uart_get_baud_rate(port, new, old,
-                                 port->uartclk / (32 * 0xffff) + 1,
-                                 port->uartclk / 32);
-       divisor = (port->uartclk + 16 * baud) / (32 * baud);
-
-       /* enable the /32 prescaler and set the divisor */
-       mpc52xx_set_divisor(PSC(port), 0xdd00, divisor);
-       return baud;
-}
-
-static unsigned int mpc5200b_psc_set_baudrate(struct uart_port *port,
-                                             struct ktermios *new,
-                                             struct ktermios *old)
-{
-       unsigned int baud;
-       unsigned int divisor;
-       u16 prescaler;
-
-       /* The 5200B has a selectable /4 or /32 prescaler, uartclk contains the
-        * ipb freq */
-       baud = uart_get_baud_rate(port, new, old,
-                                 port->uartclk / (32 * 0xffff) + 1,
-                                 port->uartclk / 4);
-       divisor = (port->uartclk + 2 * baud) / (4 * baud);
-
-       /* select the proper prescaler and set the divisor */
-       if (divisor > 0xffff) {
-               divisor = (divisor + 4) / 8;
-               prescaler = 0xdd00; /* /32 */
-       } else
-               prescaler = 0xff00; /* /4 */
-       mpc52xx_set_divisor(PSC(port), prescaler, divisor);
-       return baud;
-}
-
-static void mpc52xx_psc_get_irq(struct uart_port *port, struct device_node *np)
-{
-       port->irqflags = IRQF_DISABLED;
-       port->irq = irq_of_parse_and_map(np, 0);
-}
-
-/* 52xx specific interrupt handler. The caller holds the port lock */
-static irqreturn_t mpc52xx_psc_handle_irq(struct uart_port *port)
-{
-       return mpc5xxx_uart_process_int(port);
-}
-
-static struct psc_ops mpc52xx_psc_ops = {
-       .fifo_init = mpc52xx_psc_fifo_init,
-       .raw_rx_rdy = mpc52xx_psc_raw_rx_rdy,
-       .raw_tx_rdy = mpc52xx_psc_raw_tx_rdy,
-       .rx_rdy = mpc52xx_psc_rx_rdy,
-       .tx_rdy = mpc52xx_psc_tx_rdy,
-       .tx_empty = mpc52xx_psc_tx_empty,
-       .stop_rx = mpc52xx_psc_stop_rx,
-       .start_tx = mpc52xx_psc_start_tx,
-       .stop_tx = mpc52xx_psc_stop_tx,
-       .rx_clr_irq = mpc52xx_psc_rx_clr_irq,
-       .tx_clr_irq = mpc52xx_psc_tx_clr_irq,
-       .write_char = mpc52xx_psc_write_char,
-       .read_char = mpc52xx_psc_read_char,
-       .cw_disable_ints = mpc52xx_psc_cw_disable_ints,
-       .cw_restore_ints = mpc52xx_psc_cw_restore_ints,
-       .set_baudrate = mpc5200_psc_set_baudrate,
-       .get_irq = mpc52xx_psc_get_irq,
-       .handle_irq = mpc52xx_psc_handle_irq,
-};
-
-static struct psc_ops mpc5200b_psc_ops = {
-       .fifo_init = mpc52xx_psc_fifo_init,
-       .raw_rx_rdy = mpc52xx_psc_raw_rx_rdy,
-       .raw_tx_rdy = mpc52xx_psc_raw_tx_rdy,
-       .rx_rdy = mpc52xx_psc_rx_rdy,
-       .tx_rdy = mpc52xx_psc_tx_rdy,
-       .tx_empty = mpc52xx_psc_tx_empty,
-       .stop_rx = mpc52xx_psc_stop_rx,
-       .start_tx = mpc52xx_psc_start_tx,
-       .stop_tx = mpc52xx_psc_stop_tx,
-       .rx_clr_irq = mpc52xx_psc_rx_clr_irq,
-       .tx_clr_irq = mpc52xx_psc_tx_clr_irq,
-       .write_char = mpc52xx_psc_write_char,
-       .read_char = mpc52xx_psc_read_char,
-       .cw_disable_ints = mpc52xx_psc_cw_disable_ints,
-       .cw_restore_ints = mpc52xx_psc_cw_restore_ints,
-       .set_baudrate = mpc5200b_psc_set_baudrate,
-       .get_irq = mpc52xx_psc_get_irq,
-       .handle_irq = mpc52xx_psc_handle_irq,
-};
-
-#endif /* CONFIG_MPC52xx */
-
-#ifdef CONFIG_PPC_MPC512x
-#define FIFO_512x(port) ((struct mpc512x_psc_fifo __iomem *)(PSC(port)+1))
-
-/* PSC FIFO Controller for mpc512x */
-struct psc_fifoc {
-       u32 fifoc_cmd;
-       u32 fifoc_int;
-       u32 fifoc_dma;
-       u32 fifoc_axe;
-       u32 fifoc_debug;
-};
-
-static struct psc_fifoc __iomem *psc_fifoc;
-static unsigned int psc_fifoc_irq;
-
-static void mpc512x_psc_fifo_init(struct uart_port *port)
-{
-       /* /32 prescaler */
-       out_be16(&PSC(port)->mpc52xx_psc_clock_select, 0xdd00);
-
-       out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_RESET_SLICE);
-       out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_ENABLE_SLICE);
-       out_be32(&FIFO_512x(port)->txalarm, 1);
-       out_be32(&FIFO_512x(port)->tximr, 0);
-
-       out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_RESET_SLICE);
-       out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_ENABLE_SLICE);
-       out_be32(&FIFO_512x(port)->rxalarm, 1);
-       out_be32(&FIFO_512x(port)->rximr, 0);
-
-       out_be32(&FIFO_512x(port)->tximr, MPC512x_PSC_FIFO_ALARM);
-       out_be32(&FIFO_512x(port)->rximr, MPC512x_PSC_FIFO_ALARM);
-}
-
-static int mpc512x_psc_raw_rx_rdy(struct uart_port *port)
-{
-       return !(in_be32(&FIFO_512x(port)->rxsr) & MPC512x_PSC_FIFO_EMPTY);
-}
-
-static int mpc512x_psc_raw_tx_rdy(struct uart_port *port)
-{
-       return !(in_be32(&FIFO_512x(port)->txsr) & MPC512x_PSC_FIFO_FULL);
-}
-
-static int mpc512x_psc_rx_rdy(struct uart_port *port)
-{
-       return in_be32(&FIFO_512x(port)->rxsr)
-           & in_be32(&FIFO_512x(port)->rximr)
-           & MPC512x_PSC_FIFO_ALARM;
-}
-
-static int mpc512x_psc_tx_rdy(struct uart_port *port)
-{
-       return in_be32(&FIFO_512x(port)->txsr)
-           & in_be32(&FIFO_512x(port)->tximr)
-           & MPC512x_PSC_FIFO_ALARM;
-}
-
-static int mpc512x_psc_tx_empty(struct uart_port *port)
-{
-       return in_be32(&FIFO_512x(port)->txsr)
-           & MPC512x_PSC_FIFO_EMPTY;
-}
-
-static void mpc512x_psc_stop_rx(struct uart_port *port)
-{
-       unsigned long rx_fifo_imr;
-
-       rx_fifo_imr = in_be32(&FIFO_512x(port)->rximr);
-       rx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM;
-       out_be32(&FIFO_512x(port)->rximr, rx_fifo_imr);
-}
-
-static void mpc512x_psc_start_tx(struct uart_port *port)
-{
-       unsigned long tx_fifo_imr;
-
-       tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr);
-       tx_fifo_imr |= MPC512x_PSC_FIFO_ALARM;
-       out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr);
-}
-
-static void mpc512x_psc_stop_tx(struct uart_port *port)
-{
-       unsigned long tx_fifo_imr;
-
-       tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr);
-       tx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM;
-       out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr);
-}
-
-static void mpc512x_psc_rx_clr_irq(struct uart_port *port)
-{
-       out_be32(&FIFO_512x(port)->rxisr, in_be32(&FIFO_512x(port)->rxisr));
-}
-
-static void mpc512x_psc_tx_clr_irq(struct uart_port *port)
-{
-       out_be32(&FIFO_512x(port)->txisr, in_be32(&FIFO_512x(port)->txisr));
-}
-
-static void mpc512x_psc_write_char(struct uart_port *port, unsigned char c)
-{
-       out_8(&FIFO_512x(port)->txdata_8, c);
-}
-
-static unsigned char mpc512x_psc_read_char(struct uart_port *port)
-{
-       return in_8(&FIFO_512x(port)->rxdata_8);
-}
-
-static void mpc512x_psc_cw_disable_ints(struct uart_port *port)
-{
-       port->read_status_mask =
-               in_be32(&FIFO_512x(port)->tximr) << 16 |
-               in_be32(&FIFO_512x(port)->rximr);
-       out_be32(&FIFO_512x(port)->tximr, 0);
-       out_be32(&FIFO_512x(port)->rximr, 0);
-}
-
-static void mpc512x_psc_cw_restore_ints(struct uart_port *port)
-{
-       out_be32(&FIFO_512x(port)->tximr,
-               (port->read_status_mask >> 16) & 0x7f);
-       out_be32(&FIFO_512x(port)->rximr, port->read_status_mask & 0x7f);
-}
-
-static unsigned int mpc512x_psc_set_baudrate(struct uart_port *port,
-                                            struct ktermios *new,
-                                            struct ktermios *old)
-{
-       unsigned int baud;
-       unsigned int divisor;
-
-       /*
-        * The "MPC5121e Microcontroller Reference Manual, Rev. 3" says on
-        * pg. 30-10 that the chip supports a /32 and a /10 prescaler.
-        * Furthermore, it states that "After reset, the prescaler by 10
-        * for the UART mode is selected", but the reset register value is
-        * 0x0000 which means a /32 prescaler. This is wrong.
-        *
-        * In reality using /32 prescaler doesn't work, as it is not supported!
-        * Use /16 or /10 prescaler, see "MPC5121e Hardware Design Guide",
-        * Chapter 4.1 PSC in UART Mode.
-        * Calculate with a /16 prescaler here.
-        */
-
-       /* uartclk contains the ips freq */
-       baud = uart_get_baud_rate(port, new, old,
-                                 port->uartclk / (16 * 0xffff) + 1,
-                                 port->uartclk / 16);
-       divisor = (port->uartclk + 8 * baud) / (16 * baud);
-
-       /* enable the /16 prescaler and set the divisor */
-       mpc52xx_set_divisor(PSC(port), 0xdd00, divisor);
-       return baud;
-}
-
-/* Init PSC FIFO Controller */
-static int __init mpc512x_psc_fifoc_init(void)
-{
-       struct device_node *np;
-
-       np = of_find_compatible_node(NULL, NULL,
-                                    "fsl,mpc5121-psc-fifo");
-       if (!np) {
-               pr_err("%s: Can't find FIFOC node\n", __func__);
-               return -ENODEV;
-       }
-
-       psc_fifoc = of_iomap(np, 0);
-       if (!psc_fifoc) {
-               pr_err("%s: Can't map FIFOC\n", __func__);
-               of_node_put(np);
-               return -ENODEV;
-       }
-
-       psc_fifoc_irq = irq_of_parse_and_map(np, 0);
-       of_node_put(np);
-       if (psc_fifoc_irq == NO_IRQ) {
-               pr_err("%s: Can't get FIFOC irq\n", __func__);
-               iounmap(psc_fifoc);
-               return -ENODEV;
-       }
-
-       return 0;
-}
-
-static void __exit mpc512x_psc_fifoc_uninit(void)
-{
-       iounmap(psc_fifoc);
-}
-
-/* 512x specific interrupt handler. The caller holds the port lock */
-static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port)
-{
-       unsigned long fifoc_int;
-       int psc_num;
-
-       /* Read pending PSC FIFOC interrupts */
-       fifoc_int = in_be32(&psc_fifoc->fifoc_int);
-
-       /* Check if it is an interrupt for this port */
-       psc_num = (port->mapbase & 0xf00) >> 8;
-       if (test_bit(psc_num, &fifoc_int) ||
-           test_bit(psc_num + 16, &fifoc_int))
-               return mpc5xxx_uart_process_int(port);
-
-       return IRQ_NONE;
-}
-
-static int mpc512x_psc_clock(struct uart_port *port, int enable)
-{
-       struct clk *psc_clk;
-       int psc_num;
-       char clk_name[10];
-
-       if (uart_console(port))
-               return 0;
-
-       psc_num = (port->mapbase & 0xf00) >> 8;
-       snprintf(clk_name, sizeof(clk_name), "psc%d_clk", psc_num);
-       psc_clk = clk_get(port->dev, clk_name);
-       if (IS_ERR(psc_clk)) {
-               dev_err(port->dev, "Failed to get PSC clock entry!\n");
-               return -ENODEV;
-       }
-
-       dev_dbg(port->dev, "%s %sable\n", clk_name, enable ? "en" : "dis");
-
-       if (enable)
-               clk_enable(psc_clk);
-       else
-               clk_disable(psc_clk);
-
-       return 0;
-}
-
-static void mpc512x_psc_get_irq(struct uart_port *port, struct device_node *np)
-{
-       port->irqflags = IRQF_SHARED;
-       port->irq = psc_fifoc_irq;
-}
-
-static struct psc_ops mpc512x_psc_ops = {
-       .fifo_init = mpc512x_psc_fifo_init,
-       .raw_rx_rdy = mpc512x_psc_raw_rx_rdy,
-       .raw_tx_rdy = mpc512x_psc_raw_tx_rdy,
-       .rx_rdy = mpc512x_psc_rx_rdy,
-       .tx_rdy = mpc512x_psc_tx_rdy,
-       .tx_empty = mpc512x_psc_tx_empty,
-       .stop_rx = mpc512x_psc_stop_rx,
-       .start_tx = mpc512x_psc_start_tx,
-       .stop_tx = mpc512x_psc_stop_tx,
-       .rx_clr_irq = mpc512x_psc_rx_clr_irq,
-       .tx_clr_irq = mpc512x_psc_tx_clr_irq,
-       .write_char = mpc512x_psc_write_char,
-       .read_char = mpc512x_psc_read_char,
-       .cw_disable_ints = mpc512x_psc_cw_disable_ints,
-       .cw_restore_ints = mpc512x_psc_cw_restore_ints,
-       .set_baudrate = mpc512x_psc_set_baudrate,
-       .clock = mpc512x_psc_clock,
-       .fifoc_init = mpc512x_psc_fifoc_init,
-       .fifoc_uninit = mpc512x_psc_fifoc_uninit,
-       .get_irq = mpc512x_psc_get_irq,
-       .handle_irq = mpc512x_psc_handle_irq,
-};
-#endif
-
-static struct psc_ops *psc_ops;
-
-/* ======================================================================== */
-/* UART operations                                                          */
-/* ======================================================================== */
-
-static unsigned int
-mpc52xx_uart_tx_empty(struct uart_port *port)
-{
-       return psc_ops->tx_empty(port) ? TIOCSER_TEMT : 0;
-}
-
-static void
-mpc52xx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       if (mctrl & TIOCM_RTS)
-               out_8(&PSC(port)->op1, MPC52xx_PSC_OP_RTS);
-       else
-               out_8(&PSC(port)->op0, MPC52xx_PSC_OP_RTS);
-}
-
-static unsigned int
-mpc52xx_uart_get_mctrl(struct uart_port *port)
-{
-       unsigned int ret = TIOCM_DSR;
-       u8 status = in_8(&PSC(port)->mpc52xx_psc_ipcr);
-
-       if (!(status & MPC52xx_PSC_CTS))
-               ret |= TIOCM_CTS;
-       if (!(status & MPC52xx_PSC_DCD))
-               ret |= TIOCM_CAR;
-
-       return ret;
-}
-
-static void
-mpc52xx_uart_stop_tx(struct uart_port *port)
-{
-       /* port->lock taken by caller */
-       psc_ops->stop_tx(port);
-}
-
-static void
-mpc52xx_uart_start_tx(struct uart_port *port)
-{
-       /* port->lock taken by caller */
-       psc_ops->start_tx(port);
-}
-
-static void
-mpc52xx_uart_send_xchar(struct uart_port *port, char ch)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&port->lock, flags);
-
-       port->x_char = ch;
-       if (ch) {
-               /* Make sure tx interrupts are on */
-               /* Truly necessary ??? They should be anyway */
-               psc_ops->start_tx(port);
-       }
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void
-mpc52xx_uart_stop_rx(struct uart_port *port)
-{
-       /* port->lock taken by caller */
-       psc_ops->stop_rx(port);
-}
-
-static void
-mpc52xx_uart_enable_ms(struct uart_port *port)
-{
-       struct mpc52xx_psc __iomem *psc = PSC(port);
-
-       /* clear D_*-bits by reading them */
-       in_8(&psc->mpc52xx_psc_ipcr);
-       /* enable CTS and DCD as IPC interrupts */
-       out_8(&psc->mpc52xx_psc_acr, MPC52xx_PSC_IEC_CTS | MPC52xx_PSC_IEC_DCD);
-
-       port->read_status_mask |= MPC52xx_PSC_IMR_IPC;
-       out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
-}
-
-static void
-mpc52xx_uart_break_ctl(struct uart_port *port, int ctl)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&port->lock, flags);
-
-       if (ctl == -1)
-               out_8(&PSC(port)->command, MPC52xx_PSC_START_BRK);
-       else
-               out_8(&PSC(port)->command, MPC52xx_PSC_STOP_BRK);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static int
-mpc52xx_uart_startup(struct uart_port *port)
-{
-       struct mpc52xx_psc __iomem *psc = PSC(port);
-       int ret;
-
-       if (psc_ops->clock) {
-               ret = psc_ops->clock(port, 1);
-               if (ret)
-                       return ret;
-       }
-
-       /* Request IRQ */
-       ret = request_irq(port->irq, mpc52xx_uart_int,
-                         port->irqflags, "mpc52xx_psc_uart", port);
-       if (ret)
-               return ret;
-
-       /* Reset/activate the port, clear and enable interrupts */
-       out_8(&psc->command, MPC52xx_PSC_RST_RX);
-       out_8(&psc->command, MPC52xx_PSC_RST_TX);
-
-       out_be32(&psc->sicr, 0);        /* UART mode DCD ignored */
-
-       psc_ops->fifo_init(port);
-
-       out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
-       out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
-
-       return 0;
-}
-
-static void
-mpc52xx_uart_shutdown(struct uart_port *port)
-{
-       struct mpc52xx_psc __iomem *psc = PSC(port);
-
-       /* Shut down the port.  Leave TX active if on a console port */
-       out_8(&psc->command, MPC52xx_PSC_RST_RX);
-       if (!uart_console(port))
-               out_8(&psc->command, MPC52xx_PSC_RST_TX);
-
-       port->read_status_mask = 0;
-       out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
-
-       if (psc_ops->clock)
-               psc_ops->clock(port, 0);
-
-       /* Release interrupt */
-       free_irq(port->irq, port);
-}
-
-static void
-mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
-                        struct ktermios *old)
-{
-       struct mpc52xx_psc __iomem *psc = PSC(port);
-       unsigned long flags;
-       unsigned char mr1, mr2;
-       unsigned int j;
-       unsigned int baud;
-
-       /* Prepare what we're gonna write */
-       mr1 = 0;
-
-       switch (new->c_cflag & CSIZE) {
-       case CS5:       mr1 |= MPC52xx_PSC_MODE_5_BITS;
-               break;
-       case CS6:       mr1 |= MPC52xx_PSC_MODE_6_BITS;
-               break;
-       case CS7:       mr1 |= MPC52xx_PSC_MODE_7_BITS;
-               break;
-       case CS8:
-       default:        mr1 |= MPC52xx_PSC_MODE_8_BITS;
-       }
-
-       if (new->c_cflag & PARENB) {
-               mr1 |= (new->c_cflag & PARODD) ?
-                       MPC52xx_PSC_MODE_PARODD : MPC52xx_PSC_MODE_PAREVEN;
-       } else
-               mr1 |= MPC52xx_PSC_MODE_PARNONE;
-
-
-       mr2 = 0;
-
-       if (new->c_cflag & CSTOPB)
-               mr2 |= MPC52xx_PSC_MODE_TWO_STOP;
-       else
-               mr2 |= ((new->c_cflag & CSIZE) == CS5) ?
-                       MPC52xx_PSC_MODE_ONE_STOP_5_BITS :
-                       MPC52xx_PSC_MODE_ONE_STOP;
-
-       if (new->c_cflag & CRTSCTS) {
-               mr1 |= MPC52xx_PSC_MODE_RXRTS;
-               mr2 |= MPC52xx_PSC_MODE_TXCTS;
-       }
-
-       /* Get the lock */
-       spin_lock_irqsave(&port->lock, flags);
-
-       /* Do our best to flush TX & RX, so we don't lose anything */
-       /* But we don't wait indefinitely ! */
-       j = 5000000;    /* Maximum wait */
-       /* FIXME Can't receive chars since set_termios might be called at early
-        * boot for the console, all stuff is not yet ready to receive at that
-        * time and that just makes the kernel oops */
-       /* while (j-- && mpc52xx_uart_int_rx_chars(port)); */
-       while (!mpc52xx_uart_tx_empty(port) && --j)
-               udelay(1);
-
-       if (!j)
-               printk(KERN_ERR "mpc52xx_uart.c: "
-                       "Unable to flush RX & TX fifos in-time in set_termios."
-                       "Some chars may have been lost.\n");
-
-       /* Reset the TX & RX */
-       out_8(&psc->command, MPC52xx_PSC_RST_RX);
-       out_8(&psc->command, MPC52xx_PSC_RST_TX);
-
-       /* Send new mode settings */
-       out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
-       out_8(&psc->mode, mr1);
-       out_8(&psc->mode, mr2);
-       baud = psc_ops->set_baudrate(port, new, old);
-
-       /* Update the per-port timeout */
-       uart_update_timeout(port, new->c_cflag, baud);
-
-       if (UART_ENABLE_MS(port, new->c_cflag))
-               mpc52xx_uart_enable_ms(port);
-
-       /* Reenable TX & RX */
-       out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
-       out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
-
-       /* We're all set, release the lock */
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *
-mpc52xx_uart_type(struct uart_port *port)
-{
-       /*
-        * We keep using PORT_MPC52xx for historic reasons although it applies
-        * for MPC512x, too, but print "MPC5xxx" to not irritate users
-        */
-       return port->type == PORT_MPC52xx ? "MPC5xxx PSC" : NULL;
-}
-
-static void
-mpc52xx_uart_release_port(struct uart_port *port)
-{
-       /* remapped by us ? */
-       if (port->flags & UPF_IOREMAP) {
-               iounmap(port->membase);
-               port->membase = NULL;
-       }
-
-       release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc));
-}
-
-static int
-mpc52xx_uart_request_port(struct uart_port *port)
-{
-       int err;
-
-       if (port->flags & UPF_IOREMAP) /* Need to remap ? */
-               port->membase = ioremap(port->mapbase,
-                                       sizeof(struct mpc52xx_psc));
-
-       if (!port->membase)
-               return -EINVAL;
-
-       err = request_mem_region(port->mapbase, sizeof(struct mpc52xx_psc),
-                       "mpc52xx_psc_uart") != NULL ? 0 : -EBUSY;
-
-       if (err && (port->flags & UPF_IOREMAP)) {
-               iounmap(port->membase);
-               port->membase = NULL;
-       }
-
-       return err;
-}
-
-static void
-mpc52xx_uart_config_port(struct uart_port *port, int flags)
-{
-       if ((flags & UART_CONFIG_TYPE)
-               && (mpc52xx_uart_request_port(port) == 0))
-               port->type = PORT_MPC52xx;
-}
-
-static int
-mpc52xx_uart_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_MPC52xx)
-               return -EINVAL;
-
-       if ((ser->irq != port->irq) ||
-           (ser->io_type != UPIO_MEM) ||
-           (ser->baud_base != port->uartclk)  ||
-           (ser->iomem_base != (void *)port->mapbase) ||
-           (ser->hub6 != 0))
-               return -EINVAL;
-
-       return 0;
-}
-
-
-static struct uart_ops mpc52xx_uart_ops = {
-       .tx_empty       = mpc52xx_uart_tx_empty,
-       .set_mctrl      = mpc52xx_uart_set_mctrl,
-       .get_mctrl      = mpc52xx_uart_get_mctrl,
-       .stop_tx        = mpc52xx_uart_stop_tx,
-       .start_tx       = mpc52xx_uart_start_tx,
-       .send_xchar     = mpc52xx_uart_send_xchar,
-       .stop_rx        = mpc52xx_uart_stop_rx,
-       .enable_ms      = mpc52xx_uart_enable_ms,
-       .break_ctl      = mpc52xx_uart_break_ctl,
-       .startup        = mpc52xx_uart_startup,
-       .shutdown       = mpc52xx_uart_shutdown,
-       .set_termios    = mpc52xx_uart_set_termios,
-/*     .pm             = mpc52xx_uart_pm,              Not supported yet */
-/*     .set_wake       = mpc52xx_uart_set_wake,        Not supported yet */
-       .type           = mpc52xx_uart_type,
-       .release_port   = mpc52xx_uart_release_port,
-       .request_port   = mpc52xx_uart_request_port,
-       .config_port    = mpc52xx_uart_config_port,
-       .verify_port    = mpc52xx_uart_verify_port
-};
-
-
-/* ======================================================================== */
-/* Interrupt handling                                                       */
-/* ======================================================================== */
-
-static inline int
-mpc52xx_uart_int_rx_chars(struct uart_port *port)
-{
-       struct tty_struct *tty = port->state->port.tty;
-       unsigned char ch, flag;
-       unsigned short status;
-
-       /* While we can read, do so ! */
-       while (psc_ops->raw_rx_rdy(port)) {
-               /* Get the char */
-               ch = psc_ops->read_char(port);
-
-               /* Handle sysreq char */
-#ifdef SUPPORT_SYSRQ
-               if (uart_handle_sysrq_char(port, ch)) {
-                       port->sysrq = 0;
-                       continue;
-               }
-#endif
-
-               /* Store it */
-
-               flag = TTY_NORMAL;
-               port->icount.rx++;
-
-               status = in_be16(&PSC(port)->mpc52xx_psc_status);
-
-               if (status & (MPC52xx_PSC_SR_PE |
-                             MPC52xx_PSC_SR_FE |
-                             MPC52xx_PSC_SR_RB)) {
-
-                       if (status & MPC52xx_PSC_SR_RB) {
-                               flag = TTY_BREAK;
-                               uart_handle_break(port);
-                               port->icount.brk++;
-                       } else if (status & MPC52xx_PSC_SR_PE) {
-                               flag = TTY_PARITY;
-                               port->icount.parity++;
-                       }
-                       else if (status & MPC52xx_PSC_SR_FE) {
-                               flag = TTY_FRAME;
-                               port->icount.frame++;
-                       }
-
-                       /* Clear error condition */
-                       out_8(&PSC(port)->command, MPC52xx_PSC_RST_ERR_STAT);
-
-               }
-               tty_insert_flip_char(tty, ch, flag);
-               if (status & MPC52xx_PSC_SR_OE) {
-                       /*
-                        * Overrun is special, since it's
-                        * reported immediately, and doesn't
-                        * affect the current character
-                        */
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-                       port->icount.overrun++;
-               }
-       }
-
-       spin_unlock(&port->lock);
-       tty_flip_buffer_push(tty);
-       spin_lock(&port->lock);
-
-       return psc_ops->raw_rx_rdy(port);
-}
-
-static inline int
-mpc52xx_uart_int_tx_chars(struct uart_port *port)
-{
-       struct circ_buf *xmit = &port->state->xmit;
-
-       /* Process out of band chars */
-       if (port->x_char) {
-               psc_ops->write_char(port, port->x_char);
-               port->icount.tx++;
-               port->x_char = 0;
-               return 1;
-       }
-
-       /* Nothing to do ? */
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               mpc52xx_uart_stop_tx(port);
-               return 0;
-       }
-
-       /* Send chars */
-       while (psc_ops->raw_tx_rdy(port)) {
-               psc_ops->write_char(port, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       }
-
-       /* Wake up */
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       /* Maybe we're done after all */
-       if (uart_circ_empty(xmit)) {
-               mpc52xx_uart_stop_tx(port);
-               return 0;
-       }
-
-       return 1;
-}
-
-static irqreturn_t
-mpc5xxx_uart_process_int(struct uart_port *port)
-{
-       unsigned long pass = ISR_PASS_LIMIT;
-       unsigned int keepgoing;
-       u8 status;
-
-       /* While we have stuff to do, we continue */
-       do {
-               /* If we don't find anything to do, we stop */
-               keepgoing = 0;
-
-               psc_ops->rx_clr_irq(port);
-               if (psc_ops->rx_rdy(port))
-                       keepgoing |= mpc52xx_uart_int_rx_chars(port);
-
-               psc_ops->tx_clr_irq(port);
-               if (psc_ops->tx_rdy(port))
-                       keepgoing |= mpc52xx_uart_int_tx_chars(port);
-
-               status = in_8(&PSC(port)->mpc52xx_psc_ipcr);
-               if (status & MPC52xx_PSC_D_DCD)
-                       uart_handle_dcd_change(port, !(status & MPC52xx_PSC_DCD));
-
-               if (status & MPC52xx_PSC_D_CTS)
-                       uart_handle_cts_change(port, !(status & MPC52xx_PSC_CTS));
-
-               /* Limit number of iteration */
-               if (!(--pass))
-                       keepgoing = 0;
-
-       } while (keepgoing);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t
-mpc52xx_uart_int(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       irqreturn_t ret;
-
-       spin_lock(&port->lock);
-
-       ret = psc_ops->handle_irq(port);
-
-       spin_unlock(&port->lock);
-
-       return ret;
-}
-
-/* ======================================================================== */
-/* Console ( if applicable )                                                */
-/* ======================================================================== */
-
-#ifdef CONFIG_SERIAL_MPC52xx_CONSOLE
-
-static void __init
-mpc52xx_console_get_options(struct uart_port *port,
-                           int *baud, int *parity, int *bits, int *flow)
-{
-       struct mpc52xx_psc __iomem *psc = PSC(port);
-       unsigned char mr1;
-
-       pr_debug("mpc52xx_console_get_options(port=%p)\n", port);
-
-       /* Read the mode registers */
-       out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
-       mr1 = in_8(&psc->mode);
-
-       /* CT{U,L}R are write-only ! */
-       *baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
-
-       /* Parse them */
-       switch (mr1 & MPC52xx_PSC_MODE_BITS_MASK) {
-       case MPC52xx_PSC_MODE_5_BITS:
-               *bits = 5;
-               break;
-       case MPC52xx_PSC_MODE_6_BITS:
-               *bits = 6;
-               break;
-       case MPC52xx_PSC_MODE_7_BITS:
-               *bits = 7;
-               break;
-       case MPC52xx_PSC_MODE_8_BITS:
-       default:
-               *bits = 8;
-       }
-
-       if (mr1 & MPC52xx_PSC_MODE_PARNONE)
-               *parity = 'n';
-       else
-               *parity = mr1 & MPC52xx_PSC_MODE_PARODD ? 'o' : 'e';
-}
-
-static void
-mpc52xx_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct uart_port *port = &mpc52xx_uart_ports[co->index];
-       unsigned int i, j;
-
-       /* Disable interrupts */
-       psc_ops->cw_disable_ints(port);
-
-       /* Wait the TX buffer to be empty */
-       j = 5000000;    /* Maximum wait */
-       while (!mpc52xx_uart_tx_empty(port) && --j)
-               udelay(1);
-
-       /* Write all the chars */
-       for (i = 0; i < count; i++, s++) {
-               /* Line return handling */
-               if (*s == '\n')
-                       psc_ops->write_char(port, '\r');
-
-               /* Send the char */
-               psc_ops->write_char(port, *s);
-
-               /* Wait the TX buffer to be empty */
-               j = 20000;      /* Maximum wait */
-               while (!mpc52xx_uart_tx_empty(port) && --j)
-                       udelay(1);
-       }
-
-       /* Restore interrupt state */
-       psc_ops->cw_restore_ints(port);
-}
-
-
-static int __init
-mpc52xx_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port = &mpc52xx_uart_ports[co->index];
-       struct device_node *np = mpc52xx_uart_nodes[co->index];
-       unsigned int uartclk;
-       struct resource res;
-       int ret;
-
-       int baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       pr_debug("mpc52xx_console_setup co=%p, co->index=%i, options=%s\n",
-                co, co->index, options);
-
-       if ((co->index < 0) || (co->index >= MPC52xx_PSC_MAXNUM)) {
-               pr_debug("PSC%x out of range\n", co->index);
-               return -EINVAL;
-       }
-
-       if (!np) {
-               pr_debug("PSC%x not found in device tree\n", co->index);
-               return -EINVAL;
-       }
-
-       pr_debug("Console on ttyPSC%x is %s\n",
-                co->index, mpc52xx_uart_nodes[co->index]->full_name);
-
-       /* Fetch register locations */
-       ret = of_address_to_resource(np, 0, &res);
-       if (ret) {
-               pr_debug("Could not get resources for PSC%x\n", co->index);
-               return ret;
-       }
-
-       uartclk = mpc5xxx_get_bus_frequency(np);
-       if (uartclk == 0) {
-               pr_debug("Could not find uart clock frequency!\n");
-               return -EINVAL;
-       }
-
-       /* Basic port init. Needed since we use some uart_??? func before
-        * real init for early access */
-       spin_lock_init(&port->lock);
-       port->uartclk = uartclk;
-       port->ops       = &mpc52xx_uart_ops;
-       port->mapbase = res.start;
-       port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc));
-       port->irq = irq_of_parse_and_map(np, 0);
-
-       if (port->membase == NULL)
-               return -EINVAL;
-
-       pr_debug("mpc52xx-psc uart at %p, mapped to %p, irq=%x, freq=%i\n",
-                (void *)port->mapbase, port->membase,
-                port->irq, port->uartclk);
-
-       /* Setup the port parameters accoding to options */
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               mpc52xx_console_get_options(port, &baud, &parity, &bits, &flow);
-
-       pr_debug("Setting console parameters: %i %i%c1 flow=%c\n",
-                baud, bits, parity, flow);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-
-static struct uart_driver mpc52xx_uart_driver;
-
-static struct console mpc52xx_console = {
-       .name   = "ttyPSC",
-       .write  = mpc52xx_console_write,
-       .device = uart_console_device,
-       .setup  = mpc52xx_console_setup,
-       .flags  = CON_PRINTBUFFER,
-       .index  = -1,   /* Specified on the cmdline (e.g. console=ttyPSC0) */
-       .data   = &mpc52xx_uart_driver,
-};
-
-
-static int __init
-mpc52xx_console_init(void)
-{
-       mpc52xx_uart_of_enumerate();
-       register_console(&mpc52xx_console);
-       return 0;
-}
-
-console_initcall(mpc52xx_console_init);
-
-#define MPC52xx_PSC_CONSOLE &mpc52xx_console
-#else
-#define MPC52xx_PSC_CONSOLE NULL
-#endif
-
-
-/* ======================================================================== */
-/* UART Driver                                                              */
-/* ======================================================================== */
-
-static struct uart_driver mpc52xx_uart_driver = {
-       .driver_name    = "mpc52xx_psc_uart",
-       .dev_name       = "ttyPSC",
-       .major          = SERIAL_PSC_MAJOR,
-       .minor          = SERIAL_PSC_MINOR,
-       .nr             = MPC52xx_PSC_MAXNUM,
-       .cons           = MPC52xx_PSC_CONSOLE,
-};
-
-/* ======================================================================== */
-/* OF Platform Driver                                                       */
-/* ======================================================================== */
-
-static struct of_device_id mpc52xx_uart_of_match[] = {
-#ifdef CONFIG_PPC_MPC52xx
-       { .compatible = "fsl,mpc5200b-psc-uart", .data = &mpc5200b_psc_ops, },
-       { .compatible = "fsl,mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
-       /* binding used by old lite5200 device trees: */
-       { .compatible = "mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
-       /* binding used by efika: */
-       { .compatible = "mpc5200-serial", .data = &mpc52xx_psc_ops, },
-#endif
-#ifdef CONFIG_PPC_MPC512x
-       { .compatible = "fsl,mpc5121-psc-uart", .data = &mpc512x_psc_ops, },
-#endif
-       {},
-};
-
-static int __devinit
-mpc52xx_uart_of_probe(struct platform_device *op, const struct of_device_id *match)
-{
-       int idx = -1;
-       unsigned int uartclk;
-       struct uart_port *port = NULL;
-       struct resource res;
-       int ret;
-
-       dev_dbg(&op->dev, "mpc52xx_uart_probe(op=%p, match=%p)\n", op, match);
-
-       /* Check validity & presence */
-       for (idx = 0; idx < MPC52xx_PSC_MAXNUM; idx++)
-               if (mpc52xx_uart_nodes[idx] == op->dev.of_node)
-                       break;
-       if (idx >= MPC52xx_PSC_MAXNUM)
-               return -EINVAL;
-       pr_debug("Found %s assigned to ttyPSC%x\n",
-                mpc52xx_uart_nodes[idx]->full_name, idx);
-
-       /* set the uart clock to the input clock of the psc, the different
-        * prescalers are taken into account in the set_baudrate() methods
-        * of the respective chip */
-       uartclk = mpc5xxx_get_bus_frequency(op->dev.of_node);
-       if (uartclk == 0) {
-               dev_dbg(&op->dev, "Could not find uart clock frequency!\n");
-               return -EINVAL;
-       }
-
-       /* Init the port structure */
-       port = &mpc52xx_uart_ports[idx];
-
-       spin_lock_init(&port->lock);
-       port->uartclk = uartclk;
-       port->fifosize  = 512;
-       port->iotype    = UPIO_MEM;
-       port->flags     = UPF_BOOT_AUTOCONF |
-                         (uart_console(port) ? 0 : UPF_IOREMAP);
-       port->line      = idx;
-       port->ops       = &mpc52xx_uart_ops;
-       port->dev       = &op->dev;
-
-       /* Search for IRQ and mapbase */
-       ret = of_address_to_resource(op->dev.of_node, 0, &res);
-       if (ret)
-               return ret;
-
-       port->mapbase = res.start;
-       if (!port->mapbase) {
-               dev_dbg(&op->dev, "Could not allocate resources for PSC\n");
-               return -EINVAL;
-       }
-
-       psc_ops->get_irq(port, op->dev.of_node);
-       if (port->irq == NO_IRQ) {
-               dev_dbg(&op->dev, "Could not get irq\n");
-               return -EINVAL;
-       }
-
-       dev_dbg(&op->dev, "mpc52xx-psc uart at %p, irq=%x, freq=%i\n",
-               (void *)port->mapbase, port->irq, port->uartclk);
-
-       /* Add the port to the uart sub-system */
-       ret = uart_add_one_port(&mpc52xx_uart_driver, port);
-       if (ret)
-               return ret;
-
-       dev_set_drvdata(&op->dev, (void *)port);
-       return 0;
-}
-
-static int
-mpc52xx_uart_of_remove(struct platform_device *op)
-{
-       struct uart_port *port = dev_get_drvdata(&op->dev);
-       dev_set_drvdata(&op->dev, NULL);
-
-       if (port)
-               uart_remove_one_port(&mpc52xx_uart_driver, port);
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int
-mpc52xx_uart_of_suspend(struct platform_device *op, pm_message_t state)
-{
-       struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev);
-
-       if (port)
-               uart_suspend_port(&mpc52xx_uart_driver, port);
-
-       return 0;
-}
-
-static int
-mpc52xx_uart_of_resume(struct platform_device *op)
-{
-       struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev);
-
-       if (port)
-               uart_resume_port(&mpc52xx_uart_driver, port);
-
-       return 0;
-}
-#endif
-
-static void
-mpc52xx_uart_of_assign(struct device_node *np)
-{
-       int i;
-
-       /* Find the first free PSC number */
-       for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) {
-               if (mpc52xx_uart_nodes[i] == NULL) {
-                       of_node_get(np);
-                       mpc52xx_uart_nodes[i] = np;
-                       return;
-               }
-       }
-}
-
-static void
-mpc52xx_uart_of_enumerate(void)
-{
-       static int enum_done;
-       struct device_node *np;
-       const struct  of_device_id *match;
-       int i;
-
-       if (enum_done)
-               return;
-
-       /* Assign index to each PSC in device tree */
-       for_each_matching_node(np, mpc52xx_uart_of_match) {
-               match = of_match_node(mpc52xx_uart_of_match, np);
-               psc_ops = match->data;
-               mpc52xx_uart_of_assign(np);
-       }
-
-       enum_done = 1;
-
-       for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) {
-               if (mpc52xx_uart_nodes[i])
-                       pr_debug("%s assigned to ttyPSC%x\n",
-                                mpc52xx_uart_nodes[i]->full_name, i);
-       }
-}
-
-MODULE_DEVICE_TABLE(of, mpc52xx_uart_of_match);
-
-static struct of_platform_driver mpc52xx_uart_of_driver = {
-       .probe          = mpc52xx_uart_of_probe,
-       .remove         = mpc52xx_uart_of_remove,
-#ifdef CONFIG_PM
-       .suspend        = mpc52xx_uart_of_suspend,
-       .resume         = mpc52xx_uart_of_resume,
-#endif
-       .driver = {
-               .name = "mpc52xx-psc-uart",
-               .owner = THIS_MODULE,
-               .of_match_table = mpc52xx_uart_of_match,
-       },
-};
-
-
-/* ======================================================================== */
-/* Module                                                                   */
-/* ======================================================================== */
-
-static int __init
-mpc52xx_uart_init(void)
-{
-       int ret;
-
-       printk(KERN_INFO "Serial: MPC52xx PSC UART driver\n");
-
-       ret = uart_register_driver(&mpc52xx_uart_driver);
-       if (ret) {
-               printk(KERN_ERR "%s: uart_register_driver failed (%i)\n",
-                      __FILE__, ret);
-               return ret;
-       }
-
-       mpc52xx_uart_of_enumerate();
-
-       /*
-        * Map the PSC FIFO Controller and init if on MPC512x.
-        */
-       if (psc_ops && psc_ops->fifoc_init) {
-               ret = psc_ops->fifoc_init();
-               if (ret)
-                       return ret;
-       }
-
-       ret = of_register_platform_driver(&mpc52xx_uart_of_driver);
-       if (ret) {
-               printk(KERN_ERR "%s: of_register_platform_driver failed (%i)\n",
-                      __FILE__, ret);
-               uart_unregister_driver(&mpc52xx_uart_driver);
-               return ret;
-       }
-
-       return 0;
-}
-
-static void __exit
-mpc52xx_uart_exit(void)
-{
-       if (psc_ops->fifoc_uninit)
-               psc_ops->fifoc_uninit();
-
-       of_unregister_platform_driver(&mpc52xx_uart_of_driver);
-       uart_unregister_driver(&mpc52xx_uart_driver);
-}
-
-
-module_init(mpc52xx_uart_init);
-module_exit(mpc52xx_uart_exit);
-
-MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>");
-MODULE_DESCRIPTION("Freescale MPC52xx PSC UART");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c
deleted file mode 100644 (file)
index 6a9c660..0000000
+++ /dev/null
@@ -1,2159 +0,0 @@
-/*
- * Generic driver for the MPSC (UART mode) on Marvell parts (e.g., GT64240,
- * GT64260, MV64340, MV64360, GT96100, ... ).
- *
- * Author: Mark A. Greer <mgreer@mvista.com>
- *
- * Based on an old MPSC driver that was in the linuxppc tree.  It appears to
- * have been created by Chris Zankel (formerly of MontaVista) but there
- * is no proper Copyright so I'm not sure.  Apparently, parts were also
- * taken from PPCBoot (now U-Boot).  Also based on drivers/serial/8250.c
- * by Russell King.
- *
- * 2004 (c) MontaVista, Software, Inc.  This file is licensed under
- * the terms of the GNU General Public License version 2.  This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-/*
- * The MPSC interface is much like a typical network controller's interface.
- * That is, you set up separate rings of descriptors for transmitting and
- * receiving data.  There is also a pool of buffers with (one buffer per
- * descriptor) that incoming data are dma'd into or outgoing data are dma'd
- * out of.
- *
- * The MPSC requires two other controllers to be able to work.  The Baud Rate
- * Generator (BRG) provides a clock at programmable frequencies which determines
- * the baud rate.  The Serial DMA Controller (SDMA) takes incoming data from the
- * MPSC and DMA's it into memory or DMA's outgoing data and passes it to the
- * MPSC.  It is actually the SDMA interrupt that the driver uses to keep the
- * transmit and receive "engines" going (i.e., indicate data has been
- * transmitted or received).
- *
- * NOTES:
- *
- * 1) Some chips have an erratum where several regs cannot be
- * read.  To work around that, we keep a local copy of those regs in
- * 'mpsc_port_info'.
- *
- * 2) Some chips have an erratum where the ctlr will hang when the SDMA ctlr
- * accesses system mem with coherency enabled.  For that reason, the driver
- * assumes that coherency for that ctlr has been disabled.  This means
- * that when in a cache coherent system, the driver has to manually manage
- * the data cache on the areas that it touches because the dma_* macro are
- * basically no-ops.
- *
- * 3) There is an erratum (on PPC) where you can't use the instruction to do
- * a DMA_TO_DEVICE/cache clean so DMA_BIDIRECTIONAL/flushes are used in places
- * where a DMA_TO_DEVICE/clean would have [otherwise] sufficed.
- *
- * 4) AFAICT, hardware flow control isn't supported by the controller --MAG.
- */
-
-
-#if defined(CONFIG_SERIAL_MPSC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/mv643xx.h>
-#include <linux/platform_device.h>
-#include <linux/gfp.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#define        MPSC_NUM_CTLRS          2
-
-/*
- * Descriptors and buffers must be cache line aligned.
- * Buffers lengths must be multiple of cache line size.
- * Number of Tx & Rx descriptors must be powers of 2.
- */
-#define        MPSC_RXR_ENTRIES        32
-#define        MPSC_RXRE_SIZE          dma_get_cache_alignment()
-#define        MPSC_RXR_SIZE           (MPSC_RXR_ENTRIES * MPSC_RXRE_SIZE)
-#define        MPSC_RXBE_SIZE          dma_get_cache_alignment()
-#define        MPSC_RXB_SIZE           (MPSC_RXR_ENTRIES * MPSC_RXBE_SIZE)
-
-#define        MPSC_TXR_ENTRIES        32
-#define        MPSC_TXRE_SIZE          dma_get_cache_alignment()
-#define        MPSC_TXR_SIZE           (MPSC_TXR_ENTRIES * MPSC_TXRE_SIZE)
-#define        MPSC_TXBE_SIZE          dma_get_cache_alignment()
-#define        MPSC_TXB_SIZE           (MPSC_TXR_ENTRIES * MPSC_TXBE_SIZE)
-
-#define        MPSC_DMA_ALLOC_SIZE     (MPSC_RXR_SIZE + MPSC_RXB_SIZE + MPSC_TXR_SIZE \
-               + MPSC_TXB_SIZE + dma_get_cache_alignment() /* for alignment */)
-
-/* Rx and Tx Ring entry descriptors -- assume entry size is <= cacheline size */
-struct mpsc_rx_desc {
-       u16 bufsize;
-       u16 bytecnt;
-       u32 cmdstat;
-       u32 link;
-       u32 buf_ptr;
-} __attribute((packed));
-
-struct mpsc_tx_desc {
-       u16 bytecnt;
-       u16 shadow;
-       u32 cmdstat;
-       u32 link;
-       u32 buf_ptr;
-} __attribute((packed));
-
-/*
- * Some regs that have the erratum that you can't read them are are shared
- * between the two MPSC controllers.  This struct contains those shared regs.
- */
-struct mpsc_shared_regs {
-       phys_addr_t mpsc_routing_base_p;
-       phys_addr_t sdma_intr_base_p;
-
-       void __iomem *mpsc_routing_base;
-       void __iomem *sdma_intr_base;
-
-       u32 MPSC_MRR_m;
-       u32 MPSC_RCRR_m;
-       u32 MPSC_TCRR_m;
-       u32 SDMA_INTR_CAUSE_m;
-       u32 SDMA_INTR_MASK_m;
-};
-
-/* The main driver data structure */
-struct mpsc_port_info {
-       struct uart_port port;  /* Overlay uart_port structure */
-
-       /* Internal driver state for this ctlr */
-       u8 ready;
-       u8 rcv_data;
-       tcflag_t c_iflag;       /* save termios->c_iflag */
-       tcflag_t c_cflag;       /* save termios->c_cflag */
-
-       /* Info passed in from platform */
-       u8 mirror_regs;         /* Need to mirror regs? */
-       u8 cache_mgmt;          /* Need manual cache mgmt? */
-       u8 brg_can_tune;        /* BRG has baud tuning? */
-       u32 brg_clk_src;
-       u16 mpsc_max_idle;
-       int default_baud;
-       int default_bits;
-       int default_parity;
-       int default_flow;
-
-       /* Physical addresses of various blocks of registers (from platform) */
-       phys_addr_t mpsc_base_p;
-       phys_addr_t sdma_base_p;
-       phys_addr_t brg_base_p;
-
-       /* Virtual addresses of various blocks of registers (from platform) */
-       void __iomem *mpsc_base;
-       void __iomem *sdma_base;
-       void __iomem *brg_base;
-
-       /* Descriptor ring and buffer allocations */
-       void *dma_region;
-       dma_addr_t dma_region_p;
-
-       dma_addr_t rxr;         /* Rx descriptor ring */
-       dma_addr_t rxr_p;       /* Phys addr of rxr */
-       u8 *rxb;                /* Rx Ring I/O buf */
-       u8 *rxb_p;              /* Phys addr of rxb */
-       u32 rxr_posn;           /* First desc w/ Rx data */
-
-       dma_addr_t txr;         /* Tx descriptor ring */
-       dma_addr_t txr_p;       /* Phys addr of txr */
-       u8 *txb;                /* Tx Ring I/O buf */
-       u8 *txb_p;              /* Phys addr of txb */
-       int txr_head;           /* Where new data goes */
-       int txr_tail;           /* Where sent data comes off */
-       spinlock_t tx_lock;     /* transmit lock */
-
-       /* Mirrored values of regs we can't read (if 'mirror_regs' set) */
-       u32 MPSC_MPCR_m;
-       u32 MPSC_CHR_1_m;
-       u32 MPSC_CHR_2_m;
-       u32 MPSC_CHR_10_m;
-       u32 BRG_BCR_m;
-       struct mpsc_shared_regs *shared_regs;
-};
-
-/* Hooks to platform-specific code */
-int mpsc_platform_register_driver(void);
-void mpsc_platform_unregister_driver(void);
-
-/* Hooks back in to mpsc common to be called by platform-specific code */
-struct mpsc_port_info *mpsc_device_probe(int index);
-struct mpsc_port_info *mpsc_device_remove(int index);
-
-/* Main MPSC Configuration Register Offsets */
-#define        MPSC_MMCRL                      0x0000
-#define        MPSC_MMCRH                      0x0004
-#define        MPSC_MPCR                       0x0008
-#define        MPSC_CHR_1                      0x000c
-#define        MPSC_CHR_2                      0x0010
-#define        MPSC_CHR_3                      0x0014
-#define        MPSC_CHR_4                      0x0018
-#define        MPSC_CHR_5                      0x001c
-#define        MPSC_CHR_6                      0x0020
-#define        MPSC_CHR_7                      0x0024
-#define        MPSC_CHR_8                      0x0028
-#define        MPSC_CHR_9                      0x002c
-#define        MPSC_CHR_10                     0x0030
-#define        MPSC_CHR_11                     0x0034
-
-#define        MPSC_MPCR_FRZ                   (1 << 9)
-#define        MPSC_MPCR_CL_5                  0
-#define        MPSC_MPCR_CL_6                  1
-#define        MPSC_MPCR_CL_7                  2
-#define        MPSC_MPCR_CL_8                  3
-#define        MPSC_MPCR_SBL_1                 0
-#define        MPSC_MPCR_SBL_2                 1
-
-#define        MPSC_CHR_2_TEV                  (1<<1)
-#define        MPSC_CHR_2_TA                   (1<<7)
-#define        MPSC_CHR_2_TTCS                 (1<<9)
-#define        MPSC_CHR_2_REV                  (1<<17)
-#define        MPSC_CHR_2_RA                   (1<<23)
-#define        MPSC_CHR_2_CRD                  (1<<25)
-#define        MPSC_CHR_2_EH                   (1<<31)
-#define        MPSC_CHR_2_PAR_ODD              0
-#define        MPSC_CHR_2_PAR_SPACE            1
-#define        MPSC_CHR_2_PAR_EVEN             2
-#define        MPSC_CHR_2_PAR_MARK             3
-
-/* MPSC Signal Routing */
-#define        MPSC_MRR                        0x0000
-#define        MPSC_RCRR                       0x0004
-#define        MPSC_TCRR                       0x0008
-
-/* Serial DMA Controller Interface Registers */
-#define        SDMA_SDC                        0x0000
-#define        SDMA_SDCM                       0x0008
-#define        SDMA_RX_DESC                    0x0800
-#define        SDMA_RX_BUF_PTR                 0x0808
-#define        SDMA_SCRDP                      0x0810
-#define        SDMA_TX_DESC                    0x0c00
-#define        SDMA_SCTDP                      0x0c10
-#define        SDMA_SFTDP                      0x0c14
-
-#define        SDMA_DESC_CMDSTAT_PE            (1<<0)
-#define        SDMA_DESC_CMDSTAT_CDL           (1<<1)
-#define        SDMA_DESC_CMDSTAT_FR            (1<<3)
-#define        SDMA_DESC_CMDSTAT_OR            (1<<6)
-#define        SDMA_DESC_CMDSTAT_BR            (1<<9)
-#define        SDMA_DESC_CMDSTAT_MI            (1<<10)
-#define        SDMA_DESC_CMDSTAT_A             (1<<11)
-#define        SDMA_DESC_CMDSTAT_AM            (1<<12)
-#define        SDMA_DESC_CMDSTAT_CT            (1<<13)
-#define        SDMA_DESC_CMDSTAT_C             (1<<14)
-#define        SDMA_DESC_CMDSTAT_ES            (1<<15)
-#define        SDMA_DESC_CMDSTAT_L             (1<<16)
-#define        SDMA_DESC_CMDSTAT_F             (1<<17)
-#define        SDMA_DESC_CMDSTAT_P             (1<<18)
-#define        SDMA_DESC_CMDSTAT_EI            (1<<23)
-#define        SDMA_DESC_CMDSTAT_O             (1<<31)
-
-#define SDMA_DESC_DFLT                 (SDMA_DESC_CMDSTAT_O \
-               | SDMA_DESC_CMDSTAT_EI)
-
-#define        SDMA_SDC_RFT                    (1<<0)
-#define        SDMA_SDC_SFM                    (1<<1)
-#define        SDMA_SDC_BLMR                   (1<<6)
-#define        SDMA_SDC_BLMT                   (1<<7)
-#define        SDMA_SDC_POVR                   (1<<8)
-#define        SDMA_SDC_RIFB                   (1<<9)
-
-#define        SDMA_SDCM_ERD                   (1<<7)
-#define        SDMA_SDCM_AR                    (1<<15)
-#define        SDMA_SDCM_STD                   (1<<16)
-#define        SDMA_SDCM_TXD                   (1<<23)
-#define        SDMA_SDCM_AT                    (1<<31)
-
-#define        SDMA_0_CAUSE_RXBUF              (1<<0)
-#define        SDMA_0_CAUSE_RXERR              (1<<1)
-#define        SDMA_0_CAUSE_TXBUF              (1<<2)
-#define        SDMA_0_CAUSE_TXEND              (1<<3)
-#define        SDMA_1_CAUSE_RXBUF              (1<<8)
-#define        SDMA_1_CAUSE_RXERR              (1<<9)
-#define        SDMA_1_CAUSE_TXBUF              (1<<10)
-#define        SDMA_1_CAUSE_TXEND              (1<<11)
-
-#define        SDMA_CAUSE_RX_MASK      (SDMA_0_CAUSE_RXBUF | SDMA_0_CAUSE_RXERR \
-               | SDMA_1_CAUSE_RXBUF | SDMA_1_CAUSE_RXERR)
-#define        SDMA_CAUSE_TX_MASK      (SDMA_0_CAUSE_TXBUF | SDMA_0_CAUSE_TXEND \
-               | SDMA_1_CAUSE_TXBUF | SDMA_1_CAUSE_TXEND)
-
-/* SDMA Interrupt registers */
-#define        SDMA_INTR_CAUSE                 0x0000
-#define        SDMA_INTR_MASK                  0x0080
-
-/* Baud Rate Generator Interface Registers */
-#define        BRG_BCR                         0x0000
-#define        BRG_BTR                         0x0004
-
-/*
- * Define how this driver is known to the outside (we've been assigned a
- * range on the "Low-density serial ports" major).
- */
-#define MPSC_MAJOR                     204
-#define MPSC_MINOR_START               44
-#define        MPSC_DRIVER_NAME                "MPSC"
-#define        MPSC_DEV_NAME                   "ttyMM"
-#define        MPSC_VERSION                    "1.00"
-
-static struct mpsc_port_info mpsc_ports[MPSC_NUM_CTLRS];
-static struct mpsc_shared_regs mpsc_shared_regs;
-static struct uart_driver mpsc_reg;
-
-static void mpsc_start_rx(struct mpsc_port_info *pi);
-static void mpsc_free_ring_mem(struct mpsc_port_info *pi);
-static void mpsc_release_port(struct uart_port *port);
-/*
- ******************************************************************************
- *
- * Baud Rate Generator Routines (BRG)
- *
- ******************************************************************************
- */
-static void mpsc_brg_init(struct mpsc_port_info *pi, u32 clk_src)
-{
-       u32     v;
-
-       v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR);
-       v = (v & ~(0xf << 18)) | ((clk_src & 0xf) << 18);
-
-       if (pi->brg_can_tune)
-               v &= ~(1 << 25);
-
-       if (pi->mirror_regs)
-               pi->BRG_BCR_m = v;
-       writel(v, pi->brg_base + BRG_BCR);
-
-       writel(readl(pi->brg_base + BRG_BTR) & 0xffff0000,
-               pi->brg_base + BRG_BTR);
-}
-
-static void mpsc_brg_enable(struct mpsc_port_info *pi)
-{
-       u32     v;
-
-       v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR);
-       v |= (1 << 16);
-
-       if (pi->mirror_regs)
-               pi->BRG_BCR_m = v;
-       writel(v, pi->brg_base + BRG_BCR);
-}
-
-static void mpsc_brg_disable(struct mpsc_port_info *pi)
-{
-       u32     v;
-
-       v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR);
-       v &= ~(1 << 16);
-
-       if (pi->mirror_regs)
-               pi->BRG_BCR_m = v;
-       writel(v, pi->brg_base + BRG_BCR);
-}
-
-/*
- * To set the baud, we adjust the CDV field in the BRG_BCR reg.
- * From manual: Baud = clk / ((CDV+1)*2) ==> CDV = (clk / (baud*2)) - 1.
- * However, the input clock is divided by 16 in the MPSC b/c of how
- * 'MPSC_MMCRH' was set up so we have to divide the 'clk' used in our
- * calculation by 16 to account for that.  So the real calculation
- * that accounts for the way the mpsc is set up is:
- * CDV = (clk / (baud*2*16)) - 1 ==> CDV = (clk / (baud << 5)) - 1.
- */
-static void mpsc_set_baudrate(struct mpsc_port_info *pi, u32 baud)
-{
-       u32     cdv = (pi->port.uartclk / (baud << 5)) - 1;
-       u32     v;
-
-       mpsc_brg_disable(pi);
-       v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR);
-       v = (v & 0xffff0000) | (cdv & 0xffff);
-
-       if (pi->mirror_regs)
-               pi->BRG_BCR_m = v;
-       writel(v, pi->brg_base + BRG_BCR);
-       mpsc_brg_enable(pi);
-}
-
-/*
- ******************************************************************************
- *
- * Serial DMA Routines (SDMA)
- *
- ******************************************************************************
- */
-
-static void mpsc_sdma_burstsize(struct mpsc_port_info *pi, u32 burst_size)
-{
-       u32     v;
-
-       pr_debug("mpsc_sdma_burstsize[%d]: burst_size: %d\n",
-                       pi->port.line, burst_size);
-
-       burst_size >>= 3; /* Divide by 8 b/c reg values are 8-byte chunks */
-
-       if (burst_size < 2)
-               v = 0x0;        /* 1 64-bit word */
-       else if (burst_size < 4)
-               v = 0x1;        /* 2 64-bit words */
-       else if (burst_size < 8)
-               v = 0x2;        /* 4 64-bit words */
-       else
-               v = 0x3;        /* 8 64-bit words */
-
-       writel((readl(pi->sdma_base + SDMA_SDC) & (0x3 << 12)) | (v << 12),
-               pi->sdma_base + SDMA_SDC);
-}
-
-static void mpsc_sdma_init(struct mpsc_port_info *pi, u32 burst_size)
-{
-       pr_debug("mpsc_sdma_init[%d]: burst_size: %d\n", pi->port.line,
-               burst_size);
-
-       writel((readl(pi->sdma_base + SDMA_SDC) & 0x3ff) | 0x03f,
-               pi->sdma_base + SDMA_SDC);
-       mpsc_sdma_burstsize(pi, burst_size);
-}
-
-static u32 mpsc_sdma_intr_mask(struct mpsc_port_info *pi, u32 mask)
-{
-       u32     old, v;
-
-       pr_debug("mpsc_sdma_intr_mask[%d]: mask: 0x%x\n", pi->port.line, mask);
-
-       old = v = (pi->mirror_regs) ? pi->shared_regs->SDMA_INTR_MASK_m :
-               readl(pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
-
-       mask &= 0xf;
-       if (pi->port.line)
-               mask <<= 8;
-       v &= ~mask;
-
-       if (pi->mirror_regs)
-               pi->shared_regs->SDMA_INTR_MASK_m = v;
-       writel(v, pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
-
-       if (pi->port.line)
-               old >>= 8;
-       return old & 0xf;
-}
-
-static void mpsc_sdma_intr_unmask(struct mpsc_port_info *pi, u32 mask)
-{
-       u32     v;
-
-       pr_debug("mpsc_sdma_intr_unmask[%d]: mask: 0x%x\n", pi->port.line,mask);
-
-       v = (pi->mirror_regs) ? pi->shared_regs->SDMA_INTR_MASK_m
-               : readl(pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
-
-       mask &= 0xf;
-       if (pi->port.line)
-               mask <<= 8;
-       v |= mask;
-
-       if (pi->mirror_regs)
-               pi->shared_regs->SDMA_INTR_MASK_m = v;
-       writel(v, pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
-}
-
-static void mpsc_sdma_intr_ack(struct mpsc_port_info *pi)
-{
-       pr_debug("mpsc_sdma_intr_ack[%d]: Acknowledging IRQ\n", pi->port.line);
-
-       if (pi->mirror_regs)
-               pi->shared_regs->SDMA_INTR_CAUSE_m = 0;
-       writeb(0x00, pi->shared_regs->sdma_intr_base + SDMA_INTR_CAUSE
-                       + pi->port.line);
-}
-
-static void mpsc_sdma_set_rx_ring(struct mpsc_port_info *pi,
-               struct mpsc_rx_desc *rxre_p)
-{
-       pr_debug("mpsc_sdma_set_rx_ring[%d]: rxre_p: 0x%x\n",
-               pi->port.line, (u32)rxre_p);
-
-       writel((u32)rxre_p, pi->sdma_base + SDMA_SCRDP);
-}
-
-static void mpsc_sdma_set_tx_ring(struct mpsc_port_info *pi,
-               struct mpsc_tx_desc *txre_p)
-{
-       writel((u32)txre_p, pi->sdma_base + SDMA_SFTDP);
-       writel((u32)txre_p, pi->sdma_base + SDMA_SCTDP);
-}
-
-static void mpsc_sdma_cmd(struct mpsc_port_info *pi, u32 val)
-{
-       u32     v;
-
-       v = readl(pi->sdma_base + SDMA_SDCM);
-       if (val)
-               v |= val;
-       else
-               v = 0;
-       wmb();
-       writel(v, pi->sdma_base + SDMA_SDCM);
-       wmb();
-}
-
-static uint mpsc_sdma_tx_active(struct mpsc_port_info *pi)
-{
-       return readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_TXD;
-}
-
-static void mpsc_sdma_start_tx(struct mpsc_port_info *pi)
-{
-       struct mpsc_tx_desc *txre, *txre_p;
-
-       /* If tx isn't running & there's a desc ready to go, start it */
-       if (!mpsc_sdma_tx_active(pi)) {
-               txre = (struct mpsc_tx_desc *)(pi->txr
-                               + (pi->txr_tail * MPSC_TXRE_SIZE));
-               dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE,
-                               DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       invalidate_dcache_range((ulong)txre,
-                                       (ulong)txre + MPSC_TXRE_SIZE);
-#endif
-
-               if (be32_to_cpu(txre->cmdstat) & SDMA_DESC_CMDSTAT_O) {
-                       txre_p = (struct mpsc_tx_desc *)
-                               (pi->txr_p + (pi->txr_tail * MPSC_TXRE_SIZE));
-
-                       mpsc_sdma_set_tx_ring(pi, txre_p);
-                       mpsc_sdma_cmd(pi, SDMA_SDCM_STD | SDMA_SDCM_TXD);
-               }
-       }
-}
-
-static void mpsc_sdma_stop(struct mpsc_port_info *pi)
-{
-       pr_debug("mpsc_sdma_stop[%d]: Stopping SDMA\n", pi->port.line);
-
-       /* Abort any SDMA transfers */
-       mpsc_sdma_cmd(pi, 0);
-       mpsc_sdma_cmd(pi, SDMA_SDCM_AR | SDMA_SDCM_AT);
-
-       /* Clear the SDMA current and first TX and RX pointers */
-       mpsc_sdma_set_tx_ring(pi, NULL);
-       mpsc_sdma_set_rx_ring(pi, NULL);
-
-       /* Disable interrupts */
-       mpsc_sdma_intr_mask(pi, 0xf);
-       mpsc_sdma_intr_ack(pi);
-}
-
-/*
- ******************************************************************************
- *
- * Multi-Protocol Serial Controller Routines (MPSC)
- *
- ******************************************************************************
- */
-
-static void mpsc_hw_init(struct mpsc_port_info *pi)
-{
-       u32     v;
-
-       pr_debug("mpsc_hw_init[%d]: Initializing hardware\n", pi->port.line);
-
-       /* Set up clock routing */
-       if (pi->mirror_regs) {
-               v = pi->shared_regs->MPSC_MRR_m;
-               v &= ~0x1c7;
-               pi->shared_regs->MPSC_MRR_m = v;
-               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_MRR);
-
-               v = pi->shared_regs->MPSC_RCRR_m;
-               v = (v & ~0xf0f) | 0x100;
-               pi->shared_regs->MPSC_RCRR_m = v;
-               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_RCRR);
-
-               v = pi->shared_regs->MPSC_TCRR_m;
-               v = (v & ~0xf0f) | 0x100;
-               pi->shared_regs->MPSC_TCRR_m = v;
-               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_TCRR);
-       } else {
-               v = readl(pi->shared_regs->mpsc_routing_base + MPSC_MRR);
-               v &= ~0x1c7;
-               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_MRR);
-
-               v = readl(pi->shared_regs->mpsc_routing_base + MPSC_RCRR);
-               v = (v & ~0xf0f) | 0x100;
-               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_RCRR);
-
-               v = readl(pi->shared_regs->mpsc_routing_base + MPSC_TCRR);
-               v = (v & ~0xf0f) | 0x100;
-               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_TCRR);
-       }
-
-       /* Put MPSC in UART mode & enabel Tx/Rx egines */
-       writel(0x000004c4, pi->mpsc_base + MPSC_MMCRL);
-
-       /* No preamble, 16x divider, low-latency, */
-       writel(0x04400400, pi->mpsc_base + MPSC_MMCRH);
-       mpsc_set_baudrate(pi, pi->default_baud);
-
-       if (pi->mirror_regs) {
-               pi->MPSC_CHR_1_m = 0;
-               pi->MPSC_CHR_2_m = 0;
-       }
-       writel(0, pi->mpsc_base + MPSC_CHR_1);
-       writel(0, pi->mpsc_base + MPSC_CHR_2);
-       writel(pi->mpsc_max_idle, pi->mpsc_base + MPSC_CHR_3);
-       writel(0, pi->mpsc_base + MPSC_CHR_4);
-       writel(0, pi->mpsc_base + MPSC_CHR_5);
-       writel(0, pi->mpsc_base + MPSC_CHR_6);
-       writel(0, pi->mpsc_base + MPSC_CHR_7);
-       writel(0, pi->mpsc_base + MPSC_CHR_8);
-       writel(0, pi->mpsc_base + MPSC_CHR_9);
-       writel(0, pi->mpsc_base + MPSC_CHR_10);
-}
-
-static void mpsc_enter_hunt(struct mpsc_port_info *pi)
-{
-       pr_debug("mpsc_enter_hunt[%d]: Hunting...\n", pi->port.line);
-
-       if (pi->mirror_regs) {
-               writel(pi->MPSC_CHR_2_m | MPSC_CHR_2_EH,
-                       pi->mpsc_base + MPSC_CHR_2);
-               /* Erratum prevents reading CHR_2 so just delay for a while */
-               udelay(100);
-       } else {
-               writel(readl(pi->mpsc_base + MPSC_CHR_2) | MPSC_CHR_2_EH,
-                               pi->mpsc_base + MPSC_CHR_2);
-
-               while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_EH)
-                       udelay(10);
-       }
-}
-
-static void mpsc_freeze(struct mpsc_port_info *pi)
-{
-       u32     v;
-
-       pr_debug("mpsc_freeze[%d]: Freezing\n", pi->port.line);
-
-       v = (pi->mirror_regs) ? pi->MPSC_MPCR_m :
-               readl(pi->mpsc_base + MPSC_MPCR);
-       v |= MPSC_MPCR_FRZ;
-
-       if (pi->mirror_regs)
-               pi->MPSC_MPCR_m = v;
-       writel(v, pi->mpsc_base + MPSC_MPCR);
-}
-
-static void mpsc_unfreeze(struct mpsc_port_info *pi)
-{
-       u32     v;
-
-       v = (pi->mirror_regs) ? pi->MPSC_MPCR_m :
-               readl(pi->mpsc_base + MPSC_MPCR);
-       v &= ~MPSC_MPCR_FRZ;
-
-       if (pi->mirror_regs)
-               pi->MPSC_MPCR_m = v;
-       writel(v, pi->mpsc_base + MPSC_MPCR);
-
-       pr_debug("mpsc_unfreeze[%d]: Unfrozen\n", pi->port.line);
-}
-
-static void mpsc_set_char_length(struct mpsc_port_info *pi, u32 len)
-{
-       u32     v;
-
-       pr_debug("mpsc_set_char_length[%d]: char len: %d\n", pi->port.line,len);
-
-       v = (pi->mirror_regs) ? pi->MPSC_MPCR_m :
-               readl(pi->mpsc_base + MPSC_MPCR);
-       v = (v & ~(0x3 << 12)) | ((len & 0x3) << 12);
-
-       if (pi->mirror_regs)
-               pi->MPSC_MPCR_m = v;
-       writel(v, pi->mpsc_base + MPSC_MPCR);
-}
-
-static void mpsc_set_stop_bit_length(struct mpsc_port_info *pi, u32 len)
-{
-       u32     v;
-
-       pr_debug("mpsc_set_stop_bit_length[%d]: stop bits: %d\n",
-               pi->port.line, len);
-
-       v = (pi->mirror_regs) ? pi->MPSC_MPCR_m :
-               readl(pi->mpsc_base + MPSC_MPCR);
-
-       v = (v & ~(1 << 14)) | ((len & 0x1) << 14);
-
-       if (pi->mirror_regs)
-               pi->MPSC_MPCR_m = v;
-       writel(v, pi->mpsc_base + MPSC_MPCR);
-}
-
-static void mpsc_set_parity(struct mpsc_port_info *pi, u32 p)
-{
-       u32     v;
-
-       pr_debug("mpsc_set_parity[%d]: parity bits: 0x%x\n", pi->port.line, p);
-
-       v = (pi->mirror_regs) ? pi->MPSC_CHR_2_m :
-               readl(pi->mpsc_base + MPSC_CHR_2);
-
-       p &= 0x3;
-       v = (v & ~0xc000c) | (p << 18) | (p << 2);
-
-       if (pi->mirror_regs)
-               pi->MPSC_CHR_2_m = v;
-       writel(v, pi->mpsc_base + MPSC_CHR_2);
-}
-
-/*
- ******************************************************************************
- *
- * Driver Init Routines
- *
- ******************************************************************************
- */
-
-static void mpsc_init_hw(struct mpsc_port_info *pi)
-{
-       pr_debug("mpsc_init_hw[%d]: Initializing\n", pi->port.line);
-
-       mpsc_brg_init(pi, pi->brg_clk_src);
-       mpsc_brg_enable(pi);
-       mpsc_sdma_init(pi, dma_get_cache_alignment());  /* burst a cacheline */
-       mpsc_sdma_stop(pi);
-       mpsc_hw_init(pi);
-}
-
-static int mpsc_alloc_ring_mem(struct mpsc_port_info *pi)
-{
-       int rc = 0;
-
-       pr_debug("mpsc_alloc_ring_mem[%d]: Allocating ring mem\n",
-               pi->port.line);
-
-       if (!pi->dma_region) {
-               if (!dma_supported(pi->port.dev, 0xffffffff)) {
-                       printk(KERN_ERR "MPSC: Inadequate DMA support\n");
-                       rc = -ENXIO;
-               } else if ((pi->dma_region = dma_alloc_noncoherent(pi->port.dev,
-                                               MPSC_DMA_ALLOC_SIZE,
-                                               &pi->dma_region_p, GFP_KERNEL))
-                               == NULL) {
-                       printk(KERN_ERR "MPSC: Can't alloc Desc region\n");
-                       rc = -ENOMEM;
-               }
-       }
-
-       return rc;
-}
-
-static void mpsc_free_ring_mem(struct mpsc_port_info *pi)
-{
-       pr_debug("mpsc_free_ring_mem[%d]: Freeing ring mem\n", pi->port.line);
-
-       if (pi->dma_region) {
-               dma_free_noncoherent(pi->port.dev, MPSC_DMA_ALLOC_SIZE,
-                               pi->dma_region, pi->dma_region_p);
-               pi->dma_region = NULL;
-               pi->dma_region_p = (dma_addr_t)NULL;
-       }
-}
-
-static void mpsc_init_rings(struct mpsc_port_info *pi)
-{
-       struct mpsc_rx_desc *rxre;
-       struct mpsc_tx_desc *txre;
-       dma_addr_t dp, dp_p;
-       u8 *bp, *bp_p;
-       int i;
-
-       pr_debug("mpsc_init_rings[%d]: Initializing rings\n", pi->port.line);
-
-       BUG_ON(pi->dma_region == NULL);
-
-       memset(pi->dma_region, 0, MPSC_DMA_ALLOC_SIZE);
-
-       /*
-        * Descriptors & buffers are multiples of cacheline size and must be
-        * cacheline aligned.
-        */
-       dp = ALIGN((u32)pi->dma_region, dma_get_cache_alignment());
-       dp_p = ALIGN((u32)pi->dma_region_p, dma_get_cache_alignment());
-
-       /*
-        * Partition dma region into rx ring descriptor, rx buffers,
-        * tx ring descriptors, and tx buffers.
-        */
-       pi->rxr = dp;
-       pi->rxr_p = dp_p;
-       dp += MPSC_RXR_SIZE;
-       dp_p += MPSC_RXR_SIZE;
-
-       pi->rxb = (u8 *)dp;
-       pi->rxb_p = (u8 *)dp_p;
-       dp += MPSC_RXB_SIZE;
-       dp_p += MPSC_RXB_SIZE;
-
-       pi->rxr_posn = 0;
-
-       pi->txr = dp;
-       pi->txr_p = dp_p;
-       dp += MPSC_TXR_SIZE;
-       dp_p += MPSC_TXR_SIZE;
-
-       pi->txb = (u8 *)dp;
-       pi->txb_p = (u8 *)dp_p;
-
-       pi->txr_head = 0;
-       pi->txr_tail = 0;
-
-       /* Init rx ring descriptors */
-       dp = pi->rxr;
-       dp_p = pi->rxr_p;
-       bp = pi->rxb;
-       bp_p = pi->rxb_p;
-
-       for (i = 0; i < MPSC_RXR_ENTRIES; i++) {
-               rxre = (struct mpsc_rx_desc *)dp;
-
-               rxre->bufsize = cpu_to_be16(MPSC_RXBE_SIZE);
-               rxre->bytecnt = cpu_to_be16(0);
-               rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O
-                               | SDMA_DESC_CMDSTAT_EI | SDMA_DESC_CMDSTAT_F
-                               | SDMA_DESC_CMDSTAT_L);
-               rxre->link = cpu_to_be32(dp_p + MPSC_RXRE_SIZE);
-               rxre->buf_ptr = cpu_to_be32(bp_p);
-
-               dp += MPSC_RXRE_SIZE;
-               dp_p += MPSC_RXRE_SIZE;
-               bp += MPSC_RXBE_SIZE;
-               bp_p += MPSC_RXBE_SIZE;
-       }
-       rxre->link = cpu_to_be32(pi->rxr_p);    /* Wrap last back to first */
-
-       /* Init tx ring descriptors */
-       dp = pi->txr;
-       dp_p = pi->txr_p;
-       bp = pi->txb;
-       bp_p = pi->txb_p;
-
-       for (i = 0; i < MPSC_TXR_ENTRIES; i++) {
-               txre = (struct mpsc_tx_desc *)dp;
-
-               txre->link = cpu_to_be32(dp_p + MPSC_TXRE_SIZE);
-               txre->buf_ptr = cpu_to_be32(bp_p);
-
-               dp += MPSC_TXRE_SIZE;
-               dp_p += MPSC_TXRE_SIZE;
-               bp += MPSC_TXBE_SIZE;
-               bp_p += MPSC_TXBE_SIZE;
-       }
-       txre->link = cpu_to_be32(pi->txr_p);    /* Wrap last back to first */
-
-       dma_cache_sync(pi->port.dev, (void *)pi->dma_region,
-                       MPSC_DMA_ALLOC_SIZE, DMA_BIDIRECTIONAL);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       flush_dcache_range((ulong)pi->dma_region,
-                                       (ulong)pi->dma_region
-                                       + MPSC_DMA_ALLOC_SIZE);
-#endif
-
-       return;
-}
-
-static void mpsc_uninit_rings(struct mpsc_port_info *pi)
-{
-       pr_debug("mpsc_uninit_rings[%d]: Uninitializing rings\n",pi->port.line);
-
-       BUG_ON(pi->dma_region == NULL);
-
-       pi->rxr = 0;
-       pi->rxr_p = 0;
-       pi->rxb = NULL;
-       pi->rxb_p = NULL;
-       pi->rxr_posn = 0;
-
-       pi->txr = 0;
-       pi->txr_p = 0;
-       pi->txb = NULL;
-       pi->txb_p = NULL;
-       pi->txr_head = 0;
-       pi->txr_tail = 0;
-}
-
-static int mpsc_make_ready(struct mpsc_port_info *pi)
-{
-       int rc;
-
-       pr_debug("mpsc_make_ready[%d]: Making cltr ready\n", pi->port.line);
-
-       if (!pi->ready) {
-               mpsc_init_hw(pi);
-               if ((rc = mpsc_alloc_ring_mem(pi)))
-                       return rc;
-               mpsc_init_rings(pi);
-               pi->ready = 1;
-       }
-
-       return 0;
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-static int serial_polled;
-#endif
-
-/*
- ******************************************************************************
- *
- * Interrupt Handling Routines
- *
- ******************************************************************************
- */
-
-static int mpsc_rx_intr(struct mpsc_port_info *pi)
-{
-       struct mpsc_rx_desc *rxre;
-       struct tty_struct *tty = pi->port.state->port.tty;
-       u32     cmdstat, bytes_in, i;
-       int     rc = 0;
-       u8      *bp;
-       char    flag = TTY_NORMAL;
-
-       pr_debug("mpsc_rx_intr[%d]: Handling Rx intr\n", pi->port.line);
-
-       rxre = (struct mpsc_rx_desc *)(pi->rxr + (pi->rxr_posn*MPSC_RXRE_SIZE));
-
-       dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE,
-                       DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-               invalidate_dcache_range((ulong)rxre,
-                               (ulong)rxre + MPSC_RXRE_SIZE);
-#endif
-
-       /*
-        * Loop through Rx descriptors handling ones that have been completed.
-        */
-       while (!((cmdstat = be32_to_cpu(rxre->cmdstat))
-                               & SDMA_DESC_CMDSTAT_O)) {
-               bytes_in = be16_to_cpu(rxre->bytecnt);
-#ifdef CONFIG_CONSOLE_POLL
-               if (unlikely(serial_polled)) {
-                       serial_polled = 0;
-                       return 0;
-               }
-#endif
-               /* Following use of tty struct directly is deprecated */
-               if (unlikely(tty_buffer_request_room(tty, bytes_in)
-                                       < bytes_in)) {
-                       if (tty->low_latency)
-                               tty_flip_buffer_push(tty);
-                       /*
-                        * If this failed then we will throw away the bytes
-                        * but must do so to clear interrupts.
-                        */
-               }
-
-               bp = pi->rxb + (pi->rxr_posn * MPSC_RXBE_SIZE);
-               dma_cache_sync(pi->port.dev, (void *)bp, MPSC_RXBE_SIZE,
-                               DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       invalidate_dcache_range((ulong)bp,
-                                       (ulong)bp + MPSC_RXBE_SIZE);
-#endif
-
-               /*
-                * Other than for parity error, the manual provides little
-                * info on what data will be in a frame flagged by any of
-                * these errors.  For parity error, it is the last byte in
-                * the buffer that had the error.  As for the rest, I guess
-                * we'll assume there is no data in the buffer.
-                * If there is...it gets lost.
-                */
-               if (unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR
-                                               | SDMA_DESC_CMDSTAT_FR
-                                               | SDMA_DESC_CMDSTAT_OR))) {
-
-                       pi->port.icount.rx++;
-
-                       if (cmdstat & SDMA_DESC_CMDSTAT_BR) {   /* Break */
-                               pi->port.icount.brk++;
-
-                               if (uart_handle_break(&pi->port))
-                                       goto next_frame;
-                       } else if (cmdstat & SDMA_DESC_CMDSTAT_FR) {
-                               pi->port.icount.frame++;
-                       } else if (cmdstat & SDMA_DESC_CMDSTAT_OR) {
-                               pi->port.icount.overrun++;
-                       }
-
-                       cmdstat &= pi->port.read_status_mask;
-
-                       if (cmdstat & SDMA_DESC_CMDSTAT_BR)
-                               flag = TTY_BREAK;
-                       else if (cmdstat & SDMA_DESC_CMDSTAT_FR)
-                               flag = TTY_FRAME;
-                       else if (cmdstat & SDMA_DESC_CMDSTAT_OR)
-                               flag = TTY_OVERRUN;
-                       else if (cmdstat & SDMA_DESC_CMDSTAT_PE)
-                               flag = TTY_PARITY;
-               }
-
-               if (uart_handle_sysrq_char(&pi->port, *bp)) {
-                       bp++;
-                       bytes_in--;
-#ifdef CONFIG_CONSOLE_POLL
-                       if (unlikely(serial_polled)) {
-                               serial_polled = 0;
-                               return 0;
-                       }
-#endif
-                       goto next_frame;
-               }
-
-               if ((unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR
-                                               | SDMA_DESC_CMDSTAT_FR
-                                               | SDMA_DESC_CMDSTAT_OR)))
-                               && !(cmdstat & pi->port.ignore_status_mask)) {
-                       tty_insert_flip_char(tty, *bp, flag);
-               } else {
-                       for (i=0; i<bytes_in; i++)
-                               tty_insert_flip_char(tty, *bp++, TTY_NORMAL);
-
-                       pi->port.icount.rx += bytes_in;
-               }
-
-next_frame:
-               rxre->bytecnt = cpu_to_be16(0);
-               wmb();
-               rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O
-                               | SDMA_DESC_CMDSTAT_EI | SDMA_DESC_CMDSTAT_F
-                               | SDMA_DESC_CMDSTAT_L);
-               wmb();
-               dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE,
-                               DMA_BIDIRECTIONAL);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       flush_dcache_range((ulong)rxre,
-                                       (ulong)rxre + MPSC_RXRE_SIZE);
-#endif
-
-               /* Advance to next descriptor */
-               pi->rxr_posn = (pi->rxr_posn + 1) & (MPSC_RXR_ENTRIES - 1);
-               rxre = (struct mpsc_rx_desc *)
-                       (pi->rxr + (pi->rxr_posn * MPSC_RXRE_SIZE));
-               dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE,
-                               DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       invalidate_dcache_range((ulong)rxre,
-                                       (ulong)rxre + MPSC_RXRE_SIZE);
-#endif
-               rc = 1;
-       }
-
-       /* Restart rx engine, if its stopped */
-       if ((readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_ERD) == 0)
-               mpsc_start_rx(pi);
-
-       tty_flip_buffer_push(tty);
-       return rc;
-}
-
-static void mpsc_setup_tx_desc(struct mpsc_port_info *pi, u32 count, u32 intr)
-{
-       struct mpsc_tx_desc *txre;
-
-       txre = (struct mpsc_tx_desc *)(pi->txr
-                       + (pi->txr_head * MPSC_TXRE_SIZE));
-
-       txre->bytecnt = cpu_to_be16(count);
-       txre->shadow = txre->bytecnt;
-       wmb();                  /* ensure cmdstat is last field updated */
-       txre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O | SDMA_DESC_CMDSTAT_F
-                       | SDMA_DESC_CMDSTAT_L
-                       | ((intr) ? SDMA_DESC_CMDSTAT_EI : 0));
-       wmb();
-       dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE,
-                       DMA_BIDIRECTIONAL);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-               flush_dcache_range((ulong)txre,
-                               (ulong)txre + MPSC_TXRE_SIZE);
-#endif
-}
-
-static void mpsc_copy_tx_data(struct mpsc_port_info *pi)
-{
-       struct circ_buf *xmit = &pi->port.state->xmit;
-       u8 *bp;
-       u32 i;
-
-       /* Make sure the desc ring isn't full */
-       while (CIRC_CNT(pi->txr_head, pi->txr_tail, MPSC_TXR_ENTRIES)
-                       < (MPSC_TXR_ENTRIES - 1)) {
-               if (pi->port.x_char) {
-                       /*
-                        * Ideally, we should use the TCS field in
-                        * CHR_1 to put the x_char out immediately but
-                        * errata prevents us from being able to read
-                        * CHR_2 to know that its safe to write to
-                        * CHR_1.  Instead, just put it in-band with
-                        * all the other Tx data.
-                        */
-                       bp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE);
-                       *bp = pi->port.x_char;
-                       pi->port.x_char = 0;
-                       i = 1;
-               } else if (!uart_circ_empty(xmit)
-                               && !uart_tx_stopped(&pi->port)) {
-                       i = min((u32)MPSC_TXBE_SIZE,
-                               (u32)uart_circ_chars_pending(xmit));
-                       i = min(i, (u32)CIRC_CNT_TO_END(xmit->head, xmit->tail,
-                               UART_XMIT_SIZE));
-                       bp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE);
-                       memcpy(bp, &xmit->buf[xmit->tail], i);
-                       xmit->tail = (xmit->tail + i) & (UART_XMIT_SIZE - 1);
-
-                       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-                               uart_write_wakeup(&pi->port);
-               } else { /* All tx data copied into ring bufs */
-                       return;
-               }
-
-               dma_cache_sync(pi->port.dev, (void *)bp, MPSC_TXBE_SIZE,
-                               DMA_BIDIRECTIONAL);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       flush_dcache_range((ulong)bp,
-                                       (ulong)bp + MPSC_TXBE_SIZE);
-#endif
-               mpsc_setup_tx_desc(pi, i, 1);
-
-               /* Advance to next descriptor */
-               pi->txr_head = (pi->txr_head + 1) & (MPSC_TXR_ENTRIES - 1);
-       }
-}
-
-static int mpsc_tx_intr(struct mpsc_port_info *pi)
-{
-       struct mpsc_tx_desc *txre;
-       int rc = 0;
-       unsigned long iflags;
-
-       spin_lock_irqsave(&pi->tx_lock, iflags);
-
-       if (!mpsc_sdma_tx_active(pi)) {
-               txre = (struct mpsc_tx_desc *)(pi->txr
-                               + (pi->txr_tail * MPSC_TXRE_SIZE));
-
-               dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE,
-                               DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       invalidate_dcache_range((ulong)txre,
-                                       (ulong)txre + MPSC_TXRE_SIZE);
-#endif
-
-               while (!(be32_to_cpu(txre->cmdstat) & SDMA_DESC_CMDSTAT_O)) {
-                       rc = 1;
-                       pi->port.icount.tx += be16_to_cpu(txre->bytecnt);
-                       pi->txr_tail = (pi->txr_tail+1) & (MPSC_TXR_ENTRIES-1);
-
-                       /* If no more data to tx, fall out of loop */
-                       if (pi->txr_head == pi->txr_tail)
-                               break;
-
-                       txre = (struct mpsc_tx_desc *)(pi->txr
-                                       + (pi->txr_tail * MPSC_TXRE_SIZE));
-                       dma_cache_sync(pi->port.dev, (void *)txre,
-                                       MPSC_TXRE_SIZE, DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-                       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                               invalidate_dcache_range((ulong)txre,
-                                               (ulong)txre + MPSC_TXRE_SIZE);
-#endif
-               }
-
-               mpsc_copy_tx_data(pi);
-               mpsc_sdma_start_tx(pi); /* start next desc if ready */
-       }
-
-       spin_unlock_irqrestore(&pi->tx_lock, iflags);
-       return rc;
-}
-
-/*
- * This is the driver's interrupt handler.  To avoid a race, we first clear
- * the interrupt, then handle any completed Rx/Tx descriptors.  When done
- * handling those descriptors, we restart the Rx/Tx engines if they're stopped.
- */
-static irqreturn_t mpsc_sdma_intr(int irq, void *dev_id)
-{
-       struct mpsc_port_info *pi = dev_id;
-       ulong iflags;
-       int rc = IRQ_NONE;
-
-       pr_debug("mpsc_sdma_intr[%d]: SDMA Interrupt Received\n",pi->port.line);
-
-       spin_lock_irqsave(&pi->port.lock, iflags);
-       mpsc_sdma_intr_ack(pi);
-       if (mpsc_rx_intr(pi))
-               rc = IRQ_HANDLED;
-       if (mpsc_tx_intr(pi))
-               rc = IRQ_HANDLED;
-       spin_unlock_irqrestore(&pi->port.lock, iflags);
-
-       pr_debug("mpsc_sdma_intr[%d]: SDMA Interrupt Handled\n", pi->port.line);
-       return rc;
-}
-
-/*
- ******************************************************************************
- *
- * serial_core.c Interface routines
- *
- ******************************************************************************
- */
-static uint mpsc_tx_empty(struct uart_port *port)
-{
-       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-       ulong iflags;
-       uint rc;
-
-       spin_lock_irqsave(&pi->port.lock, iflags);
-       rc = mpsc_sdma_tx_active(pi) ? 0 : TIOCSER_TEMT;
-       spin_unlock_irqrestore(&pi->port.lock, iflags);
-
-       return rc;
-}
-
-static void mpsc_set_mctrl(struct uart_port *port, uint mctrl)
-{
-       /* Have no way to set modem control lines AFAICT */
-}
-
-static uint mpsc_get_mctrl(struct uart_port *port)
-{
-       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-       u32 mflags, status;
-
-       status = (pi->mirror_regs) ? pi->MPSC_CHR_10_m
-               : readl(pi->mpsc_base + MPSC_CHR_10);
-
-       mflags = 0;
-       if (status & 0x1)
-               mflags |= TIOCM_CTS;
-       if (status & 0x2)
-               mflags |= TIOCM_CAR;
-
-       return mflags | TIOCM_DSR;      /* No way to tell if DSR asserted */
-}
-
-static void mpsc_stop_tx(struct uart_port *port)
-{
-       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-
-       pr_debug("mpsc_stop_tx[%d]\n", port->line);
-
-       mpsc_freeze(pi);
-}
-
-static void mpsc_start_tx(struct uart_port *port)
-{
-       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-       unsigned long iflags;
-
-       spin_lock_irqsave(&pi->tx_lock, iflags);
-
-       mpsc_unfreeze(pi);
-       mpsc_copy_tx_data(pi);
-       mpsc_sdma_start_tx(pi);
-
-       spin_unlock_irqrestore(&pi->tx_lock, iflags);
-
-       pr_debug("mpsc_start_tx[%d]\n", port->line);
-}
-
-static void mpsc_start_rx(struct mpsc_port_info *pi)
-{
-       pr_debug("mpsc_start_rx[%d]: Starting...\n", pi->port.line);
-
-       if (pi->rcv_data) {
-               mpsc_enter_hunt(pi);
-               mpsc_sdma_cmd(pi, SDMA_SDCM_ERD);
-       }
-}
-
-static void mpsc_stop_rx(struct uart_port *port)
-{
-       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-
-       pr_debug("mpsc_stop_rx[%d]: Stopping...\n", port->line);
-
-       if (pi->mirror_regs) {
-               writel(pi->MPSC_CHR_2_m | MPSC_CHR_2_RA,
-                               pi->mpsc_base + MPSC_CHR_2);
-               /* Erratum prevents reading CHR_2 so just delay for a while */
-               udelay(100);
-       } else {
-               writel(readl(pi->mpsc_base + MPSC_CHR_2) | MPSC_CHR_2_RA,
-                               pi->mpsc_base + MPSC_CHR_2);
-
-               while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_RA)
-                       udelay(10);
-       }
-
-       mpsc_sdma_cmd(pi, SDMA_SDCM_AR);
-}
-
-static void mpsc_enable_ms(struct uart_port *port)
-{
-}
-
-static void mpsc_break_ctl(struct uart_port *port, int ctl)
-{
-       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-       ulong   flags;
-       u32     v;
-
-       v = ctl ? 0x00ff0000 : 0;
-
-       spin_lock_irqsave(&pi->port.lock, flags);
-       if (pi->mirror_regs)
-               pi->MPSC_CHR_1_m = v;
-       writel(v, pi->mpsc_base + MPSC_CHR_1);
-       spin_unlock_irqrestore(&pi->port.lock, flags);
-}
-
-static int mpsc_startup(struct uart_port *port)
-{
-       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-       u32 flag = 0;
-       int rc;
-
-       pr_debug("mpsc_startup[%d]: Starting up MPSC, irq: %d\n",
-               port->line, pi->port.irq);
-
-       if ((rc = mpsc_make_ready(pi)) == 0) {
-               /* Setup IRQ handler */
-               mpsc_sdma_intr_ack(pi);
-
-               /* If irq's are shared, need to set flag */
-               if (mpsc_ports[0].port.irq == mpsc_ports[1].port.irq)
-                       flag = IRQF_SHARED;
-
-               if (request_irq(pi->port.irq, mpsc_sdma_intr, flag,
-                                       "mpsc-sdma", pi))
-                       printk(KERN_ERR "MPSC: Can't get SDMA IRQ %d\n",
-                                       pi->port.irq);
-
-               mpsc_sdma_intr_unmask(pi, 0xf);
-               mpsc_sdma_set_rx_ring(pi, (struct mpsc_rx_desc *)(pi->rxr_p
-                                       + (pi->rxr_posn * MPSC_RXRE_SIZE)));
-       }
-
-       return rc;
-}
-
-static void mpsc_shutdown(struct uart_port *port)
-{
-       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-
-       pr_debug("mpsc_shutdown[%d]: Shutting down MPSC\n", port->line);
-
-       mpsc_sdma_stop(pi);
-       free_irq(pi->port.irq, pi);
-}
-
-static void mpsc_set_termios(struct uart_port *port, struct ktermios *termios,
-                struct ktermios *old)
-{
-       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-       u32 baud;
-       ulong flags;
-       u32 chr_bits, stop_bits, par;
-
-       pi->c_iflag = termios->c_iflag;
-       pi->c_cflag = termios->c_cflag;
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               chr_bits = MPSC_MPCR_CL_5;
-               break;
-       case CS6:
-               chr_bits = MPSC_MPCR_CL_6;
-               break;
-       case CS7:
-               chr_bits = MPSC_MPCR_CL_7;
-               break;
-       case CS8:
-       default:
-               chr_bits = MPSC_MPCR_CL_8;
-               break;
-       }
-
-       if (termios->c_cflag & CSTOPB)
-               stop_bits = MPSC_MPCR_SBL_2;
-       else
-               stop_bits = MPSC_MPCR_SBL_1;
-
-       par = MPSC_CHR_2_PAR_EVEN;
-       if (termios->c_cflag & PARENB)
-               if (termios->c_cflag & PARODD)
-                       par = MPSC_CHR_2_PAR_ODD;
-#ifdef CMSPAR
-               if (termios->c_cflag & CMSPAR) {
-                       if (termios->c_cflag & PARODD)
-                               par = MPSC_CHR_2_PAR_MARK;
-                       else
-                               par = MPSC_CHR_2_PAR_SPACE;
-               }
-#endif
-
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk);
-
-       spin_lock_irqsave(&pi->port.lock, flags);
-
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       mpsc_set_char_length(pi, chr_bits);
-       mpsc_set_stop_bit_length(pi, stop_bits);
-       mpsc_set_parity(pi, par);
-       mpsc_set_baudrate(pi, baud);
-
-       /* Characters/events to read */
-       pi->port.read_status_mask = SDMA_DESC_CMDSTAT_OR;
-
-       if (termios->c_iflag & INPCK)
-               pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_PE
-                       | SDMA_DESC_CMDSTAT_FR;
-
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_BR;
-
-       /* Characters/events to ignore */
-       pi->port.ignore_status_mask = 0;
-
-       if (termios->c_iflag & IGNPAR)
-               pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_PE
-                       | SDMA_DESC_CMDSTAT_FR;
-
-       if (termios->c_iflag & IGNBRK) {
-               pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_BR;
-
-               if (termios->c_iflag & IGNPAR)
-                       pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_OR;
-       }
-
-       if ((termios->c_cflag & CREAD)) {
-               if (!pi->rcv_data) {
-                       pi->rcv_data = 1;
-                       mpsc_start_rx(pi);
-               }
-       } else if (pi->rcv_data) {
-               mpsc_stop_rx(port);
-               pi->rcv_data = 0;
-       }
-
-       spin_unlock_irqrestore(&pi->port.lock, flags);
-}
-
-static const char *mpsc_type(struct uart_port *port)
-{
-       pr_debug("mpsc_type[%d]: port type: %s\n", port->line,MPSC_DRIVER_NAME);
-       return MPSC_DRIVER_NAME;
-}
-
-static int mpsc_request_port(struct uart_port *port)
-{
-       /* Should make chip/platform specific call */
-       return 0;
-}
-
-static void mpsc_release_port(struct uart_port *port)
-{
-       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-
-       if (pi->ready) {
-               mpsc_uninit_rings(pi);
-               mpsc_free_ring_mem(pi);
-               pi->ready = 0;
-       }
-}
-
-static void mpsc_config_port(struct uart_port *port, int flags)
-{
-}
-
-static int mpsc_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-       int rc = 0;
-
-       pr_debug("mpsc_verify_port[%d]: Verifying port data\n", pi->port.line);
-
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_MPSC)
-               rc = -EINVAL;
-       else if (pi->port.irq != ser->irq)
-               rc = -EINVAL;
-       else if (ser->io_type != SERIAL_IO_MEM)
-               rc = -EINVAL;
-       else if (pi->port.uartclk / 16 != ser->baud_base) /* Not sure */
-               rc = -EINVAL;
-       else if ((void *)pi->port.mapbase != ser->iomem_base)
-               rc = -EINVAL;
-       else if (pi->port.iobase != ser->port)
-               rc = -EINVAL;
-       else if (ser->hub6 != 0)
-               rc = -EINVAL;
-
-       return rc;
-}
-#ifdef CONFIG_CONSOLE_POLL
-/* Serial polling routines for writing and reading from the uart while
- * in an interrupt or debug context.
- */
-
-static char poll_buf[2048];
-static int poll_ptr;
-static int poll_cnt;
-static void mpsc_put_poll_char(struct uart_port *port,
-                                                          unsigned char c);
-
-static int mpsc_get_poll_char(struct uart_port *port)
-{
-       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-       struct mpsc_rx_desc *rxre;
-       u32     cmdstat, bytes_in, i;
-       u8      *bp;
-
-       if (!serial_polled)
-               serial_polled = 1;
-
-       pr_debug("mpsc_rx_intr[%d]: Handling Rx intr\n", pi->port.line);
-
-       if (poll_cnt) {
-               poll_cnt--;
-               return poll_buf[poll_ptr++];
-       }
-       poll_ptr = 0;
-       poll_cnt = 0;
-
-       while (poll_cnt == 0) {
-               rxre = (struct mpsc_rx_desc *)(pi->rxr +
-                      (pi->rxr_posn*MPSC_RXRE_SIZE));
-               dma_cache_sync(pi->port.dev, (void *)rxre,
-                              MPSC_RXRE_SIZE, DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       invalidate_dcache_range((ulong)rxre,
-                       (ulong)rxre + MPSC_RXRE_SIZE);
-#endif
-               /*
-                * Loop through Rx descriptors handling ones that have
-                * been completed.
-                */
-               while (poll_cnt == 0 &&
-                      !((cmdstat = be32_to_cpu(rxre->cmdstat)) &
-                        SDMA_DESC_CMDSTAT_O)){
-                       bytes_in = be16_to_cpu(rxre->bytecnt);
-                       bp = pi->rxb + (pi->rxr_posn * MPSC_RXBE_SIZE);
-                       dma_cache_sync(pi->port.dev, (void *) bp,
-                                      MPSC_RXBE_SIZE, DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-                       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                               invalidate_dcache_range((ulong)bp,
-                                       (ulong)bp + MPSC_RXBE_SIZE);
-#endif
-                       if ((unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR |
-                        SDMA_DESC_CMDSTAT_FR | SDMA_DESC_CMDSTAT_OR))) &&
-                               !(cmdstat & pi->port.ignore_status_mask)) {
-                               poll_buf[poll_cnt] = *bp;
-                               poll_cnt++;
-                       } else {
-                               for (i = 0; i < bytes_in; i++) {
-                                       poll_buf[poll_cnt] = *bp++;
-                                       poll_cnt++;
-                               }
-                               pi->port.icount.rx += bytes_in;
-                       }
-                       rxre->bytecnt = cpu_to_be16(0);
-                       wmb();
-                       rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O |
-                                                   SDMA_DESC_CMDSTAT_EI |
-                                                   SDMA_DESC_CMDSTAT_F |
-                                                   SDMA_DESC_CMDSTAT_L);
-                       wmb();
-                       dma_cache_sync(pi->port.dev, (void *)rxre,
-                                      MPSC_RXRE_SIZE, DMA_BIDIRECTIONAL);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-                       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                               flush_dcache_range((ulong)rxre,
-                                          (ulong)rxre + MPSC_RXRE_SIZE);
-#endif
-
-                       /* Advance to next descriptor */
-                       pi->rxr_posn = (pi->rxr_posn + 1) &
-                               (MPSC_RXR_ENTRIES - 1);
-                       rxre = (struct mpsc_rx_desc *)(pi->rxr +
-                                      (pi->rxr_posn * MPSC_RXRE_SIZE));
-                       dma_cache_sync(pi->port.dev, (void *)rxre,
-                                      MPSC_RXRE_SIZE, DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-                       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                               invalidate_dcache_range((ulong)rxre,
-                                               (ulong)rxre + MPSC_RXRE_SIZE);
-#endif
-               }
-
-               /* Restart rx engine, if its stopped */
-               if ((readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_ERD) == 0)
-                       mpsc_start_rx(pi);
-       }
-       if (poll_cnt) {
-               poll_cnt--;
-               return poll_buf[poll_ptr++];
-       }
-
-       return 0;
-}
-
-
-static void mpsc_put_poll_char(struct uart_port *port,
-                        unsigned char c)
-{
-       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-       u32 data;
-
-       data = readl(pi->mpsc_base + MPSC_MPCR);
-       writeb(c, pi->mpsc_base + MPSC_CHR_1);
-       mb();
-       data = readl(pi->mpsc_base + MPSC_CHR_2);
-       data |= MPSC_CHR_2_TTCS;
-       writel(data, pi->mpsc_base + MPSC_CHR_2);
-       mb();
-
-       while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_TTCS);
-}
-#endif
-
-static struct uart_ops mpsc_pops = {
-       .tx_empty       = mpsc_tx_empty,
-       .set_mctrl      = mpsc_set_mctrl,
-       .get_mctrl      = mpsc_get_mctrl,
-       .stop_tx        = mpsc_stop_tx,
-       .start_tx       = mpsc_start_tx,
-       .stop_rx        = mpsc_stop_rx,
-       .enable_ms      = mpsc_enable_ms,
-       .break_ctl      = mpsc_break_ctl,
-       .startup        = mpsc_startup,
-       .shutdown       = mpsc_shutdown,
-       .set_termios    = mpsc_set_termios,
-       .type           = mpsc_type,
-       .release_port   = mpsc_release_port,
-       .request_port   = mpsc_request_port,
-       .config_port    = mpsc_config_port,
-       .verify_port    = mpsc_verify_port,
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_get_char = mpsc_get_poll_char,
-       .poll_put_char = mpsc_put_poll_char,
-#endif
-};
-
-/*
- ******************************************************************************
- *
- * Console Interface Routines
- *
- ******************************************************************************
- */
-
-#ifdef CONFIG_SERIAL_MPSC_CONSOLE
-static void mpsc_console_write(struct console *co, const char *s, uint count)
-{
-       struct mpsc_port_info *pi = &mpsc_ports[co->index];
-       u8 *bp, *dp, add_cr = 0;
-       int i;
-       unsigned long iflags;
-
-       spin_lock_irqsave(&pi->tx_lock, iflags);
-
-       while (pi->txr_head != pi->txr_tail) {
-               while (mpsc_sdma_tx_active(pi))
-                       udelay(100);
-               mpsc_sdma_intr_ack(pi);
-               mpsc_tx_intr(pi);
-       }
-
-       while (mpsc_sdma_tx_active(pi))
-               udelay(100);
-
-       while (count > 0) {
-               bp = dp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE);
-
-               for (i = 0; i < MPSC_TXBE_SIZE; i++) {
-                       if (count == 0)
-                               break;
-
-                       if (add_cr) {
-                               *(dp++) = '\r';
-                               add_cr = 0;
-                       } else {
-                               *(dp++) = *s;
-
-                               if (*(s++) == '\n') { /* add '\r' after '\n' */
-                                       add_cr = 1;
-                                       count++;
-                               }
-                       }
-
-                       count--;
-               }
-
-               dma_cache_sync(pi->port.dev, (void *)bp, MPSC_TXBE_SIZE,
-                               DMA_BIDIRECTIONAL);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       flush_dcache_range((ulong)bp,
-                                       (ulong)bp + MPSC_TXBE_SIZE);
-#endif
-               mpsc_setup_tx_desc(pi, i, 0);
-               pi->txr_head = (pi->txr_head + 1) & (MPSC_TXR_ENTRIES - 1);
-               mpsc_sdma_start_tx(pi);
-
-               while (mpsc_sdma_tx_active(pi))
-                       udelay(100);
-
-               pi->txr_tail = (pi->txr_tail + 1) & (MPSC_TXR_ENTRIES - 1);
-       }
-
-       spin_unlock_irqrestore(&pi->tx_lock, iflags);
-}
-
-static int __init mpsc_console_setup(struct console *co, char *options)
-{
-       struct mpsc_port_info *pi;
-       int baud, bits, parity, flow;
-
-       pr_debug("mpsc_console_setup[%d]: options: %s\n", co->index, options);
-
-       if (co->index >= MPSC_NUM_CTLRS)
-               co->index = 0;
-
-       pi = &mpsc_ports[co->index];
-
-       baud = pi->default_baud;
-       bits = pi->default_bits;
-       parity = pi->default_parity;
-       flow = pi->default_flow;
-
-       if (!pi->port.ops)
-               return -ENODEV;
-
-       spin_lock_init(&pi->port.lock); /* Temporary fix--copied from 8250.c */
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(&pi->port, co, baud, parity, bits, flow);
-}
-
-static struct console mpsc_console = {
-       .name   = MPSC_DEV_NAME,
-       .write  = mpsc_console_write,
-       .device = uart_console_device,
-       .setup  = mpsc_console_setup,
-       .flags  = CON_PRINTBUFFER,
-       .index  = -1,
-       .data   = &mpsc_reg,
-};
-
-static int __init mpsc_late_console_init(void)
-{
-       pr_debug("mpsc_late_console_init: Enter\n");
-
-       if (!(mpsc_console.flags & CON_ENABLED))
-               register_console(&mpsc_console);
-       return 0;
-}
-
-late_initcall(mpsc_late_console_init);
-
-#define MPSC_CONSOLE   &mpsc_console
-#else
-#define MPSC_CONSOLE   NULL
-#endif
-/*
- ******************************************************************************
- *
- * Dummy Platform Driver to extract & map shared register regions
- *
- ******************************************************************************
- */
-static void mpsc_resource_err(char *s)
-{
-       printk(KERN_WARNING "MPSC: Platform device resource error in %s\n", s);
-}
-
-static int mpsc_shared_map_regs(struct platform_device *pd)
-{
-       struct resource *r;
-
-       if ((r = platform_get_resource(pd, IORESOURCE_MEM,
-                                       MPSC_ROUTING_BASE_ORDER))
-                       && request_mem_region(r->start,
-                               MPSC_ROUTING_REG_BLOCK_SIZE,
-                               "mpsc_routing_regs")) {
-               mpsc_shared_regs.mpsc_routing_base = ioremap(r->start,
-                               MPSC_ROUTING_REG_BLOCK_SIZE);
-               mpsc_shared_regs.mpsc_routing_base_p = r->start;
-       } else {
-               mpsc_resource_err("MPSC routing base");
-               return -ENOMEM;
-       }
-
-       if ((r = platform_get_resource(pd, IORESOURCE_MEM,
-                                       MPSC_SDMA_INTR_BASE_ORDER))
-                       && request_mem_region(r->start,
-                               MPSC_SDMA_INTR_REG_BLOCK_SIZE,
-                               "sdma_intr_regs")) {
-               mpsc_shared_regs.sdma_intr_base = ioremap(r->start,
-                       MPSC_SDMA_INTR_REG_BLOCK_SIZE);
-               mpsc_shared_regs.sdma_intr_base_p = r->start;
-       } else {
-               iounmap(mpsc_shared_regs.mpsc_routing_base);
-               release_mem_region(mpsc_shared_regs.mpsc_routing_base_p,
-                               MPSC_ROUTING_REG_BLOCK_SIZE);
-               mpsc_resource_err("SDMA intr base");
-               return -ENOMEM;
-       }
-
-       return 0;
-}
-
-static void mpsc_shared_unmap_regs(void)
-{
-       if (!mpsc_shared_regs.mpsc_routing_base) {
-               iounmap(mpsc_shared_regs.mpsc_routing_base);
-               release_mem_region(mpsc_shared_regs.mpsc_routing_base_p,
-                               MPSC_ROUTING_REG_BLOCK_SIZE);
-       }
-       if (!mpsc_shared_regs.sdma_intr_base) {
-               iounmap(mpsc_shared_regs.sdma_intr_base);
-               release_mem_region(mpsc_shared_regs.sdma_intr_base_p,
-                               MPSC_SDMA_INTR_REG_BLOCK_SIZE);
-       }
-
-       mpsc_shared_regs.mpsc_routing_base = NULL;
-       mpsc_shared_regs.sdma_intr_base = NULL;
-
-       mpsc_shared_regs.mpsc_routing_base_p = 0;
-       mpsc_shared_regs.sdma_intr_base_p = 0;
-}
-
-static int mpsc_shared_drv_probe(struct platform_device *dev)
-{
-       struct mpsc_shared_pdata        *pdata;
-       int                              rc = -ENODEV;
-
-       if (dev->id == 0) {
-               if (!(rc = mpsc_shared_map_regs(dev))) {
-                       pdata = (struct mpsc_shared_pdata *)
-                               dev->dev.platform_data;
-
-                       mpsc_shared_regs.MPSC_MRR_m = pdata->mrr_val;
-                       mpsc_shared_regs.MPSC_RCRR_m= pdata->rcrr_val;
-                       mpsc_shared_regs.MPSC_TCRR_m= pdata->tcrr_val;
-                       mpsc_shared_regs.SDMA_INTR_CAUSE_m =
-                               pdata->intr_cause_val;
-                       mpsc_shared_regs.SDMA_INTR_MASK_m =
-                               pdata->intr_mask_val;
-
-                       rc = 0;
-               }
-       }
-
-       return rc;
-}
-
-static int mpsc_shared_drv_remove(struct platform_device *dev)
-{
-       int     rc = -ENODEV;
-
-       if (dev->id == 0) {
-               mpsc_shared_unmap_regs();
-               mpsc_shared_regs.MPSC_MRR_m = 0;
-               mpsc_shared_regs.MPSC_RCRR_m = 0;
-               mpsc_shared_regs.MPSC_TCRR_m = 0;
-               mpsc_shared_regs.SDMA_INTR_CAUSE_m = 0;
-               mpsc_shared_regs.SDMA_INTR_MASK_m = 0;
-               rc = 0;
-       }
-
-       return rc;
-}
-
-static struct platform_driver mpsc_shared_driver = {
-       .probe  = mpsc_shared_drv_probe,
-       .remove = mpsc_shared_drv_remove,
-       .driver = {
-               .name   = MPSC_SHARED_NAME,
-       },
-};
-
-/*
- ******************************************************************************
- *
- * Driver Interface Routines
- *
- ******************************************************************************
- */
-static struct uart_driver mpsc_reg = {
-       .owner          = THIS_MODULE,
-       .driver_name    = MPSC_DRIVER_NAME,
-       .dev_name       = MPSC_DEV_NAME,
-       .major          = MPSC_MAJOR,
-       .minor          = MPSC_MINOR_START,
-       .nr             = MPSC_NUM_CTLRS,
-       .cons           = MPSC_CONSOLE,
-};
-
-static int mpsc_drv_map_regs(struct mpsc_port_info *pi,
-               struct platform_device *pd)
-{
-       struct resource *r;
-
-       if ((r = platform_get_resource(pd, IORESOURCE_MEM, MPSC_BASE_ORDER))
-                       && request_mem_region(r->start, MPSC_REG_BLOCK_SIZE,
-                       "mpsc_regs")) {
-               pi->mpsc_base = ioremap(r->start, MPSC_REG_BLOCK_SIZE);
-               pi->mpsc_base_p = r->start;
-       } else {
-               mpsc_resource_err("MPSC base");
-               goto err;
-       }
-
-       if ((r = platform_get_resource(pd, IORESOURCE_MEM,
-                                       MPSC_SDMA_BASE_ORDER))
-                       && request_mem_region(r->start,
-                               MPSC_SDMA_REG_BLOCK_SIZE, "sdma_regs")) {
-               pi->sdma_base = ioremap(r->start,MPSC_SDMA_REG_BLOCK_SIZE);
-               pi->sdma_base_p = r->start;
-       } else {
-               mpsc_resource_err("SDMA base");
-               if (pi->mpsc_base) {
-                       iounmap(pi->mpsc_base);
-                       pi->mpsc_base = NULL;
-               }
-               goto err;
-       }
-
-       if ((r = platform_get_resource(pd,IORESOURCE_MEM,MPSC_BRG_BASE_ORDER))
-                       && request_mem_region(r->start,
-                               MPSC_BRG_REG_BLOCK_SIZE, "brg_regs")) {
-               pi->brg_base = ioremap(r->start, MPSC_BRG_REG_BLOCK_SIZE);
-               pi->brg_base_p = r->start;
-       } else {
-               mpsc_resource_err("BRG base");
-               if (pi->mpsc_base) {
-                       iounmap(pi->mpsc_base);
-                       pi->mpsc_base = NULL;
-               }
-               if (pi->sdma_base) {
-                       iounmap(pi->sdma_base);
-                       pi->sdma_base = NULL;
-               }
-               goto err;
-       }
-       return 0;
-
-err:
-       return -ENOMEM;
-}
-
-static void mpsc_drv_unmap_regs(struct mpsc_port_info *pi)
-{
-       if (!pi->mpsc_base) {
-               iounmap(pi->mpsc_base);
-               release_mem_region(pi->mpsc_base_p, MPSC_REG_BLOCK_SIZE);
-       }
-       if (!pi->sdma_base) {
-               iounmap(pi->sdma_base);
-               release_mem_region(pi->sdma_base_p, MPSC_SDMA_REG_BLOCK_SIZE);
-       }
-       if (!pi->brg_base) {
-               iounmap(pi->brg_base);
-               release_mem_region(pi->brg_base_p, MPSC_BRG_REG_BLOCK_SIZE);
-       }
-
-       pi->mpsc_base = NULL;
-       pi->sdma_base = NULL;
-       pi->brg_base = NULL;
-
-       pi->mpsc_base_p = 0;
-       pi->sdma_base_p = 0;
-       pi->brg_base_p = 0;
-}
-
-static void mpsc_drv_get_platform_data(struct mpsc_port_info *pi,
-               struct platform_device *pd, int num)
-{
-       struct mpsc_pdata       *pdata;
-
-       pdata = (struct mpsc_pdata *)pd->dev.platform_data;
-
-       pi->port.uartclk = pdata->brg_clk_freq;
-       pi->port.iotype = UPIO_MEM;
-       pi->port.line = num;
-       pi->port.type = PORT_MPSC;
-       pi->port.fifosize = MPSC_TXBE_SIZE;
-       pi->port.membase = pi->mpsc_base;
-       pi->port.mapbase = (ulong)pi->mpsc_base;
-       pi->port.ops = &mpsc_pops;
-
-       pi->mirror_regs = pdata->mirror_regs;
-       pi->cache_mgmt = pdata->cache_mgmt;
-       pi->brg_can_tune = pdata->brg_can_tune;
-       pi->brg_clk_src = pdata->brg_clk_src;
-       pi->mpsc_max_idle = pdata->max_idle;
-       pi->default_baud = pdata->default_baud;
-       pi->default_bits = pdata->default_bits;
-       pi->default_parity = pdata->default_parity;
-       pi->default_flow = pdata->default_flow;
-
-       /* Initial values of mirrored regs */
-       pi->MPSC_CHR_1_m = pdata->chr_1_val;
-       pi->MPSC_CHR_2_m = pdata->chr_2_val;
-       pi->MPSC_CHR_10_m = pdata->chr_10_val;
-       pi->MPSC_MPCR_m = pdata->mpcr_val;
-       pi->BRG_BCR_m = pdata->bcr_val;
-
-       pi->shared_regs = &mpsc_shared_regs;
-
-       pi->port.irq = platform_get_irq(pd, 0);
-}
-
-static int mpsc_drv_probe(struct platform_device *dev)
-{
-       struct mpsc_port_info   *pi;
-       int                     rc = -ENODEV;
-
-       pr_debug("mpsc_drv_probe: Adding MPSC %d\n", dev->id);
-
-       if (dev->id < MPSC_NUM_CTLRS) {
-               pi = &mpsc_ports[dev->id];
-
-               if (!(rc = mpsc_drv_map_regs(pi, dev))) {
-                       mpsc_drv_get_platform_data(pi, dev, dev->id);
-                       pi->port.dev = &dev->dev;
-
-                       if (!(rc = mpsc_make_ready(pi))) {
-                               spin_lock_init(&pi->tx_lock);
-                               if (!(rc = uart_add_one_port(&mpsc_reg,
-                                                               &pi->port))) {
-                                       rc = 0;
-                               } else {
-                                       mpsc_release_port((struct uart_port *)
-                                                       pi);
-                                       mpsc_drv_unmap_regs(pi);
-                               }
-                       } else {
-                               mpsc_drv_unmap_regs(pi);
-                       }
-               }
-       }
-
-       return rc;
-}
-
-static int mpsc_drv_remove(struct platform_device *dev)
-{
-       pr_debug("mpsc_drv_exit: Removing MPSC %d\n", dev->id);
-
-       if (dev->id < MPSC_NUM_CTLRS) {
-               uart_remove_one_port(&mpsc_reg, &mpsc_ports[dev->id].port);
-               mpsc_release_port((struct uart_port *)
-                               &mpsc_ports[dev->id].port);
-               mpsc_drv_unmap_regs(&mpsc_ports[dev->id]);
-               return 0;
-       } else {
-               return -ENODEV;
-       }
-}
-
-static struct platform_driver mpsc_driver = {
-       .probe  = mpsc_drv_probe,
-       .remove = mpsc_drv_remove,
-       .driver = {
-               .name   = MPSC_CTLR_NAME,
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init mpsc_drv_init(void)
-{
-       int     rc;
-
-       printk(KERN_INFO "Serial: MPSC driver\n");
-
-       memset(mpsc_ports, 0, sizeof(mpsc_ports));
-       memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));
-
-       if (!(rc = uart_register_driver(&mpsc_reg))) {
-               if (!(rc = platform_driver_register(&mpsc_shared_driver))) {
-                       if ((rc = platform_driver_register(&mpsc_driver))) {
-                               platform_driver_unregister(&mpsc_shared_driver);
-                               uart_unregister_driver(&mpsc_reg);
-                       }
-               } else {
-                       uart_unregister_driver(&mpsc_reg);
-               }
-       }
-
-       return rc;
-}
-
-static void __exit mpsc_drv_exit(void)
-{
-       platform_driver_unregister(&mpsc_driver);
-       platform_driver_unregister(&mpsc_shared_driver);
-       uart_unregister_driver(&mpsc_reg);
-       memset(mpsc_ports, 0, sizeof(mpsc_ports));
-       memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));
-}
-
-module_init(mpsc_drv_init);
-module_exit(mpsc_drv_exit);
-
-MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>");
-MODULE_DESCRIPTION("Generic Marvell MPSC serial/UART driver");
-MODULE_VERSION(MPSC_VERSION);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV_MAJOR(MPSC_MAJOR);
-MODULE_ALIAS("platform:" MPSC_CTLR_NAME);
diff --git a/drivers/serial/mrst_max3110.c b/drivers/serial/mrst_max3110.c
deleted file mode 100644 (file)
index b62857b..0000000
+++ /dev/null
@@ -1,919 +0,0 @@
-/*
- *  mrst_max3110.c - spi uart protocol driver for Maxim 3110
- *
- * Copyright (c) 2008-2010, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-/*
- * Note:
- * 1. From Max3110 spec, the Rx FIFO has 8 words, while the Tx FIFO only has
- *    1 word. If SPI master controller doesn't support sclk frequency change,
- *    then the char need be sent out one by one with some delay
- *
- * 2. Currently only RX availabe interrrupt is used, no need for waiting TXE
- *    interrupt for a low speed UART device
- */
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/irq.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial_reg.h>
-
-#include <linux/kthread.h>
-#include <linux/spi/spi.h>
-
-#include "mrst_max3110.h"
-
-#define PR_FMT "mrst_max3110: "
-
-#define UART_TX_NEEDED 1
-#define CON_TX_NEEDED  2
-#define BIT_IRQ_PENDING    3
-
-struct uart_max3110 {
-       struct uart_port port;
-       struct spi_device *spi;
-       char name[24];
-
-       wait_queue_head_t wq;
-       struct task_struct *main_thread;
-       struct task_struct *read_thread;
-       struct mutex thread_mutex;;
-
-       u32 baud;
-       u16 cur_conf;
-       u8 clock;
-       u8 parity, word_7bits;
-       u16 irq;
-
-       unsigned long uart_flags;
-
-       /* console related */
-       struct circ_buf con_xmit;
-};
-
-/* global data structure, may need be removed */
-static struct uart_max3110 *pmax;
-
-static void receive_chars(struct uart_max3110 *max,
-                               unsigned char *str, int len);
-static int max3110_read_multi(struct uart_max3110 *max, u8 *buf);
-static void max3110_con_receive(struct uart_max3110 *max);
-
-static int max3110_write_then_read(struct uart_max3110 *max,
-               const void *txbuf, void *rxbuf, unsigned len, int always_fast)
-{
-       struct spi_device *spi = max->spi;
-       struct spi_message      message;
-       struct spi_transfer     x;
-       int ret;
-
-       spi_message_init(&message);
-       memset(&x, 0, sizeof x);
-       x.len = len;
-       x.tx_buf = txbuf;
-       x.rx_buf = rxbuf;
-       spi_message_add_tail(&x, &message);
-
-       if (always_fast)
-               x.speed_hz = spi->max_speed_hz;
-       else if (max->baud)
-               x.speed_hz = max->baud;
-
-       /* Do the i/o */
-       ret = spi_sync(spi, &message);
-       return ret;
-}
-
-/* Write a 16b word to the device */
-static int max3110_out(struct uart_max3110 *max, const u16 out)
-{
-       void *buf;
-       u16 *obuf, *ibuf;
-       u8  ch;
-       int ret;
-
-       buf = kzalloc(8, GFP_KERNEL | GFP_DMA);
-       if (!buf)
-               return -ENOMEM;
-
-       obuf = buf;
-       ibuf = buf + 4;
-       *obuf = out;
-       ret = max3110_write_then_read(max, obuf, ibuf, 2, 1);
-       if (ret) {
-               pr_warning(PR_FMT "%s(): get err msg %d when sending 0x%x\n",
-                               __func__, ret, out);
-               goto exit;
-       }
-
-       /* If some valid data is read back */
-       if (*ibuf & MAX3110_READ_DATA_AVAILABLE) {
-               ch = *ibuf & 0xff;
-               receive_chars(max, &ch, 1);
-       }
-
-exit:
-       kfree(buf);
-       return ret;
-}
-
-/*
- * This is usually used to read data from SPIC RX FIFO, which doesn't
- * need any delay like flushing character out.
- *
- * Return how many valide bytes are read back
- */
-static int max3110_read_multi(struct uart_max3110 *max, u8 *rxbuf)
-{
-       void *buf;
-       u16 *obuf, *ibuf;
-       u8 *pbuf, valid_str[M3110_RX_FIFO_DEPTH];
-       int i, j, blen;
-
-       blen = M3110_RX_FIFO_DEPTH * sizeof(u16);
-       buf = kzalloc(blen * 2, GFP_KERNEL | GFP_DMA);
-       if (!buf) {
-               pr_warning(PR_FMT "%s(): fail to alloc dma buffer\n", __func__);
-               return 0;
-       }
-
-       /* tx/rx always have the same length */
-       obuf = buf;
-       ibuf = buf + blen;
-
-       if (max3110_write_then_read(max, obuf, ibuf, blen, 1)) {
-               kfree(buf);
-               return 0;
-       }
-
-       /* If caller doesn't provide a buffer, then handle received char */
-       pbuf = rxbuf ? rxbuf : valid_str;
-
-       for (i = 0, j = 0; i < M3110_RX_FIFO_DEPTH; i++) {
-               if (ibuf[i] & MAX3110_READ_DATA_AVAILABLE)
-                       pbuf[j++] = ibuf[i] & 0xff;
-       }
-
-       if (j && (pbuf == valid_str))
-               receive_chars(max, valid_str, j);
-
-       kfree(buf);
-       return j;
-}
-
-static void serial_m3110_con_putchar(struct uart_port *port, int ch)
-{
-       struct uart_max3110 *max =
-               container_of(port, struct uart_max3110, port);
-       struct circ_buf *xmit = &max->con_xmit;
-
-       if (uart_circ_chars_free(xmit)) {
-               xmit->buf[xmit->head] = (char)ch;
-               xmit->head = (xmit->head + 1) & (PAGE_SIZE - 1);
-       }
-}
-
-/*
- * 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.
- */
-static void serial_m3110_con_write(struct console *co,
-                               const char *s, unsigned int count)
-{
-       if (!pmax)
-               return;
-
-       uart_console_write(&pmax->port, s, count, serial_m3110_con_putchar);
-
-       if (!test_and_set_bit(CON_TX_NEEDED, &pmax->uart_flags))
-               wake_up_process(pmax->main_thread);
-}
-
-static int __init
-serial_m3110_con_setup(struct console *co, char *options)
-{
-       struct uart_max3110 *max = pmax;
-       int baud = 115200;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       pr_info(PR_FMT "setting up console\n");
-
-       if (co->index == -1)
-               co->index = 0;
-
-       if (!max) {
-               pr_err(PR_FMT "pmax is NULL, return");
-               return -ENODEV;
-       }
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(&max->port, co, baud, parity, bits, flow);
-}
-
-static struct tty_driver *serial_m3110_con_device(struct console *co,
-                                                       int *index)
-{
-       struct uart_driver *p = co->data;
-       *index = co->index;
-       return p->tty_driver;
-}
-
-static struct uart_driver serial_m3110_reg;
-static struct console serial_m3110_console = {
-       .name           = "ttyS",
-       .write          = serial_m3110_con_write,
-       .device         = serial_m3110_con_device,
-       .setup          = serial_m3110_con_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &serial_m3110_reg,
-};
-
-static unsigned int serial_m3110_tx_empty(struct uart_port *port)
-{
-       return 1;
-}
-
-static void serial_m3110_stop_tx(struct uart_port *port)
-{
-       return;
-}
-
-/* stop_rx will be called in spin_lock env */
-static void serial_m3110_stop_rx(struct uart_port *port)
-{
-       return;
-}
-
-#define WORDS_PER_XFER 128
-static void send_circ_buf(struct uart_max3110 *max,
-                               struct circ_buf *xmit)
-{
-       void *buf;
-       u16 *obuf, *ibuf;
-       u8 valid_str[WORDS_PER_XFER];
-       int i, j, len, blen, dma_size, left, ret = 0;
-
-
-       dma_size = WORDS_PER_XFER * sizeof(u16) * 2;
-       buf = kzalloc(dma_size, GFP_KERNEL | GFP_DMA);
-       if (!buf)
-               return;
-       obuf = buf;
-       ibuf = buf + dma_size/2;
-
-       while (!uart_circ_empty(xmit)) {
-               left = uart_circ_chars_pending(xmit);
-               while (left) {
-                       len = min(left, WORDS_PER_XFER);
-                       blen = len * sizeof(u16);
-                       memset(ibuf, 0, blen);
-
-                       for (i = 0; i < len; i++) {
-                               obuf[i] = (u8)xmit->buf[xmit->tail] | WD_TAG;
-                               xmit->tail = (xmit->tail + 1) &
-                                               (UART_XMIT_SIZE - 1);
-                       }
-
-                       /* Fail to send msg to console is not very critical */
-                       ret = max3110_write_then_read(max, obuf, ibuf, blen, 0);
-                       if (ret)
-                               pr_warning(PR_FMT "%s(): get err msg %d\n",
-                                               __func__, ret);
-
-                       for (i = 0, j = 0; i < len; i++) {
-                               if (ibuf[i] & MAX3110_READ_DATA_AVAILABLE)
-                                       valid_str[j++] = ibuf[i] & 0xff;
-                       }
-
-                       if (j)
-                               receive_chars(max, valid_str, j);
-
-                       max->port.icount.tx += len;
-                       left -= len;
-               }
-       }
-
-       kfree(buf);
-}
-
-static void transmit_char(struct uart_max3110 *max)
-{
-       struct uart_port *port = &max->port;
-       struct circ_buf *xmit = &port->state->xmit;
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port))
-               return;
-
-       send_circ_buf(max, xmit);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (uart_circ_empty(xmit))
-               serial_m3110_stop_tx(port);
-}
-
-/*
- * This will be called by uart_write() and tty_write, can't
- * go to sleep
- */
-static void serial_m3110_start_tx(struct uart_port *port)
-{
-       struct uart_max3110 *max =
-               container_of(port, struct uart_max3110, port);
-
-       if (!test_and_set_bit(UART_TX_NEEDED, &max->uart_flags))
-               wake_up_process(max->main_thread);
-}
-
-static void receive_chars(struct uart_max3110 *max, unsigned char *str, int len)
-{
-       struct uart_port *port = &max->port;
-       struct tty_struct *tty;
-       int usable;
-
-       /* If uart is not opened, just return */
-       if (!port->state)
-               return;
-
-       tty = port->state->port.tty;
-       if (!tty)
-               return;
-
-       while (len) {
-               usable = tty_buffer_request_room(tty, len);
-               if (usable) {
-                       tty_insert_flip_string(tty, str, usable);
-                       str += usable;
-                       port->icount.rx += usable;
-               }
-               len -= usable;
-       }
-       tty_flip_buffer_push(tty);
-}
-
-/*
- * This routine will be used in read_thread or RX IRQ handling,
- * it will first do one round buffer read(8 words), if there is some
- * valid RX data, will try to read 5 more rounds till all data
- * is read out.
- *
- * Use stack space as data buffer to save some system load, and chose
- * 504 Btyes as a threadhold to do a bulk push to upper tty layer when
- * receiving bulk data, a much bigger buffer may cause stack overflow
- */
-static void max3110_con_receive(struct uart_max3110 *max)
-{
-       int loop = 1, num, total = 0;
-       u8 recv_buf[512], *pbuf;
-
-       pbuf = recv_buf;
-       do {
-               num = max3110_read_multi(max, pbuf);
-
-               if (num) {
-                       loop = 5;
-                       pbuf += num;
-                       total += num;
-
-                       if (total >= 504) {
-                               receive_chars(max, recv_buf, total);
-                               pbuf = recv_buf;
-                               total = 0;
-                       }
-               }
-       } while (--loop);
-
-       if (total)
-               receive_chars(max, recv_buf, total);
-}
-
-static int max3110_main_thread(void *_max)
-{
-       struct uart_max3110 *max = _max;
-       wait_queue_head_t *wq = &max->wq;
-       int ret = 0;
-       struct circ_buf *xmit = &max->con_xmit;
-
-       init_waitqueue_head(wq);
-       pr_info(PR_FMT "start main thread\n");
-
-       do {
-               wait_event_interruptible(*wq, max->uart_flags || kthread_should_stop());
-
-               mutex_lock(&max->thread_mutex);
-
-               if (test_and_clear_bit(BIT_IRQ_PENDING, &max->uart_flags))
-                       max3110_con_receive(max);
-
-               /* first handle console output */
-               if (test_and_clear_bit(CON_TX_NEEDED, &max->uart_flags))
-                       send_circ_buf(max, xmit);
-
-               /* handle uart output */
-               if (test_and_clear_bit(UART_TX_NEEDED, &max->uart_flags))
-                       transmit_char(max);
-
-               mutex_unlock(&max->thread_mutex);
-
-       } while (!kthread_should_stop());
-
-       return ret;
-}
-
-static irqreturn_t serial_m3110_irq(int irq, void *dev_id)
-{
-       struct uart_max3110 *max = dev_id;
-
-       /* max3110's irq is a falling edge, not level triggered,
-        * so no need to disable the irq */
-       if (!test_and_set_bit(BIT_IRQ_PENDING, &max->uart_flags))
-               wake_up_process(max->main_thread);
-
-       return IRQ_HANDLED;
-}
-
-/* if don't use RX IRQ, then need a thread to polling read */
-static int max3110_read_thread(void *_max)
-{
-       struct uart_max3110 *max = _max;
-
-       pr_info(PR_FMT "start read thread\n");
-       do {
-               /*
-                * If can't acquire the mutex, it means the main thread
-                * is running which will also perform the rx job
-                */
-               if (mutex_trylock(&max->thread_mutex)) {
-                       max3110_con_receive(max);
-                       mutex_unlock(&max->thread_mutex);
-               }
-
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(HZ / 20);
-       } while (!kthread_should_stop());
-
-       return 0;
-}
-
-static int serial_m3110_startup(struct uart_port *port)
-{
-       struct uart_max3110 *max =
-               container_of(port, struct uart_max3110, port);
-       u16 config = 0;
-       int ret = 0;
-
-       if (port->line != 0) {
-               pr_err(PR_FMT "uart port startup failed\n");
-               return -1;
-       }
-
-       /* Disable all IRQ and config it to 115200, 8n1 */
-       config = WC_TAG | WC_FIFO_ENABLE
-                       | WC_1_STOPBITS
-                       | WC_8BIT_WORD
-                       | WC_BAUD_DR2;
-
-       /* as we use thread to handle tx/rx, need set low latency */
-       port->state->port.tty->low_latency = 1;
-
-       if (max->irq) {
-               max->read_thread = NULL;
-               ret = request_irq(max->irq, serial_m3110_irq,
-                               IRQ_TYPE_EDGE_FALLING, "max3110", max);
-               if (ret) {
-                       max->irq = 0;
-                       pr_err(PR_FMT "unable to allocate IRQ, polling\n");
-               }  else {
-                       /* Enable RX IRQ only */
-                       config |= WC_RXA_IRQ_ENABLE;
-               }
-       }
-
-       if (max->irq == 0) {
-               /* If IRQ is disabled, start a read thread for input data */
-               max->read_thread =
-                       kthread_run(max3110_read_thread, max, "max3110_read");
-               if (IS_ERR(max->read_thread)) {
-                       ret = PTR_ERR(max->read_thread);
-                       max->read_thread = NULL;
-                       pr_err(PR_FMT "Can't create read thread!\n");
-                       return ret;
-               }
-       }
-
-       ret = max3110_out(max, config);
-       if (ret) {
-               if (max->irq)
-                       free_irq(max->irq, max);
-               if (max->read_thread)
-                       kthread_stop(max->read_thread);
-               max->read_thread = NULL;
-               return ret;
-       }
-
-       max->cur_conf = config;
-       return 0;
-}
-
-static void serial_m3110_shutdown(struct uart_port *port)
-{
-       struct uart_max3110 *max =
-               container_of(port, struct uart_max3110, port);
-       u16 config;
-
-       if (max->read_thread) {
-               kthread_stop(max->read_thread);
-               max->read_thread = NULL;
-       }
-
-       if (max->irq)
-               free_irq(max->irq, max);
-
-       /* Disable interrupts from this port */
-       config = WC_TAG | WC_SW_SHDI;
-       max3110_out(max, config);
-}
-
-static void serial_m3110_release_port(struct uart_port *port)
-{
-}
-
-static int serial_m3110_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-static void serial_m3110_config_port(struct uart_port *port, int flags)
-{
-       port->type = PORT_MAX3100;
-}
-
-static int
-serial_m3110_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       /* we don't want the core code to modify any port params */
-       return -EINVAL;
-}
-
-
-static const char *serial_m3110_type(struct uart_port *port)
-{
-       struct uart_max3110 *max =
-               container_of(port, struct uart_max3110, port);
-       return max->name;
-}
-
-static void
-serial_m3110_set_termios(struct uart_port *port, struct ktermios *termios,
-                      struct ktermios *old)
-{
-       struct uart_max3110 *max =
-               container_of(port, struct uart_max3110, port);
-       unsigned char cval;
-       unsigned int baud, parity = 0;
-       int clk_div = -1;
-       u16 new_conf = max->cur_conf;
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS7:
-               cval = UART_LCR_WLEN7;
-               new_conf |= WC_7BIT_WORD;
-               break;
-       default:
-               /* We only support CS7 & CS8 */
-               termios->c_cflag &= ~CSIZE;
-               termios->c_cflag |= CS8;
-       case CS8:
-               cval = UART_LCR_WLEN8;
-               new_conf |= WC_8BIT_WORD;
-               break;
-       }
-
-       baud = uart_get_baud_rate(port, termios, old, 0, 230400);
-
-       /* First calc the div for 1.8MHZ clock case */
-       switch (baud) {
-       case 300:
-               clk_div = WC_BAUD_DR384;
-               break;
-       case 600:
-               clk_div = WC_BAUD_DR192;
-               break;
-       case 1200:
-               clk_div = WC_BAUD_DR96;
-               break;
-       case 2400:
-               clk_div = WC_BAUD_DR48;
-               break;
-       case 4800:
-               clk_div = WC_BAUD_DR24;
-               break;
-       case 9600:
-               clk_div = WC_BAUD_DR12;
-               break;
-       case 19200:
-               clk_div = WC_BAUD_DR6;
-               break;
-       case 38400:
-               clk_div = WC_BAUD_DR3;
-               break;
-       case 57600:
-               clk_div = WC_BAUD_DR2;
-               break;
-       case 115200:
-               clk_div = WC_BAUD_DR1;
-               break;
-       case 230400:
-               if (max->clock & MAX3110_HIGH_CLK)
-                       break;
-       default:
-               /* Pick the previous baud rate */
-               baud = max->baud;
-               clk_div = max->cur_conf & WC_BAUD_DIV_MASK;
-               tty_termios_encode_baud_rate(termios, baud, baud);
-       }
-
-       if (max->clock & MAX3110_HIGH_CLK) {
-               clk_div += 1;
-               /* High clk version max3110 doesn't support B300 */
-               if (baud == 300) {
-                       baud = 600;
-                       clk_div = WC_BAUD_DR384;
-               }
-               if (baud == 230400)
-                       clk_div = WC_BAUD_DR1;
-               tty_termios_encode_baud_rate(termios, baud, baud);
-       }
-
-       new_conf = (new_conf & ~WC_BAUD_DIV_MASK) | clk_div;
-
-       if (unlikely(termios->c_cflag & CMSPAR))
-               termios->c_cflag &= ~CMSPAR;
-
-       if (termios->c_cflag & CSTOPB)
-               new_conf |= WC_2_STOPBITS;
-       else
-               new_conf &= ~WC_2_STOPBITS;
-
-       if (termios->c_cflag & PARENB) {
-               new_conf |= WC_PARITY_ENABLE;
-               parity |= UART_LCR_PARITY;
-       } else
-               new_conf &= ~WC_PARITY_ENABLE;
-
-       if (!(termios->c_cflag & PARODD))
-               parity |= UART_LCR_EPAR;
-       max->parity = parity;
-
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       new_conf |= WC_TAG;
-       if (new_conf != max->cur_conf) {
-               if (!max3110_out(max, new_conf)) {
-                       max->cur_conf = new_conf;
-                       max->baud = baud;
-               }
-       }
-}
-
-/* Don't handle hw handshaking */
-static unsigned int serial_m3110_get_mctrl(struct uart_port *port)
-{
-       return TIOCM_DSR | TIOCM_CAR | TIOCM_DSR;
-}
-
-static void serial_m3110_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-}
-
-static void serial_m3110_break_ctl(struct uart_port *port, int break_state)
-{
-}
-
-static void serial_m3110_pm(struct uart_port *port, unsigned int state,
-                       unsigned int oldstate)
-{
-}
-
-static void serial_m3110_enable_ms(struct uart_port *port)
-{
-}
-
-struct uart_ops serial_m3110_ops = {
-       .tx_empty       = serial_m3110_tx_empty,
-       .set_mctrl      = serial_m3110_set_mctrl,
-       .get_mctrl      = serial_m3110_get_mctrl,
-       .stop_tx        = serial_m3110_stop_tx,
-       .start_tx       = serial_m3110_start_tx,
-       .stop_rx        = serial_m3110_stop_rx,
-       .enable_ms      = serial_m3110_enable_ms,
-       .break_ctl      = serial_m3110_break_ctl,
-       .startup        = serial_m3110_startup,
-       .shutdown       = serial_m3110_shutdown,
-       .set_termios    = serial_m3110_set_termios,
-       .pm             = serial_m3110_pm,
-       .type           = serial_m3110_type,
-       .release_port   = serial_m3110_release_port,
-       .request_port   = serial_m3110_request_port,
-       .config_port    = serial_m3110_config_port,
-       .verify_port    = serial_m3110_verify_port,
-};
-
-static struct uart_driver serial_m3110_reg = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "MRST serial",
-       .dev_name       = "ttyS",
-       .major          = TTY_MAJOR,
-       .minor          = 64,
-       .nr             = 1,
-       .cons           = &serial_m3110_console,
-};
-
-#ifdef CONFIG_PM
-static int serial_m3110_suspend(struct spi_device *spi, pm_message_t state)
-{
-       struct uart_max3110 *max = spi_get_drvdata(spi);
-
-       disable_irq(max->irq);
-       uart_suspend_port(&serial_m3110_reg, &max->port);
-       max3110_out(max, max->cur_conf | WC_SW_SHDI);
-       return 0;
-}
-
-static int serial_m3110_resume(struct spi_device *spi)
-{
-       struct uart_max3110 *max = spi_get_drvdata(spi);
-
-       max3110_out(max, max->cur_conf);
-       uart_resume_port(&serial_m3110_reg, &max->port);
-       enable_irq(max->irq);
-       return 0;
-}
-#else
-#define serial_m3110_suspend   NULL
-#define serial_m3110_resume    NULL
-#endif
-
-static int __devinit serial_m3110_probe(struct spi_device *spi)
-{
-       struct uart_max3110 *max;
-       void *buffer;
-       u16 res;
-       int ret = 0;
-
-       max = kzalloc(sizeof(*max), GFP_KERNEL);
-       if (!max)
-               return -ENOMEM;
-
-       /* Set spi info */
-       spi->bits_per_word = 16;
-       max->clock = MAX3110_HIGH_CLK;
-
-       spi_setup(spi);
-
-       max->port.type = PORT_MAX3100;
-       max->port.fifosize = 2;         /* Only have 16b buffer */
-       max->port.ops = &serial_m3110_ops;
-       max->port.line = 0;
-       max->port.dev = &spi->dev;
-       max->port.uartclk = 115200;
-
-       max->spi = spi;
-       strcpy(max->name, spi->modalias);
-       max->irq = (u16)spi->irq;
-
-       mutex_init(&max->thread_mutex);
-
-       max->word_7bits = 0;
-       max->parity = 0;
-       max->baud = 0;
-
-       max->cur_conf = 0;
-       max->uart_flags = 0;
-
-       /* Check if reading configuration register returns something sane */
-
-       res = RC_TAG;
-       ret = max3110_write_then_read(max, (u8 *)&res, (u8 *)&res, 2, 0);
-       if (ret < 0 || res == 0 || res == 0xffff) {
-               printk(KERN_ERR "MAX3111 deemed not present (conf reg %04x)",
-                                                                       res);
-               ret = -ENODEV;
-               goto err_get_page;
-       }
-
-       buffer = (void *)__get_free_page(GFP_KERNEL);
-       if (!buffer) {
-               ret = -ENOMEM;
-               goto err_get_page;
-       }
-       max->con_xmit.buf = buffer;
-       max->con_xmit.head = 0;
-       max->con_xmit.tail = 0;
-
-       max->main_thread = kthread_run(max3110_main_thread,
-                                       max, "max3110_main");
-       if (IS_ERR(max->main_thread)) {
-               ret = PTR_ERR(max->main_thread);
-               goto err_kthread;
-       }
-
-       spi_set_drvdata(spi, max);
-       pmax = max;
-
-       /* Give membase a psudo value to pass serial_core's check */
-       max->port.membase = (void *)0xff110000;
-       uart_add_one_port(&serial_m3110_reg, &max->port);
-
-       return 0;
-
-err_kthread:
-       free_page((unsigned long)buffer);
-err_get_page:
-       kfree(max);
-       return ret;
-}
-
-static int __devexit serial_m3110_remove(struct spi_device *dev)
-{
-       struct uart_max3110 *max = spi_get_drvdata(dev);
-
-       if (!max)
-               return 0;
-
-       uart_remove_one_port(&serial_m3110_reg, &max->port);
-
-       free_page((unsigned long)max->con_xmit.buf);
-
-       if (max->main_thread)
-               kthread_stop(max->main_thread);
-
-       kfree(max);
-       return 0;
-}
-
-static struct spi_driver uart_max3110_driver = {
-       .driver = {
-                       .name   = "spi_max3111",
-                       .bus    = &spi_bus_type,
-                       .owner  = THIS_MODULE,
-       },
-       .probe          = serial_m3110_probe,
-       .remove         = __devexit_p(serial_m3110_remove),
-       .suspend        = serial_m3110_suspend,
-       .resume         = serial_m3110_resume,
-};
-
-static int __init serial_m3110_init(void)
-{
-       int ret = 0;
-
-       ret = uart_register_driver(&serial_m3110_reg);
-       if (ret)
-               return ret;
-
-       ret = spi_register_driver(&uart_max3110_driver);
-       if (ret)
-               uart_unregister_driver(&serial_m3110_reg);
-
-       return ret;
-}
-
-static void __exit serial_m3110_exit(void)
-{
-       spi_unregister_driver(&uart_max3110_driver);
-       uart_unregister_driver(&serial_m3110_reg);
-}
-
-module_init(serial_m3110_init);
-module_exit(serial_m3110_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("max3110-uart");
diff --git a/drivers/serial/mrst_max3110.h b/drivers/serial/mrst_max3110.h
deleted file mode 100644 (file)
index d1ef43a..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef _MRST_MAX3110_H
-#define _MRST_MAX3110_H
-
-#define MAX3110_HIGH_CLK       0x1     /* 3.6864 MHZ */
-#define MAX3110_LOW_CLK                0x0     /* 1.8432 MHZ */
-
-/* status bits for all 4 MAX3110 operate modes */
-#define MAX3110_READ_DATA_AVAILABLE    (1 << 15)
-#define MAX3110_WRITE_BUF_EMPTY                (1 << 14)
-
-#define WC_TAG                 (3 << 14)
-#define RC_TAG                 (1 << 14)
-#define WD_TAG                 (2 << 14)
-#define RD_TAG                 (0 << 14)
-
-/* bits def for write configuration */
-#define WC_FIFO_ENABLE_MASK    (1 << 13)
-#define WC_FIFO_ENABLE         (0 << 13)
-
-#define WC_SW_SHDI             (1 << 12)
-
-#define WC_IRQ_MASK            (0xF << 8)
-#define WC_TXE_IRQ_ENABLE      (1 << 11)       /* TX empty irq */
-#define WC_RXA_IRQ_ENABLE      (1 << 10)       /* RX availabe irq */
-#define WC_PAR_HIGH_IRQ_ENABLE (1 << 9)
-#define WC_REC_ACT_IRQ_ENABLE  (1 << 8)
-
-#define WC_IRDA_ENABLE         (1 << 7)
-
-#define WC_STOPBITS_MASK       (1 << 6)
-#define WC_2_STOPBITS          (1 << 6)
-#define WC_1_STOPBITS          (0 << 6)
-
-#define WC_PARITY_ENABLE_MASK  (1 << 5)
-#define WC_PARITY_ENABLE       (1 << 5)
-
-#define WC_WORDLEN_MASK                (1 << 4)
-#define WC_7BIT_WORD           (1 << 4)
-#define WC_8BIT_WORD           (0 << 4)
-
-#define WC_BAUD_DIV_MASK       (0xF)
-#define WC_BAUD_DR1            (0x0)
-#define WC_BAUD_DR2            (0x1)
-#define WC_BAUD_DR4            (0x2)
-#define WC_BAUD_DR8            (0x3)
-#define WC_BAUD_DR16           (0x4)
-#define WC_BAUD_DR32           (0x5)
-#define WC_BAUD_DR64           (0x6)
-#define WC_BAUD_DR128          (0x7)
-#define WC_BAUD_DR3            (0x8)
-#define WC_BAUD_DR6            (0x9)
-#define WC_BAUD_DR12           (0xA)
-#define WC_BAUD_DR24           (0xB)
-#define WC_BAUD_DR48           (0xC)
-#define WC_BAUD_DR96           (0xD)
-#define WC_BAUD_DR192          (0xE)
-#define WC_BAUD_DR384          (0xF)
-
-#define M3110_RX_FIFO_DEPTH    8
-#endif
diff --git a/drivers/serial/msm_serial.c b/drivers/serial/msm_serial.c
deleted file mode 100644 (file)
index 8e43a7b..0000000
+++ /dev/null
@@ -1,758 +0,0 @@
-/*
- * drivers/serial/msm_serial.c - driver for msm7k serial device and console
- *
- * Copyright (C) 2007 Google, Inc.
- * Author: Robert Love <rlove@google.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- */
-
-#if defined(CONFIG_SERIAL_MSM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-# define SUPPORT_SYSRQ
-#endif
-
-#include <linux/hrtimer.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
-#include <linux/irq.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-
-#include "msm_serial.h"
-
-struct msm_port {
-       struct uart_port        uart;
-       char                    name[16];
-       struct clk              *clk;
-       unsigned int            imr;
-};
-
-static void msm_stop_tx(struct uart_port *port)
-{
-       struct msm_port *msm_port = UART_TO_MSM(port);
-
-       msm_port->imr &= ~UART_IMR_TXLEV;
-       msm_write(port, msm_port->imr, UART_IMR);
-}
-
-static void msm_start_tx(struct uart_port *port)
-{
-       struct msm_port *msm_port = UART_TO_MSM(port);
-
-       msm_port->imr |= UART_IMR_TXLEV;
-       msm_write(port, msm_port->imr, UART_IMR);
-}
-
-static void msm_stop_rx(struct uart_port *port)
-{
-       struct msm_port *msm_port = UART_TO_MSM(port);
-
-       msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE);
-       msm_write(port, msm_port->imr, UART_IMR);
-}
-
-static void msm_enable_ms(struct uart_port *port)
-{
-       struct msm_port *msm_port = UART_TO_MSM(port);
-
-       msm_port->imr |= UART_IMR_DELTA_CTS;
-       msm_write(port, msm_port->imr, UART_IMR);
-}
-
-static void handle_rx(struct uart_port *port)
-{
-       struct tty_struct *tty = port->state->port.tty;
-       unsigned int sr;
-
-       /*
-        * Handle overrun. My understanding of the hardware is that overrun
-        * is not tied to the RX buffer, so we handle the case out of band.
-        */
-       if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) {
-               port->icount.overrun++;
-               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
-       }
-
-       /* and now the main RX loop */
-       while ((sr = msm_read(port, UART_SR)) & UART_SR_RX_READY) {
-               unsigned int c;
-               char flag = TTY_NORMAL;
-
-               c = msm_read(port, UART_RF);
-
-               if (sr & UART_SR_RX_BREAK) {
-                       port->icount.brk++;
-                       if (uart_handle_break(port))
-                               continue;
-               } else if (sr & UART_SR_PAR_FRAME_ERR) {
-                       port->icount.frame++;
-               } else {
-                       port->icount.rx++;
-               }
-
-               /* Mask conditions we're ignorning. */
-               sr &= port->read_status_mask;
-
-               if (sr & UART_SR_RX_BREAK) {
-                       flag = TTY_BREAK;
-               } else if (sr & UART_SR_PAR_FRAME_ERR) {
-                       flag = TTY_FRAME;
-               }
-
-               if (!uart_handle_sysrq_char(port, c))
-                       tty_insert_flip_char(tty, c, flag);
-       }
-
-       tty_flip_buffer_push(tty);
-}
-
-static void handle_tx(struct uart_port *port)
-{
-       struct circ_buf *xmit = &port->state->xmit;
-       struct msm_port *msm_port = UART_TO_MSM(port);
-       int sent_tx;
-
-       if (port->x_char) {
-               msm_write(port, port->x_char, UART_TF);
-               port->icount.tx++;
-               port->x_char = 0;
-       }
-
-       while (msm_read(port, UART_SR) & UART_SR_TX_READY) {
-               if (uart_circ_empty(xmit)) {
-                       /* disable tx interrupts */
-                       msm_port->imr &= ~UART_IMR_TXLEV;
-                       msm_write(port, msm_port->imr, UART_IMR);
-                       break;
-               }
-
-               msm_write(port, xmit->buf[xmit->tail], UART_TF);
-
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-               sent_tx = 1;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-}
-
-static void handle_delta_cts(struct uart_port *port)
-{
-       msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
-       port->icount.cts++;
-       wake_up_interruptible(&port->state->port.delta_msr_wait);
-}
-
-static irqreturn_t msm_irq(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       struct msm_port *msm_port = UART_TO_MSM(port);
-       unsigned int misr;
-
-       spin_lock(&port->lock);
-       misr = msm_read(port, UART_MISR);
-       msm_write(port, 0, UART_IMR); /* disable interrupt */
-
-       if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE))
-               handle_rx(port);
-       if (misr & UART_IMR_TXLEV)
-               handle_tx(port);
-       if (misr & UART_IMR_DELTA_CTS)
-               handle_delta_cts(port);
-
-       msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */
-       spin_unlock(&port->lock);
-
-       return IRQ_HANDLED;
-}
-
-static unsigned int msm_tx_empty(struct uart_port *port)
-{
-       return (msm_read(port, UART_SR) & UART_SR_TX_EMPTY) ? TIOCSER_TEMT : 0;
-}
-
-static unsigned int msm_get_mctrl(struct uart_port *port)
-{
-       return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR | TIOCM_RTS;
-}
-
-static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       unsigned int mr;
-
-       mr = msm_read(port, UART_MR1);
-
-       if (!(mctrl & TIOCM_RTS)) {
-               mr &= ~UART_MR1_RX_RDY_CTL;
-               msm_write(port, mr, UART_MR1);
-               msm_write(port, UART_CR_CMD_RESET_RFR, UART_CR);
-       } else {
-               mr |= UART_MR1_RX_RDY_CTL;
-               msm_write(port, mr, UART_MR1);
-       }
-}
-
-static void msm_break_ctl(struct uart_port *port, int break_ctl)
-{
-       if (break_ctl)
-               msm_write(port, UART_CR_CMD_START_BREAK, UART_CR);
-       else
-               msm_write(port, UART_CR_CMD_STOP_BREAK, UART_CR);
-}
-
-static int msm_set_baud_rate(struct uart_port *port, unsigned int baud)
-{
-       unsigned int baud_code, rxstale, watermark;
-
-       switch (baud) {
-       case 300:
-               baud_code = UART_CSR_300;
-               rxstale = 1;
-               break;
-       case 600:
-               baud_code = UART_CSR_600;
-               rxstale = 1;
-               break;
-       case 1200:
-               baud_code = UART_CSR_1200;
-               rxstale = 1;
-               break;
-       case 2400:
-               baud_code = UART_CSR_2400;
-               rxstale = 1;
-               break;
-       case 4800:
-               baud_code = UART_CSR_4800;
-               rxstale = 1;
-               break;
-       case 9600:
-               baud_code = UART_CSR_9600;
-               rxstale = 2;
-               break;
-       case 14400:
-               baud_code = UART_CSR_14400;
-               rxstale = 3;
-               break;
-       case 19200:
-               baud_code = UART_CSR_19200;
-               rxstale = 4;
-               break;
-       case 28800:
-               baud_code = UART_CSR_28800;
-               rxstale = 6;
-               break;
-       case 38400:
-               baud_code = UART_CSR_38400;
-               rxstale = 8;
-               break;
-       case 57600:
-               baud_code = UART_CSR_57600;
-               rxstale = 16;
-               break;
-       case 115200:
-       default:
-               baud_code = UART_CSR_115200;
-               baud = 115200;
-               rxstale = 31;
-               break;
-       }
-
-       msm_write(port, baud_code, UART_CSR);
-
-       /* RX stale watermark */
-       watermark = UART_IPR_STALE_LSB & rxstale;
-       watermark |= UART_IPR_RXSTALE_LAST;
-       watermark |= UART_IPR_STALE_TIMEOUT_MSB & (rxstale << 2);
-       msm_write(port, watermark, UART_IPR);
-
-       /* set RX watermark */
-       watermark = (port->fifosize * 3) / 4;
-       msm_write(port, watermark, UART_RFWR);
-
-       /* set TX watermark */
-       msm_write(port, 10, UART_TFWR);
-
-       return baud;
-}
-
-static void msm_reset(struct uart_port *port)
-{
-       /* reset everything */
-       msm_write(port, UART_CR_CMD_RESET_RX, UART_CR);
-       msm_write(port, UART_CR_CMD_RESET_TX, UART_CR);
-       msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
-       msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR);
-       msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
-       msm_write(port, UART_CR_CMD_SET_RFR, UART_CR);
-}
-
-static void msm_init_clock(struct uart_port *port)
-{
-       struct msm_port *msm_port = UART_TO_MSM(port);
-
-       clk_enable(msm_port->clk);
-       msm_serial_set_mnd_regs(port);
-}
-
-static int msm_startup(struct uart_port *port)
-{
-       struct msm_port *msm_port = UART_TO_MSM(port);
-       unsigned int data, rfr_level;
-       int ret;
-
-       snprintf(msm_port->name, sizeof(msm_port->name),
-                "msm_serial%d", port->line);
-
-       ret = request_irq(port->irq, msm_irq, IRQF_TRIGGER_HIGH,
-                         msm_port->name, port);
-       if (unlikely(ret))
-               return ret;
-
-       msm_init_clock(port);
-
-       if (likely(port->fifosize > 12))
-               rfr_level = port->fifosize - 12;
-       else
-               rfr_level = port->fifosize;
-
-       /* set automatic RFR level */
-       data = msm_read(port, UART_MR1);
-       data &= ~UART_MR1_AUTO_RFR_LEVEL1;
-       data &= ~UART_MR1_AUTO_RFR_LEVEL0;
-       data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2);
-       data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level;
-       msm_write(port, data, UART_MR1);
-
-       /* make sure that RXSTALE count is non-zero */
-       data = msm_read(port, UART_IPR);
-       if (unlikely(!data)) {
-               data |= UART_IPR_RXSTALE_LAST;
-               data |= UART_IPR_STALE_LSB;
-               msm_write(port, data, UART_IPR);
-       }
-
-       msm_reset(port);
-
-       msm_write(port, 0x05, UART_CR); /* enable TX & RX */
-
-       /* turn on RX and CTS interrupts */
-       msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE |
-                       UART_IMR_CURRENT_CTS;
-       msm_write(port, msm_port->imr, UART_IMR);
-
-       return 0;
-}
-
-static void msm_shutdown(struct uart_port *port)
-{
-       struct msm_port *msm_port = UART_TO_MSM(port);
-
-       msm_port->imr = 0;
-       msm_write(port, 0, UART_IMR); /* disable interrupts */
-
-       clk_disable(msm_port->clk);
-
-       free_irq(port->irq, port);
-}
-
-static void msm_set_termios(struct uart_port *port, struct ktermios *termios,
-                           struct ktermios *old)
-{
-       unsigned long flags;
-       unsigned int baud, mr;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /* calculate and set baud rate */
-       baud = uart_get_baud_rate(port, termios, old, 300, 115200);
-       baud = msm_set_baud_rate(port, baud);
-       if (tty_termios_baud_rate(termios))
-               tty_termios_encode_baud_rate(termios, baud, baud);
-       
-       /* calculate parity */
-       mr = msm_read(port, UART_MR2);
-       mr &= ~UART_MR2_PARITY_MODE;
-       if (termios->c_cflag & PARENB) {
-               if (termios->c_cflag & PARODD)
-                       mr |= UART_MR2_PARITY_MODE_ODD;
-               else if (termios->c_cflag & CMSPAR)
-                       mr |= UART_MR2_PARITY_MODE_SPACE;
-               else
-                       mr |= UART_MR2_PARITY_MODE_EVEN;
-       }
-
-       /* calculate bits per char */
-       mr &= ~UART_MR2_BITS_PER_CHAR;
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               mr |= UART_MR2_BITS_PER_CHAR_5;
-               break;
-       case CS6:
-               mr |= UART_MR2_BITS_PER_CHAR_6;
-               break;
-       case CS7:
-               mr |= UART_MR2_BITS_PER_CHAR_7;
-               break;
-       case CS8:
-       default:
-               mr |= UART_MR2_BITS_PER_CHAR_8;
-               break;
-       }
-
-       /* calculate stop bits */
-       mr &= ~(UART_MR2_STOP_BIT_LEN_ONE | UART_MR2_STOP_BIT_LEN_TWO);
-       if (termios->c_cflag & CSTOPB)
-               mr |= UART_MR2_STOP_BIT_LEN_TWO;
-       else
-               mr |= UART_MR2_STOP_BIT_LEN_ONE;
-
-       /* set parity, bits per char, and stop bit */
-       msm_write(port, mr, UART_MR2);
-
-       /* calculate and set hardware flow control */
-       mr = msm_read(port, UART_MR1);
-       mr &= ~(UART_MR1_CTS_CTL | UART_MR1_RX_RDY_CTL);
-       if (termios->c_cflag & CRTSCTS) {
-               mr |= UART_MR1_CTS_CTL;
-               mr |= UART_MR1_RX_RDY_CTL;
-       }
-       msm_write(port, mr, UART_MR1);
-
-       /* Configure status bits to ignore based on termio flags. */
-       port->read_status_mask = 0;
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= UART_SR_PAR_FRAME_ERR;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               port->read_status_mask |= UART_SR_RX_BREAK;
-
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *msm_type(struct uart_port *port)
-{
-       return "MSM";
-}
-
-static void msm_release_port(struct uart_port *port)
-{
-       struct platform_device *pdev = to_platform_device(port->dev);
-       struct resource *resource;
-       resource_size_t size;
-
-       resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (unlikely(!resource))
-               return;
-       size = resource->end - resource->start + 1;
-
-       release_mem_region(port->mapbase, size);
-       iounmap(port->membase);
-       port->membase = NULL;
-}
-
-static int msm_request_port(struct uart_port *port)
-{
-       struct platform_device *pdev = to_platform_device(port->dev);
-       struct resource *resource;
-       resource_size_t size;
-
-       resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (unlikely(!resource))
-               return -ENXIO;
-       size = resource->end - resource->start + 1;
-
-       if (unlikely(!request_mem_region(port->mapbase, size, "msm_serial")))
-               return -EBUSY;
-
-       port->membase = ioremap(port->mapbase, size);
-       if (!port->membase) {
-               release_mem_region(port->mapbase, size);
-               return -EBUSY;
-       }
-
-       return 0;
-}
-
-static void msm_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE) {
-               port->type = PORT_MSM;
-               msm_request_port(port);
-       }
-}
-
-static int msm_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       if (unlikely(ser->type != PORT_UNKNOWN && ser->type != PORT_MSM))
-               return -EINVAL;
-       if (unlikely(port->irq != ser->irq))
-               return -EINVAL;
-       return 0;
-}
-
-static void msm_power(struct uart_port *port, unsigned int state,
-                     unsigned int oldstate)
-{
-       struct msm_port *msm_port = UART_TO_MSM(port);
-
-       switch (state) {
-       case 0:
-               clk_enable(msm_port->clk);
-               break;
-       case 3:
-               clk_disable(msm_port->clk);
-               break;
-       default:
-               printk(KERN_ERR "msm_serial: Unknown PM state %d\n", state);
-       }
-}
-
-static struct uart_ops msm_uart_pops = {
-       .tx_empty = msm_tx_empty,
-       .set_mctrl = msm_set_mctrl,
-       .get_mctrl = msm_get_mctrl,
-       .stop_tx = msm_stop_tx,
-       .start_tx = msm_start_tx,
-       .stop_rx = msm_stop_rx,
-       .enable_ms = msm_enable_ms,
-       .break_ctl = msm_break_ctl,
-       .startup = msm_startup,
-       .shutdown = msm_shutdown,
-       .set_termios = msm_set_termios,
-       .type = msm_type,
-       .release_port = msm_release_port,
-       .request_port = msm_request_port,
-       .config_port = msm_config_port,
-       .verify_port = msm_verify_port,
-       .pm = msm_power,
-};
-
-static struct msm_port msm_uart_ports[] = {
-       {
-               .uart = {
-                       .iotype = UPIO_MEM,
-                       .ops = &msm_uart_pops,
-                       .flags = UPF_BOOT_AUTOCONF,
-                       .fifosize = 512,
-                       .line = 0,
-               },
-       },
-       {
-               .uart = {
-                       .iotype = UPIO_MEM,
-                       .ops = &msm_uart_pops,
-                       .flags = UPF_BOOT_AUTOCONF,
-                       .fifosize = 512,
-                       .line = 1,
-               },
-       },
-       {
-               .uart = {
-                       .iotype = UPIO_MEM,
-                       .ops = &msm_uart_pops,
-                       .flags = UPF_BOOT_AUTOCONF,
-                       .fifosize = 64,
-                       .line = 2,
-               },
-       },
-};
-
-#define UART_NR        ARRAY_SIZE(msm_uart_ports)
-
-static inline struct uart_port *get_port_from_line(unsigned int line)
-{
-       return &msm_uart_ports[line].uart;
-}
-
-#ifdef CONFIG_SERIAL_MSM_CONSOLE
-
-static void msm_console_putchar(struct uart_port *port, int c)
-{
-       while (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
-               ;
-       msm_write(port, c, UART_TF);
-}
-
-static void msm_console_write(struct console *co, const char *s,
-                             unsigned int count)
-{
-       struct uart_port *port;
-       struct msm_port *msm_port;
-
-       BUG_ON(co->index < 0 || co->index >= UART_NR);
-
-       port = get_port_from_line(co->index);
-       msm_port = UART_TO_MSM(port);
-
-       spin_lock(&port->lock);
-       uart_console_write(port, s, count, msm_console_putchar);
-       spin_unlock(&port->lock);
-}
-
-static int __init msm_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port;
-       int baud, flow, bits, parity;
-
-       if (unlikely(co->index >= UART_NR || co->index < 0))
-               return -ENXIO;
-
-       port = get_port_from_line(co->index);
-
-       if (unlikely(!port->membase))
-               return -ENXIO;
-
-       port->cons = co;
-
-       msm_init_clock(port);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       bits = 8;
-       parity = 'n';
-       flow = 'n';
-       msm_write(port, UART_MR2_BITS_PER_CHAR_8 | UART_MR2_STOP_BIT_LEN_ONE,
-                 UART_MR2);    /* 8N1 */
-
-       if (baud < 300 || baud > 115200)
-               baud = 115200;
-       msm_set_baud_rate(port, baud);
-
-       msm_reset(port);
-
-       printk(KERN_INFO "msm_serial: console setup on port #%d\n", port->line);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver msm_uart_driver;
-
-static struct console msm_console = {
-       .name = "ttyMSM",
-       .write = msm_console_write,
-       .device = uart_console_device,
-       .setup = msm_console_setup,
-       .flags = CON_PRINTBUFFER,
-       .index = -1,
-       .data = &msm_uart_driver,
-};
-
-#define MSM_CONSOLE    (&msm_console)
-
-#else
-#define MSM_CONSOLE    NULL
-#endif
-
-static struct uart_driver msm_uart_driver = {
-       .owner = THIS_MODULE,
-       .driver_name = "msm_serial",
-       .dev_name = "ttyMSM",
-       .nr = UART_NR,
-       .cons = MSM_CONSOLE,
-};
-
-static int __init msm_serial_probe(struct platform_device *pdev)
-{
-       struct msm_port *msm_port;
-       struct resource *resource;
-       struct uart_port *port;
-       int irq;
-
-       if (unlikely(pdev->id < 0 || pdev->id >= UART_NR))
-               return -ENXIO;
-
-       printk(KERN_INFO "msm_serial: detected port #%d\n", pdev->id);
-
-       port = get_port_from_line(pdev->id);
-       port->dev = &pdev->dev;
-       msm_port = UART_TO_MSM(port);
-
-       msm_port->clk = clk_get(&pdev->dev, "uart_clk");
-       if (IS_ERR(msm_port->clk))
-               return PTR_ERR(msm_port->clk);
-       port->uartclk = clk_get_rate(msm_port->clk);
-       printk(KERN_INFO "uartclk = %d\n", port->uartclk);
-
-
-       resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (unlikely(!resource))
-               return -ENXIO;
-       port->mapbase = resource->start;
-
-       irq = platform_get_irq(pdev, 0);
-       if (unlikely(irq < 0))
-               return -ENXIO;
-       port->irq = irq;
-
-       platform_set_drvdata(pdev, port);
-
-       return uart_add_one_port(&msm_uart_driver, port);
-}
-
-static int __devexit msm_serial_remove(struct platform_device *pdev)
-{
-       struct msm_port *msm_port = platform_get_drvdata(pdev);
-
-       clk_put(msm_port->clk);
-
-       return 0;
-}
-
-static struct platform_driver msm_platform_driver = {
-       .remove = msm_serial_remove,
-       .driver = {
-               .name = "msm_serial",
-               .owner = THIS_MODULE,
-       },
-};
-
-static int __init msm_serial_init(void)
-{
-       int ret;
-
-       ret = uart_register_driver(&msm_uart_driver);
-       if (unlikely(ret))
-               return ret;
-
-       ret = platform_driver_probe(&msm_platform_driver, msm_serial_probe);
-       if (unlikely(ret))
-               uart_unregister_driver(&msm_uart_driver);
-
-       printk(KERN_INFO "msm_serial: driver initialized\n");
-
-       return ret;
-}
-
-static void __exit msm_serial_exit(void)
-{
-#ifdef CONFIG_SERIAL_MSM_CONSOLE
-       unregister_console(&msm_console);
-#endif
-       platform_driver_unregister(&msm_platform_driver);
-       uart_unregister_driver(&msm_uart_driver);
-}
-
-module_init(msm_serial_init);
-module_exit(msm_serial_exit);
-
-MODULE_AUTHOR("Robert Love <rlove@google.com>");
-MODULE_DESCRIPTION("Driver for msm7x serial device");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/msm_serial.h b/drivers/serial/msm_serial.h
deleted file mode 100644 (file)
index f6ca9ca..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * drivers/serial/msm_serial.h
- *
- * Copyright (C) 2007 Google, Inc.
- * Author: Robert Love <rlove@google.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- */
-
-#ifndef __DRIVERS_SERIAL_MSM_SERIAL_H
-#define __DRIVERS_SERIAL_MSM_SERIAL_H
-
-#define UART_MR1                       0x0000
-
-#define UART_MR1_AUTO_RFR_LEVEL0       0x3F
-#define UART_MR1_AUTO_RFR_LEVEL1       0x3FF00
-#define UART_MR1_RX_RDY_CTL                    (1 << 7)
-#define UART_MR1_CTS_CTL                       (1 << 6)
-
-#define UART_MR2                       0x0004
-#define UART_MR2_ERROR_MODE            (1 << 6)
-#define UART_MR2_BITS_PER_CHAR         0x30
-#define UART_MR2_BITS_PER_CHAR_5       (0x0 << 4)
-#define UART_MR2_BITS_PER_CHAR_6       (0x1 << 4)
-#define UART_MR2_BITS_PER_CHAR_7       (0x2 << 4)
-#define UART_MR2_BITS_PER_CHAR_8       (0x3 << 4)
-#define UART_MR2_STOP_BIT_LEN_ONE      (0x1 << 2)
-#define UART_MR2_STOP_BIT_LEN_TWO      (0x3 << 2)
-#define UART_MR2_PARITY_MODE_NONE      0x0
-#define UART_MR2_PARITY_MODE_ODD       0x1
-#define UART_MR2_PARITY_MODE_EVEN      0x2
-#define UART_MR2_PARITY_MODE_SPACE     0x3
-#define UART_MR2_PARITY_MODE           0x3
-
-#define UART_CSR       0x0008
-#define UART_CSR_115200        0xFF
-#define UART_CSR_57600 0xEE
-#define UART_CSR_38400 0xDD
-#define UART_CSR_28800 0xCC
-#define UART_CSR_19200 0xBB
-#define UART_CSR_14400 0xAA
-#define UART_CSR_9600  0x99
-#define UART_CSR_4800  0x77
-#define UART_CSR_2400  0x55
-#define UART_CSR_1200  0x44
-#define UART_CSR_600   0x33
-#define UART_CSR_300   0x22
-
-#define UART_TF                0x000C
-
-#define UART_CR                                0x0010
-#define UART_CR_CMD_NULL               (0 << 4)
-#define UART_CR_CMD_RESET_RX           (1 << 4)
-#define UART_CR_CMD_RESET_TX           (2 << 4)
-#define UART_CR_CMD_RESET_ERR          (3 << 4)
-#define UART_CR_CMD_RESET_BREAK_INT    (4 << 4)
-#define UART_CR_CMD_START_BREAK                (5 << 4)
-#define UART_CR_CMD_STOP_BREAK         (6 << 4)
-#define UART_CR_CMD_RESET_CTS          (7 << 4)
-#define UART_CR_CMD_PACKET_MODE                (9 << 4)
-#define UART_CR_CMD_MODE_RESET         (12 << 4)
-#define UART_CR_CMD_SET_RFR            (13 << 4)
-#define UART_CR_CMD_RESET_RFR          (14 << 4)
-#define UART_CR_TX_DISABLE             (1 << 3)
-#define UART_CR_TX_ENABLE              (1 << 3)
-#define UART_CR_RX_DISABLE             (1 << 3)
-#define UART_CR_RX_ENABLE              (1 << 3)
-
-#define UART_IMR               0x0014
-#define UART_IMR_TXLEV         (1 << 0)
-#define UART_IMR_RXSTALE       (1 << 3)
-#define UART_IMR_RXLEV         (1 << 4)
-#define UART_IMR_DELTA_CTS     (1 << 5)
-#define UART_IMR_CURRENT_CTS   (1 << 6)
-
-#define UART_IPR_RXSTALE_LAST          0x20
-#define UART_IPR_STALE_LSB             0x1F
-#define UART_IPR_STALE_TIMEOUT_MSB     0x3FF80
-
-#define UART_IPR       0x0018
-#define UART_TFWR      0x001C
-#define UART_RFWR      0x0020
-#define UART_HCR       0x0024
-
-#define UART_MREG              0x0028
-#define UART_NREG              0x002C
-#define UART_DREG              0x0030
-#define UART_MNDREG            0x0034
-#define UART_IRDA              0x0038
-#define UART_MISR_MODE         0x0040
-#define UART_MISR_RESET                0x0044
-#define UART_MISR_EXPORT       0x0048
-#define UART_MISR_VAL          0x004C
-#define UART_TEST_CTRL         0x0050
-
-#define UART_SR                        0x0008
-#define UART_SR_HUNT_CHAR      (1 << 7)
-#define UART_SR_RX_BREAK       (1 << 6)
-#define UART_SR_PAR_FRAME_ERR  (1 << 5)
-#define UART_SR_OVERRUN                (1 << 4)
-#define UART_SR_TX_EMPTY       (1 << 3)
-#define UART_SR_TX_READY       (1 << 2)
-#define UART_SR_RX_FULL                (1 << 1)
-#define UART_SR_RX_READY       (1 << 0)
-
-#define UART_RF                0x000C
-#define UART_MISR      0x0010
-#define UART_ISR       0x0014
-
-#define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port)
-
-static inline
-void msm_write(struct uart_port *port, unsigned int val, unsigned int off)
-{
-       __raw_writel(val, port->membase + off);
-}
-
-static inline
-unsigned int msm_read(struct uart_port *port, unsigned int off)
-{
-       return __raw_readl(port->membase + off);
-}
-
-/*
- * Setup the MND registers to use the TCXO clock.
- */
-static inline void msm_serial_set_mnd_regs_tcxo(struct uart_port *port)
-{
-       msm_write(port, 0x06, UART_MREG);
-       msm_write(port, 0xF1, UART_NREG);
-       msm_write(port, 0x0F, UART_DREG);
-       msm_write(port, 0x1A, UART_MNDREG);
-}
-
-/*
- * Setup the MND registers to use the TCXO clock divided by 4.
- */
-static inline void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port)
-{
-       msm_write(port, 0x18, UART_MREG);
-       msm_write(port, 0xF6, UART_NREG);
-       msm_write(port, 0x0F, UART_DREG);
-       msm_write(port, 0x0A, UART_MNDREG);
-}
-
-static inline
-void msm_serial_set_mnd_regs_from_uartclk(struct uart_port *port)
-{
-       if (port->uartclk == 19200000)
-               msm_serial_set_mnd_regs_tcxo(port);
-       else
-               msm_serial_set_mnd_regs_tcxoby4(port);
-}
-
-/*
- * TROUT has a specific defect that makes it report it's uartclk
- * as 19.2Mhz (TCXO) when it's actually 4.8Mhz (TCXO/4). This special
- * cases TROUT to use the right clock.
- */
-#ifdef CONFIG_MACH_TROUT
-#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_tcxoby4
-#else
-#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_from_uartclk
-#endif
-
-#endif /* __DRIVERS_SERIAL_MSM_SERIAL_H */
diff --git a/drivers/serial/mux.c b/drivers/serial/mux.c
deleted file mode 100644 (file)
index 9711e06..0000000
+++ /dev/null
@@ -1,633 +0,0 @@
-/*
-** mux.c:
-**     serial driver for the Mux console found in some PA-RISC servers.
-**
-**     (c) Copyright 2002 Ryan Bradetich
-**     (c) Copyright 2002 Hewlett-Packard Company
-**
-** 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 Driver currently only supports the console (port 0) on the MUX.
-** Additional work will be needed on this driver to enable the full
-** functionality of the MUX.
-**
-*/
-
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/serial.h>
-#include <linux/console.h>
-#include <linux/delay.h> /* for udelay */
-#include <linux/device.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/parisc-device.h>
-
-#ifdef CONFIG_MAGIC_SYSRQ
-#include <linux/sysrq.h>
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
-#define MUX_OFFSET 0x800
-#define MUX_LINE_OFFSET 0x80
-
-#define MUX_FIFO_SIZE 255
-#define MUX_POLL_DELAY (30 * HZ / 1000)
-
-#define IO_DATA_REG_OFFSET 0x3c
-#define IO_DCOUNT_REG_OFFSET 0x40
-
-#define MUX_EOFIFO(status) ((status & 0xF000) == 0xF000)
-#define MUX_STATUS(status) ((status & 0xF000) == 0x8000)
-#define MUX_BREAK(status) ((status & 0xF000) == 0x2000)
-
-#define MUX_NR 256
-static unsigned int port_cnt __read_mostly;
-struct mux_port {
-       struct uart_port port;
-       int enabled;
-};
-static struct mux_port mux_ports[MUX_NR];
-
-static struct uart_driver mux_driver = {
-       .owner = THIS_MODULE,
-       .driver_name = "ttyB",
-       .dev_name = "ttyB",
-       .major = MUX_MAJOR,
-       .minor = 0,
-       .nr = MUX_NR,
-};
-
-static struct timer_list mux_timer;
-
-#define UART_PUT_CHAR(p, c) __raw_writel((c), (p)->membase + IO_DATA_REG_OFFSET)
-#define UART_GET_FIFO_CNT(p) __raw_readl((p)->membase + IO_DCOUNT_REG_OFFSET)
-
-/**
- * get_mux_port_count - Get the number of available ports on the Mux.
- * @dev: The parisc device.
- *
- * This function is used to determine the number of ports the Mux
- * supports.  The IODC data reports the number of ports the Mux
- * can support, but there are cases where not all the Mux ports
- * are connected.  This function can override the IODC and
- * return the true port count.
- */
-static int __init get_mux_port_count(struct parisc_device *dev)
-{
-       int status;
-       u8 iodc_data[32];
-       unsigned long bytecnt;
-
-       /* If this is the built-in Mux for the K-Class (Eole CAP/MUX),
-        * we only need to allocate resources for 1 port since the
-        * other 7 ports are not connected.
-        */
-       if(dev->id.hversion == 0x15)
-               return 1;
-
-       status = pdc_iodc_read(&bytecnt, dev->hpa.start, 0, iodc_data, 32);
-       BUG_ON(status != PDC_OK);
-
-       /* Return the number of ports specified in the iodc data. */
-       return ((((iodc_data)[4] & 0xf0) >> 4) * 8) + 8;
-}
-
-/**
- * mux_tx_empty - Check if the transmitter fifo is empty.
- * @port: Ptr to the uart_port.
- *
- * This function test if the transmitter fifo for the port
- * described by 'port' is empty.  If it is empty, this function
- * should return TIOCSER_TEMT, otherwise return 0.
- */
-static unsigned int mux_tx_empty(struct uart_port *port)
-{
-       return UART_GET_FIFO_CNT(port) ? 0 : TIOCSER_TEMT;
-} 
-
-/**
- * mux_set_mctrl - Set the current state of the modem control inputs.
- * @ports: Ptr to the uart_port.
- * @mctrl: Modem control bits.
- *
- * The Serial MUX does not support CTS, DCD or DSR so this function
- * is ignored.
- */
-static void mux_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-}
-
-/**
- * mux_get_mctrl - Returns the current state of modem control inputs.
- * @port: Ptr to the uart_port.
- *
- * The Serial MUX does not support CTS, DCD or DSR so these lines are
- * treated as permanently active.
- */
-static unsigned int mux_get_mctrl(struct uart_port *port)
-{ 
-       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
-}
-
-/**
- * mux_stop_tx - Stop transmitting characters.
- * @port: Ptr to the uart_port.
- *
- * The Serial MUX does not support this function.
- */
-static void mux_stop_tx(struct uart_port *port)
-{
-}
-
-/**
- * mux_start_tx - Start transmitting characters.
- * @port: Ptr to the uart_port.
- *
- * The Serial Mux does not support this function.
- */
-static void mux_start_tx(struct uart_port *port)
-{
-}
-
-/**
- * mux_stop_rx - Stop receiving characters.
- * @port: Ptr to the uart_port.
- *
- * The Serial Mux does not support this function.
- */
-static void mux_stop_rx(struct uart_port *port)
-{
-}
-
-/**
- * mux_enable_ms - Enable modum status interrupts.
- * @port: Ptr to the uart_port.
- *
- * The Serial Mux does not support this function.
- */
-static void mux_enable_ms(struct uart_port *port)
-{
-}
-
-/**
- * mux_break_ctl - Control the transmitssion of a break signal.
- * @port: Ptr to the uart_port.
- * @break_state: Raise/Lower the break signal.
- *
- * The Serial Mux does not support this function.
- */
-static void mux_break_ctl(struct uart_port *port, int break_state)
-{
-}
-
-/**
- * mux_write - Write chars to the mux fifo.
- * @port: Ptr to the uart_port.
- *
- * This function writes all the data from the uart buffer to
- * the mux fifo.
- */
-static void mux_write(struct uart_port *port)
-{
-       int count;
-       struct circ_buf *xmit = &port->state->xmit;
-
-       if(port->x_char) {
-               UART_PUT_CHAR(port, port->x_char);
-               port->icount.tx++;
-               port->x_char = 0;
-               return;
-       }
-
-       if(uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               mux_stop_tx(port);
-               return;
-       }
-
-       count = (port->fifosize) - UART_GET_FIFO_CNT(port);
-       do {
-               UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-               if(uart_circ_empty(xmit))
-                       break;
-
-       } while(--count > 0);
-
-       while(UART_GET_FIFO_CNT(port)) 
-               udelay(1);
-
-       if(uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (uart_circ_empty(xmit))
-               mux_stop_tx(port);
-}
-
-/**
- * mux_read - Read chars from the mux fifo.
- * @port: Ptr to the uart_port.
- *
- * This reads all available data from the mux's fifo and pushes
- * the data to the tty layer.
- */
-static void mux_read(struct uart_port *port)
-{
-       int data;
-       struct tty_struct *tty = port->state->port.tty;
-       __u32 start_count = port->icount.rx;
-
-       while(1) {
-               data = __raw_readl(port->membase + IO_DATA_REG_OFFSET);
-
-               if (MUX_STATUS(data))
-                       continue;
-
-               if (MUX_EOFIFO(data))
-                       break;
-
-               port->icount.rx++;
-
-               if (MUX_BREAK(data)) {
-                       port->icount.brk++;
-                       if(uart_handle_break(port))
-                               continue;
-               }
-
-               if (uart_handle_sysrq_char(port, data & 0xffu))
-                       continue;
-
-               tty_insert_flip_char(tty, data & 0xFF, TTY_NORMAL);
-       }
-       
-       if (start_count != port->icount.rx) {
-               tty_flip_buffer_push(tty);
-       }
-}
-
-/**
- * mux_startup - Initialize the port.
- * @port: Ptr to the uart_port.
- *
- * Grab any resources needed for this port and start the
- * mux timer.
- */
-static int mux_startup(struct uart_port *port)
-{
-       mux_ports[port->line].enabled = 1;
-       return 0;
-}
-
-/**
- * mux_shutdown - Disable the port.
- * @port: Ptr to the uart_port.
- *
- * Release any resources needed for the port.
- */
-static void mux_shutdown(struct uart_port *port)
-{
-       mux_ports[port->line].enabled = 0;
-}
-
-/**
- * mux_set_termios - Chane port parameters.
- * @port: Ptr to the uart_port.
- * @termios: new termios settings.
- * @old: old termios settings.
- *
- * The Serial Mux does not support this function.
- */
-static void
-mux_set_termios(struct uart_port *port, struct ktermios *termios,
-               struct ktermios *old)
-{
-}
-
-/**
- * mux_type - Describe the port.
- * @port: Ptr to the uart_port.
- *
- * Return a pointer to a string constant describing the
- * specified port.
- */
-static const char *mux_type(struct uart_port *port)
-{
-       return "Mux";
-}
-
-/**
- * mux_release_port - Release memory and IO regions.
- * @port: Ptr to the uart_port.
- * 
- * Release any memory and IO region resources currently in use by
- * the port.
- */
-static void mux_release_port(struct uart_port *port)
-{
-}
-
-/**
- * mux_request_port - Request memory and IO regions.
- * @port: Ptr to the uart_port.
- *
- * Request any memory and IO region resources required by the port.
- * If any fail, no resources should be registered when this function
- * returns, and it should return -EBUSY on failure.
- */
-static int mux_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-/**
- * mux_config_port - Perform port autoconfiguration.
- * @port: Ptr to the uart_port.
- * @type: Bitmask of required configurations.
- *
- * Perform any autoconfiguration steps for the port.  This function is
- * called if the UPF_BOOT_AUTOCONF flag is specified for the port.
- * [Note: This is required for now because of a bug in the Serial core.
- *  rmk has already submitted a patch to linus, should be available for
- *  2.5.47.]
- */
-static void mux_config_port(struct uart_port *port, int type)
-{
-       port->type = PORT_MUX;
-}
-
-/**
- * mux_verify_port - Verify the port information.
- * @port: Ptr to the uart_port.
- * @ser: Ptr to the serial information.
- *
- * Verify the new serial port information contained within serinfo is
- * suitable for this port type.
- */
-static int mux_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       if(port->membase == NULL)
-               return -EINVAL;
-
-       return 0;
-}
-
-/**
- * mux_drv_poll - Mux poll function.
- * @unused: Unused variable
- *
- * This function periodically polls the Serial MUX to check for new data.
- */
-static void mux_poll(unsigned long unused)
-{  
-       int i;
-
-       for(i = 0; i < port_cnt; ++i) {
-               if(!mux_ports[i].enabled)
-                       continue;
-
-               mux_read(&mux_ports[i].port);
-               mux_write(&mux_ports[i].port);
-       }
-
-       mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY);
-}
-
-
-#ifdef CONFIG_SERIAL_MUX_CONSOLE
-static void mux_console_write(struct console *co, const char *s, unsigned count)
-{
-       /* Wait until the FIFO drains. */
-       while(UART_GET_FIFO_CNT(&mux_ports[0].port))
-               udelay(1);
-
-       while(count--) {
-               if(*s == '\n') {
-                       UART_PUT_CHAR(&mux_ports[0].port, '\r');
-               }
-               UART_PUT_CHAR(&mux_ports[0].port, *s++);
-       }
-
-}
-
-static int mux_console_setup(struct console *co, char *options)
-{
-        return 0;
-}
-
-struct tty_driver *mux_console_device(struct console *co, int *index)
-{
-        *index = co->index;
-       return mux_driver.tty_driver;
-}
-
-static struct console mux_console = {
-       .name =         "ttyB",
-       .write =        mux_console_write,
-       .device =       mux_console_device,
-       .setup =        mux_console_setup,
-       .flags =        CON_ENABLED | CON_PRINTBUFFER,
-       .index =        0,
-};
-
-#define MUX_CONSOLE    &mux_console
-#else
-#define MUX_CONSOLE    NULL
-#endif
-
-static struct uart_ops mux_pops = {
-       .tx_empty =             mux_tx_empty,
-       .set_mctrl =            mux_set_mctrl,
-       .get_mctrl =            mux_get_mctrl,
-       .stop_tx =              mux_stop_tx,
-       .start_tx =             mux_start_tx,
-       .stop_rx =              mux_stop_rx,
-       .enable_ms =            mux_enable_ms,
-       .break_ctl =            mux_break_ctl,
-       .startup =              mux_startup,
-       .shutdown =             mux_shutdown,
-       .set_termios =          mux_set_termios,
-       .type =                 mux_type,
-       .release_port =         mux_release_port,
-       .request_port =         mux_request_port,
-       .config_port =          mux_config_port,
-       .verify_port =          mux_verify_port,
-};
-
-/**
- * mux_probe - Determine if the Serial Mux should claim this device.
- * @dev: The parisc device.
- *
- * Deterimine if the Serial Mux should claim this chip (return 0)
- * or not (return 1).
- */
-static int __init mux_probe(struct parisc_device *dev)
-{
-       int i, status;
-
-       int port_count = get_mux_port_count(dev);
-       printk(KERN_INFO "Serial mux driver (%d ports) Revision: 0.6\n", port_count);
-
-       dev_set_drvdata(&dev->dev, (void *)(long)port_count);
-       request_mem_region(dev->hpa.start + MUX_OFFSET,
-                           port_count * MUX_LINE_OFFSET, "Mux");
-
-       if(!port_cnt) {
-               mux_driver.cons = MUX_CONSOLE;
-
-               status = uart_register_driver(&mux_driver);
-               if(status) {
-                       printk(KERN_ERR "Serial mux: Unable to register driver.\n");
-                       return 1;
-               }
-       }
-
-       for(i = 0; i < port_count; ++i, ++port_cnt) {
-               struct uart_port *port = &mux_ports[port_cnt].port;
-               port->iobase    = 0;
-               port->mapbase   = dev->hpa.start + MUX_OFFSET +
-                                               (i * MUX_LINE_OFFSET);
-               port->membase   = ioremap_nocache(port->mapbase, MUX_LINE_OFFSET);
-               port->iotype    = UPIO_MEM;
-               port->type      = PORT_MUX;
-               port->irq       = NO_IRQ;
-               port->uartclk   = 0;
-               port->fifosize  = MUX_FIFO_SIZE;
-               port->ops       = &mux_pops;
-               port->flags     = UPF_BOOT_AUTOCONF;
-               port->line      = port_cnt;
-
-               /* The port->timeout needs to match what is present in
-                * uart_wait_until_sent in serial_core.c.  Otherwise
-                * the time spent in msleep_interruptable will be very
-                * long, causing the appearance of a console hang.
-                */
-               port->timeout   = HZ / 50;
-               spin_lock_init(&port->lock);
-
-               status = uart_add_one_port(&mux_driver, port);
-               BUG_ON(status);
-       }
-
-       return 0;
-}
-
-static int __devexit mux_remove(struct parisc_device *dev)
-{
-       int i, j;
-       int port_count = (long)dev_get_drvdata(&dev->dev);
-
-       /* Find Port 0 for this card in the mux_ports list. */
-       for(i = 0; i < port_cnt; ++i) {
-               if(mux_ports[i].port.mapbase == dev->hpa.start + MUX_OFFSET)
-                       break;
-       }
-       BUG_ON(i + port_count > port_cnt);
-
-       /* Release the resources associated with each port on the device. */
-       for(j = 0; j < port_count; ++j, ++i) {
-               struct uart_port *port = &mux_ports[i].port;
-
-               uart_remove_one_port(&mux_driver, port);
-               if(port->membase)
-                       iounmap(port->membase);
-       }
-
-       release_mem_region(dev->hpa.start + MUX_OFFSET, port_count * MUX_LINE_OFFSET);
-       return 0;
-}
-
-/* Hack.  This idea was taken from the 8250_gsc.c on how to properly order
- * the serial port detection in the proper order.   The idea is we always
- * want the builtin mux to be detected before addin mux cards, so we
- * specifically probe for the builtin mux cards first.
- *
- * This table only contains the parisc_device_id of known builtin mux
- * devices.  All other mux cards will be detected by the generic mux_tbl.
- */
-static struct parisc_device_id builtin_mux_tbl[] = {
-       { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, 0x15, 0x0000D }, /* All K-class */
-       { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, 0x44, 0x0000D }, /* E35, E45, and E55 */
-       { 0, }
-};
-
-static struct parisc_device_id mux_tbl[] = {
-       { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0000D },
-       { 0, }
-};
-
-MODULE_DEVICE_TABLE(parisc, builtin_mux_tbl);
-MODULE_DEVICE_TABLE(parisc, mux_tbl);
-
-static struct parisc_driver builtin_serial_mux_driver = {
-       .name =         "builtin_serial_mux",
-       .id_table =     builtin_mux_tbl,
-       .probe =        mux_probe,
-       .remove =       __devexit_p(mux_remove),
-};
-
-static struct parisc_driver serial_mux_driver = {
-       .name =         "serial_mux",
-       .id_table =     mux_tbl,
-       .probe =        mux_probe,
-       .remove =       __devexit_p(mux_remove),
-};
-
-/**
- * mux_init - Serial MUX initialization procedure.
- *
- * Register the Serial MUX driver.
- */
-static int __init mux_init(void)
-{
-       register_parisc_driver(&builtin_serial_mux_driver);
-       register_parisc_driver(&serial_mux_driver);
-
-       if(port_cnt > 0) {
-               /* Start the Mux timer */
-               init_timer(&mux_timer);
-               mux_timer.function = mux_poll;
-               mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY);
-
-#ifdef CONFIG_SERIAL_MUX_CONSOLE
-               register_console(&mux_console);
-#endif
-       }
-
-       return 0;
-}
-
-/**
- * mux_exit - Serial MUX cleanup procedure.
- *
- * Unregister the Serial MUX driver from the tty layer.
- */
-static void __exit mux_exit(void)
-{
-       /* Delete the Mux timer. */
-       if(port_cnt > 0) {
-               del_timer(&mux_timer);
-#ifdef CONFIG_SERIAL_MUX_CONSOLE
-               unregister_console(&mux_console);
-#endif
-       }
-
-       unregister_parisc_driver(&builtin_serial_mux_driver);
-       unregister_parisc_driver(&serial_mux_driver);
-       uart_unregister_driver(&mux_driver);
-}
-
-module_init(mux_init);
-module_exit(mux_exit);
-
-MODULE_AUTHOR("Ryan Bradetich");
-MODULE_DESCRIPTION("Serial MUX driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV_MAJOR(MUX_MAJOR);
diff --git a/drivers/serial/netx-serial.c b/drivers/serial/netx-serial.c
deleted file mode 100644 (file)
index 7735c9f..0000000
+++ /dev/null
@@ -1,750 +0,0 @@
-/*
- * drivers/serial/netx-serial.c
- *
- * Copyright (c) 2005 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * 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
- */
-
-#if defined(CONFIG_SERIAL_NETX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/platform_device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <mach/hardware.h>
-#include <mach/netx-regs.h>
-
-/* We've been assigned a range on the "Low-density serial ports" major */
-#define SERIAL_NX_MAJOR        204
-#define MINOR_START    170
-
-enum uart_regs {
-       UART_DR              = 0x00,
-       UART_SR              = 0x04,
-       UART_LINE_CR         = 0x08,
-       UART_BAUDDIV_MSB     = 0x0c,
-       UART_BAUDDIV_LSB     = 0x10,
-       UART_CR              = 0x14,
-       UART_FR              = 0x18,
-       UART_IIR             = 0x1c,
-       UART_ILPR            = 0x20,
-       UART_RTS_CR          = 0x24,
-       UART_RTS_LEAD        = 0x28,
-       UART_RTS_TRAIL       = 0x2c,
-       UART_DRV_ENABLE      = 0x30,
-       UART_BRM_CR          = 0x34,
-       UART_RXFIFO_IRQLEVEL = 0x38,
-       UART_TXFIFO_IRQLEVEL = 0x3c,
-};
-
-#define SR_FE (1<<0)
-#define SR_PE (1<<1)
-#define SR_BE (1<<2)
-#define SR_OE (1<<3)
-
-#define LINE_CR_BRK       (1<<0)
-#define LINE_CR_PEN       (1<<1)
-#define LINE_CR_EPS       (1<<2)
-#define LINE_CR_STP2      (1<<3)
-#define LINE_CR_FEN       (1<<4)
-#define LINE_CR_5BIT      (0<<5)
-#define LINE_CR_6BIT      (1<<5)
-#define LINE_CR_7BIT      (2<<5)
-#define LINE_CR_8BIT      (3<<5)
-#define LINE_CR_BITS_MASK (3<<5)
-
-#define CR_UART_EN (1<<0)
-#define CR_SIREN   (1<<1)
-#define CR_SIRLP   (1<<2)
-#define CR_MSIE    (1<<3)
-#define CR_RIE     (1<<4)
-#define CR_TIE     (1<<5)
-#define CR_RTIE    (1<<6)
-#define CR_LBE     (1<<7)
-
-#define FR_CTS  (1<<0)
-#define FR_DSR  (1<<1)
-#define FR_DCD  (1<<2)
-#define FR_BUSY (1<<3)
-#define FR_RXFE (1<<4)
-#define FR_TXFF (1<<5)
-#define FR_RXFF (1<<6)
-#define FR_TXFE (1<<7)
-
-#define IIR_MIS (1<<0)
-#define IIR_RIS (1<<1)
-#define IIR_TIS (1<<2)
-#define IIR_RTIS (1<<3)
-#define IIR_MASK 0xf
-
-#define RTS_CR_AUTO (1<<0)
-#define RTS_CR_RTS  (1<<1)
-#define RTS_CR_COUNT (1<<2)
-#define RTS_CR_MOD2  (1<<3)
-#define RTS_CR_RTS_POL (1<<4)
-#define RTS_CR_CTS_CTR (1<<5)
-#define RTS_CR_CTS_POL (1<<6)
-#define RTS_CR_STICK   (1<<7)
-
-#define UART_PORT_SIZE 0x40
-#define DRIVER_NAME "netx-uart"
-
-struct netx_port {
-       struct uart_port        port;
-};
-
-static void netx_stop_tx(struct uart_port *port)
-{
-       unsigned int val;
-       val = readl(port->membase + UART_CR);
-       writel(val & ~CR_TIE,  port->membase + UART_CR);
-}
-
-static void netx_stop_rx(struct uart_port *port)
-{
-       unsigned int val;
-       val = readl(port->membase + UART_CR);
-       writel(val & ~CR_RIE,  port->membase + UART_CR);
-}
-
-static void netx_enable_ms(struct uart_port *port)
-{
-       unsigned int val;
-       val = readl(port->membase + UART_CR);
-       writel(val | CR_MSIE, port->membase + UART_CR);
-}
-
-static inline void netx_transmit_buffer(struct uart_port *port)
-{
-       struct circ_buf *xmit = &port->state->xmit;
-
-       if (port->x_char) {
-               writel(port->x_char, port->membase + UART_DR);
-               port->icount.tx++;
-               port->x_char = 0;
-               return;
-       }
-
-       if (uart_tx_stopped(port) || uart_circ_empty(xmit)) {
-               netx_stop_tx(port);
-               return;
-       }
-
-       do {
-               /* send xmit->buf[xmit->tail]
-                * out the port here */
-               writel(xmit->buf[xmit->tail], port->membase + UART_DR);
-               xmit->tail = (xmit->tail + 1) &
-                        (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (!(readl(port->membase + UART_FR) & FR_TXFF));
-
-       if (uart_circ_empty(xmit))
-               netx_stop_tx(port);
-}
-
-static void netx_start_tx(struct uart_port *port)
-{
-       writel(
-           readl(port->membase + UART_CR) | CR_TIE, port->membase + UART_CR);
-
-       if (!(readl(port->membase + UART_FR) & FR_TXFF))
-               netx_transmit_buffer(port);
-}
-
-static unsigned int netx_tx_empty(struct uart_port *port)
-{
-       return readl(port->membase + UART_FR) & FR_BUSY ? 0 : TIOCSER_TEMT;
-}
-
-static void netx_txint(struct uart_port *port)
-{
-       struct circ_buf *xmit = &port->state->xmit;
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               netx_stop_tx(port);
-               return;
-       }
-
-       netx_transmit_buffer(port);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-}
-
-static void netx_rxint(struct uart_port *port)
-{
-       unsigned char rx, flg, status;
-       struct tty_struct *tty = port->state->port.tty;
-
-       while (!(readl(port->membase + UART_FR) & FR_RXFE)) {
-               rx = readl(port->membase + UART_DR);
-               flg = TTY_NORMAL;
-               port->icount.rx++;
-               status = readl(port->membase + UART_SR);
-               if (status & SR_BE) {
-                       writel(0, port->membase + UART_SR);
-                       if (uart_handle_break(port))
-                               continue;
-               }
-
-               if (unlikely(status & (SR_FE | SR_PE | SR_OE))) {
-
-                       if (status & SR_PE)
-                               port->icount.parity++;
-                       else if (status & SR_FE)
-                               port->icount.frame++;
-                       if (status & SR_OE)
-                               port->icount.overrun++;
-
-                       status &= port->read_status_mask;
-
-                       if (status & SR_BE)
-                               flg = TTY_BREAK;
-                       else if (status & SR_PE)
-                               flg = TTY_PARITY;
-                       else if (status & SR_FE)
-                               flg = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(port, rx))
-                       continue;
-
-               uart_insert_char(port, status, SR_OE, rx, flg);
-       }
-
-       tty_flip_buffer_push(tty);
-       return;
-}
-
-static irqreturn_t netx_int(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       unsigned long flags;
-       unsigned char status;
-
-       spin_lock_irqsave(&port->lock,flags);
-
-       status = readl(port->membase + UART_IIR) & IIR_MASK;
-       while (status) {
-               if (status & IIR_RIS)
-                       netx_rxint(port);
-               if (status & IIR_TIS)
-                       netx_txint(port);
-               if (status & IIR_MIS) {
-                       if (readl(port->membase + UART_FR) & FR_CTS)
-                               uart_handle_cts_change(port, 1);
-                       else
-                               uart_handle_cts_change(port, 0);
-               }
-               writel(0, port->membase + UART_IIR);
-               status = readl(port->membase + UART_IIR) & IIR_MASK;
-       }
-
-       spin_unlock_irqrestore(&port->lock,flags);
-       return IRQ_HANDLED;
-}
-
-static unsigned int netx_get_mctrl(struct uart_port *port)
-{
-       unsigned int ret = TIOCM_DSR | TIOCM_CAR;
-
-       if (readl(port->membase + UART_FR) & FR_CTS)
-               ret |= TIOCM_CTS;
-
-       return ret;
-}
-
-static void netx_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       unsigned int val;
-
-       /* FIXME: Locking needed ? */
-       if (mctrl & TIOCM_RTS) {
-               val = readl(port->membase + UART_RTS_CR);
-               writel(val | RTS_CR_RTS, port->membase + UART_RTS_CR);
-       }
-}
-
-static void netx_break_ctl(struct uart_port *port, int break_state)
-{
-       unsigned int line_cr;
-       spin_lock_irq(&port->lock);
-
-       line_cr = readl(port->membase + UART_LINE_CR);
-       if (break_state != 0)
-               line_cr |= LINE_CR_BRK;
-       else
-               line_cr &= ~LINE_CR_BRK;
-       writel(line_cr, port->membase + UART_LINE_CR);
-
-       spin_unlock_irq(&port->lock);
-}
-
-static int netx_startup(struct uart_port *port)
-{
-       int ret;
-
-       ret = request_irq(port->irq, netx_int, 0,
-                            DRIVER_NAME, port);
-       if (ret) {
-               dev_err(port->dev, "unable to grab irq%d\n",port->irq);
-               goto exit;
-       }
-
-       writel(readl(port->membase + UART_LINE_CR) | LINE_CR_FEN,
-               port->membase + UART_LINE_CR);
-
-       writel(CR_MSIE | CR_RIE | CR_TIE | CR_RTIE | CR_UART_EN,
-               port->membase + UART_CR);
-
-exit:
-       return ret;
-}
-
-static void netx_shutdown(struct uart_port *port)
-{
-       writel(0, port->membase + UART_CR) ;
-
-       free_irq(port->irq, port);
-}
-
-static void
-netx_set_termios(struct uart_port *port, struct ktermios *termios,
-                  struct ktermios *old)
-{
-       unsigned int baud, quot;
-       unsigned char old_cr;
-       unsigned char line_cr = LINE_CR_FEN;
-       unsigned char rts_cr = 0;
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               line_cr |= LINE_CR_5BIT;
-               break;
-       case CS6:
-               line_cr |= LINE_CR_6BIT;
-               break;
-       case CS7:
-               line_cr |= LINE_CR_7BIT;
-               break;
-       case CS8:
-               line_cr |= LINE_CR_8BIT;
-               break;
-       }
-
-       if (termios->c_cflag & CSTOPB)
-               line_cr |= LINE_CR_STP2;
-
-       if (termios->c_cflag & PARENB) {
-               line_cr |= LINE_CR_PEN;
-               if (!(termios->c_cflag & PARODD))
-                       line_cr |= LINE_CR_EPS;
-       }
-
-       if (termios->c_cflag & CRTSCTS)
-               rts_cr = RTS_CR_AUTO | RTS_CR_CTS_CTR | RTS_CR_RTS_POL;
-
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
-       quot = baud * 4096;
-       quot /= 1000;
-       quot *= 256;
-       quot /= 100000;
-
-       spin_lock_irq(&port->lock);
-
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       old_cr = readl(port->membase + UART_CR);
-
-       /* disable interrupts */
-       writel(old_cr & ~(CR_MSIE | CR_RIE | CR_TIE | CR_RTIE),
-               port->membase + UART_CR);
-
-       /* drain transmitter */
-       while (readl(port->membase + UART_FR) & FR_BUSY);
-
-       /* disable UART */
-       writel(old_cr & ~CR_UART_EN, port->membase + UART_CR);
-
-       /* modem status interrupts */
-       old_cr &= ~CR_MSIE;
-       if (UART_ENABLE_MS(port, termios->c_cflag))
-               old_cr |= CR_MSIE;
-
-       writel((quot>>8) & 0xff, port->membase + UART_BAUDDIV_MSB);
-       writel(quot & 0xff, port->membase + UART_BAUDDIV_LSB);
-       writel(line_cr, port->membase + UART_LINE_CR);
-
-       writel(rts_cr, port->membase + UART_RTS_CR);
-
-       /*
-        * Characters to ignore
-        */
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= SR_PE;
-       if (termios->c_iflag & IGNBRK) {
-               port->ignore_status_mask |= SR_BE;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       port->ignore_status_mask |= SR_PE;
-       }
-
-       port->read_status_mask = 0;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               port->read_status_mask |= SR_BE;
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= SR_PE | SR_FE;
-
-       writel(old_cr, port->membase + UART_CR);
-
-       spin_unlock_irq(&port->lock);
-}
-
-static const char *netx_type(struct uart_port *port)
-{
-       return port->type == PORT_NETX ? "NETX" : NULL;
-}
-
-static void netx_release_port(struct uart_port *port)
-{
-       release_mem_region(port->mapbase, UART_PORT_SIZE);
-}
-
-static int netx_request_port(struct uart_port *port)
-{
-       return request_mem_region(port->mapbase, UART_PORT_SIZE,
-                       DRIVER_NAME) != NULL ? 0 : -EBUSY;
-}
-
-static void netx_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE && netx_request_port(port) == 0)
-               port->type = PORT_NETX;
-}
-
-static int
-netx_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       int ret = 0;
-
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_NETX)
-               ret = -EINVAL;
-
-       return ret;
-}
-
-static struct uart_ops netx_pops = {
-       .tx_empty       = netx_tx_empty,
-       .set_mctrl      = netx_set_mctrl,
-       .get_mctrl      = netx_get_mctrl,
-       .stop_tx        = netx_stop_tx,
-       .start_tx       = netx_start_tx,
-       .stop_rx        = netx_stop_rx,
-       .enable_ms      = netx_enable_ms,
-       .break_ctl      = netx_break_ctl,
-       .startup        = netx_startup,
-       .shutdown       = netx_shutdown,
-       .set_termios    = netx_set_termios,
-       .type           = netx_type,
-       .release_port   = netx_release_port,
-       .request_port   = netx_request_port,
-       .config_port    = netx_config_port,
-       .verify_port    = netx_verify_port,
-};
-
-static struct netx_port netx_ports[] = {
-       {
-       .port = {
-               .type = PORT_NETX,
-               .iotype = UPIO_MEM,
-               .membase = (char __iomem *)io_p2v(NETX_PA_UART0),
-               .mapbase = NETX_PA_UART0,
-               .irq = NETX_IRQ_UART0,
-               .uartclk = 100000000,
-               .fifosize = 16,
-               .flags = UPF_BOOT_AUTOCONF,
-               .ops = &netx_pops,
-               .line = 0,
-       },
-       }, {
-       .port = {
-               .type = PORT_NETX,
-               .iotype = UPIO_MEM,
-               .membase = (char __iomem *)io_p2v(NETX_PA_UART1),
-               .mapbase = NETX_PA_UART1,
-               .irq = NETX_IRQ_UART1,
-               .uartclk = 100000000,
-               .fifosize = 16,
-               .flags = UPF_BOOT_AUTOCONF,
-               .ops = &netx_pops,
-               .line = 1,
-       },
-       }, {
-       .port = {
-               .type = PORT_NETX,
-               .iotype = UPIO_MEM,
-               .membase = (char __iomem *)io_p2v(NETX_PA_UART2),
-               .mapbase = NETX_PA_UART2,
-               .irq = NETX_IRQ_UART2,
-               .uartclk = 100000000,
-               .fifosize = 16,
-               .flags = UPF_BOOT_AUTOCONF,
-               .ops = &netx_pops,
-               .line = 2,
-       },
-       }
-};
-
-#ifdef CONFIG_SERIAL_NETX_CONSOLE
-
-static void netx_console_putchar(struct uart_port *port, int ch)
-{
-       while (readl(port->membase + UART_FR) & FR_BUSY);
-       writel(ch, port->membase + UART_DR);
-}
-
-static void
-netx_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct uart_port *port = &netx_ports[co->index].port;
-       unsigned char cr_save;
-
-       cr_save = readl(port->membase + UART_CR);
-       writel(cr_save | CR_UART_EN, port->membase + UART_CR);
-
-       uart_console_write(port, s, count, netx_console_putchar);
-
-       while (readl(port->membase + UART_FR) & FR_BUSY);
-       writel(cr_save, port->membase + UART_CR);
-}
-
-static void __init
-netx_console_get_options(struct uart_port *port, int *baud,
-                       int *parity, int *bits, int *flow)
-{
-       unsigned char line_cr;
-
-       *baud = (readl(port->membase + UART_BAUDDIV_MSB) << 8) |
-               readl(port->membase + UART_BAUDDIV_LSB);
-       *baud *= 1000;
-       *baud /= 4096;
-       *baud *= 1000;
-       *baud /= 256;
-       *baud *= 100;
-
-       line_cr = readl(port->membase + UART_LINE_CR);
-       *parity = 'n';
-       if (line_cr & LINE_CR_PEN) {
-               if (line_cr & LINE_CR_EPS)
-                       *parity = 'e';
-               else
-                       *parity = 'o';
-       }
-
-       switch (line_cr & LINE_CR_BITS_MASK) {
-       case LINE_CR_8BIT:
-               *bits = 8;
-               break;
-       case LINE_CR_7BIT:
-               *bits = 7;
-               break;
-       case LINE_CR_6BIT:
-               *bits = 6;
-               break;
-       case LINE_CR_5BIT:
-               *bits = 5;
-               break;
-       }
-
-       if (readl(port->membase + UART_RTS_CR) & RTS_CR_AUTO)
-               *flow = 'r';
-}
-
-static int __init
-netx_console_setup(struct console *co, char *options)
-{
-       struct netx_port *sport;
-       int baud = 9600;
-       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.
-        */
-       if (co->index == -1 || co->index >= ARRAY_SIZE(netx_ports))
-               co->index = 0;
-       sport = &netx_ports[co->index];
-
-       if (options) {
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       } else {
-               /* if the UART is enabled, assume it has been correctly setup
-                * by the bootloader and get the options
-                */
-               if (readl(sport->port.membase + UART_CR) & CR_UART_EN) {
-                       netx_console_get_options(&sport->port, &baud,
-                       &parity, &bits, &flow);
-               }
-
-       }
-
-       return uart_set_options(&sport->port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver netx_reg;
-static struct console netx_console = {
-       .name           = "ttyNX",
-       .write          = netx_console_write,
-       .device         = uart_console_device,
-       .setup          = netx_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &netx_reg,
-};
-
-static int __init netx_console_init(void)
-{
-       register_console(&netx_console);
-       return 0;
-}
-console_initcall(netx_console_init);
-
-#define NETX_CONSOLE   &netx_console
-#else
-#define NETX_CONSOLE   NULL
-#endif
-
-static struct uart_driver netx_reg = {
-       .owner          = THIS_MODULE,
-       .driver_name    = DRIVER_NAME,
-       .dev_name       = "ttyNX",
-       .major          = SERIAL_NX_MAJOR,
-       .minor          = MINOR_START,
-       .nr             = ARRAY_SIZE(netx_ports),
-       .cons           = NETX_CONSOLE,
-};
-
-static int serial_netx_suspend(struct platform_device *pdev, pm_message_t state)
-{
-       struct netx_port *sport = platform_get_drvdata(pdev);
-
-       if (sport)
-               uart_suspend_port(&netx_reg, &sport->port);
-
-       return 0;
-}
-
-static int serial_netx_resume(struct platform_device *pdev)
-{
-       struct netx_port *sport = platform_get_drvdata(pdev);
-
-       if (sport)
-               uart_resume_port(&netx_reg, &sport->port);
-
-       return 0;
-}
-
-static int serial_netx_probe(struct platform_device *pdev)
-{
-       struct uart_port *port = &netx_ports[pdev->id].port;
-
-       dev_info(&pdev->dev, "initialising\n");
-
-       port->dev = &pdev->dev;
-
-       writel(1, port->membase + UART_RXFIFO_IRQLEVEL);
-       uart_add_one_port(&netx_reg, &netx_ports[pdev->id].port);
-       platform_set_drvdata(pdev, &netx_ports[pdev->id]);
-
-       return 0;
-}
-
-static int serial_netx_remove(struct platform_device *pdev)
-{
-       struct netx_port *sport = platform_get_drvdata(pdev);
-
-       platform_set_drvdata(pdev, NULL);
-
-       if (sport)
-               uart_remove_one_port(&netx_reg, &sport->port);
-
-       return 0;
-}
-
-static struct platform_driver serial_netx_driver = {
-       .probe          = serial_netx_probe,
-       .remove         = serial_netx_remove,
-
-       .suspend        = serial_netx_suspend,
-       .resume         = serial_netx_resume,
-
-       .driver         = {
-               .name   = DRIVER_NAME,
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init netx_serial_init(void)
-{
-       int ret;
-
-       printk(KERN_INFO "Serial: NetX driver\n");
-
-       ret = uart_register_driver(&netx_reg);
-       if (ret)
-               return ret;
-
-       ret = platform_driver_register(&serial_netx_driver);
-       if (ret != 0)
-               uart_unregister_driver(&netx_reg);
-
-       return 0;
-}
-
-static void __exit netx_serial_exit(void)
-{
-       platform_driver_unregister(&serial_netx_driver);
-       uart_unregister_driver(&netx_reg);
-}
-
-module_init(netx_serial_init);
-module_exit(netx_serial_exit);
-
-MODULE_AUTHOR("Sascha Hauer");
-MODULE_DESCRIPTION("NetX serial port driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/serial/nwpserial.c b/drivers/serial/nwpserial.c
deleted file mode 100644 (file)
index de17367..0000000
+++ /dev/null
@@ -1,477 +0,0 @@
-/*
- *  Serial Port driver for a NWP uart device
- *
- *    Copyright (C) 2008 IBM Corp., Benjamin Krill <ben@codiert.org>
- *
- *  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.
- *
- */
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/serial.h>
-#include <linux/serial_reg.h>
-#include <linux/serial_core.h>
-#include <linux/tty.h>
-#include <linux/irqreturn.h>
-#include <linux/mutex.h>
-#include <linux/of_platform.h>
-#include <linux/of_device.h>
-#include <linux/nwpserial.h>
-#include <asm/prom.h>
-#include <asm/dcr.h>
-
-#define NWPSERIAL_NR               2
-
-#define NWPSERIAL_STATUS_RXVALID 0x1
-#define NWPSERIAL_STATUS_TXFULL  0x2
-
-struct nwpserial_port {
-       struct uart_port port;
-       dcr_host_t dcr_host;
-       unsigned int ier;
-       unsigned int mcr;
-};
-
-static DEFINE_MUTEX(nwpserial_mutex);
-static struct nwpserial_port nwpserial_ports[NWPSERIAL_NR];
-
-static void wait_for_bits(struct nwpserial_port *up, int bits)
-{
-       unsigned int status, tmout = 10000;
-
-       /* Wait up to 10ms for the character(s) to be sent. */
-       do {
-               status = dcr_read(up->dcr_host, UART_LSR);
-
-               if (--tmout == 0)
-                       break;
-               udelay(1);
-       } while ((status & bits) != bits);
-}
-
-#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE
-static void nwpserial_console_putchar(struct uart_port *port, int c)
-{
-       struct nwpserial_port *up;
-       up = container_of(port, struct nwpserial_port, port);
-       /* check if tx buffer is full */
-       wait_for_bits(up, UART_LSR_THRE);
-       dcr_write(up->dcr_host, UART_TX, c);
-       up->port.icount.tx++;
-}
-
-static void
-nwpserial_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct nwpserial_port *up = &nwpserial_ports[co->index];
-       unsigned long flags;
-       int locked = 1;
-
-       if (oops_in_progress)
-               locked = spin_trylock_irqsave(&up->port.lock, flags);
-       else
-               spin_lock_irqsave(&up->port.lock, flags);
-
-       /* save and disable interrupt */
-       up->ier = dcr_read(up->dcr_host, UART_IER);
-       dcr_write(up->dcr_host, UART_IER, up->ier & ~UART_IER_RDI);
-
-       uart_console_write(&up->port, s, count, nwpserial_console_putchar);
-
-       /* wait for transmitter to become empty */
-       while ((dcr_read(up->dcr_host, UART_LSR) & UART_LSR_THRE) == 0)
-               cpu_relax();
-
-       /* restore interrupt state */
-       dcr_write(up->dcr_host, UART_IER, up->ier);
-
-       if (locked)
-               spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static struct uart_driver nwpserial_reg;
-static struct console nwpserial_console = {
-       .name           = "ttySQ",
-       .write          = nwpserial_console_write,
-       .device         = uart_console_device,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &nwpserial_reg,
-};
-#define NWPSERIAL_CONSOLE      (&nwpserial_console)
-#else
-#define NWPSERIAL_CONSOLE      NULL
-#endif /* CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE */
-
-/**************************************************************************/
-
-static int nwpserial_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-static void nwpserial_release_port(struct uart_port *port)
-{
-       /* N/A */
-}
-
-static void nwpserial_config_port(struct uart_port *port, int flags)
-{
-       port->type = PORT_NWPSERIAL;
-}
-
-static irqreturn_t nwpserial_interrupt(int irq, void *dev_id)
-{
-       struct nwpserial_port *up = dev_id;
-       struct tty_struct *tty = up->port.state->port.tty;
-       irqreturn_t ret;
-       unsigned int iir;
-       unsigned char ch;
-
-       spin_lock(&up->port.lock);
-
-       /* check if the uart was the interrupt source. */
-       iir = dcr_read(up->dcr_host, UART_IIR);
-       if (!iir) {
-               ret = IRQ_NONE;
-               goto out;
-       }
-
-       do {
-               up->port.icount.rx++;
-               ch = dcr_read(up->dcr_host, UART_RX);
-               if (up->port.ignore_status_mask != NWPSERIAL_STATUS_RXVALID)
-                       tty_insert_flip_char(tty, ch, TTY_NORMAL);
-       } while (dcr_read(up->dcr_host, UART_LSR) & UART_LSR_DR);
-
-       tty_flip_buffer_push(tty);
-       ret = IRQ_HANDLED;
-
-       /* clear interrupt */
-       dcr_write(up->dcr_host, UART_IIR, 1);
-out:
-       spin_unlock(&up->port.lock);
-       return ret;
-}
-
-static int nwpserial_startup(struct uart_port *port)
-{
-       struct nwpserial_port *up;
-       int err;
-
-       up = container_of(port, struct nwpserial_port, port);
-
-       /* disable flow control by default */
-       up->mcr = dcr_read(up->dcr_host, UART_MCR) & ~UART_MCR_AFE;
-       dcr_write(up->dcr_host, UART_MCR, up->mcr);
-
-       /* register interrupt handler */
-       err = request_irq(up->port.irq, nwpserial_interrupt,
-                       IRQF_SHARED, "nwpserial", up);
-       if (err)
-               return err;
-
-       /* enable interrupts */
-       up->ier = UART_IER_RDI;
-       dcr_write(up->dcr_host, UART_IER, up->ier);
-
-       /* enable receiving */
-       up->port.ignore_status_mask &= ~NWPSERIAL_STATUS_RXVALID;
-
-       return 0;
-}
-
-static void nwpserial_shutdown(struct uart_port *port)
-{
-       struct nwpserial_port *up;
-       up = container_of(port, struct nwpserial_port, port);
-
-       /* disable receiving */
-       up->port.ignore_status_mask |= NWPSERIAL_STATUS_RXVALID;
-
-       /* disable interrupts from this port */
-       up->ier = 0;
-       dcr_write(up->dcr_host, UART_IER, up->ier);
-
-       /* free irq */
-       free_irq(up->port.irq, port);
-}
-
-static int nwpserial_verify_port(struct uart_port *port,
-                       struct serial_struct *ser)
-{
-       return -EINVAL;
-}
-
-static const char *nwpserial_type(struct uart_port *port)
-{
-       return port->type == PORT_NWPSERIAL ? "nwpserial" : NULL;
-}
-
-static void nwpserial_set_termios(struct uart_port *port,
-                       struct ktermios *termios, struct ktermios *old)
-{
-       struct nwpserial_port *up;
-       up = container_of(port, struct nwpserial_port, port);
-
-       up->port.read_status_mask = NWPSERIAL_STATUS_RXVALID
-                               | NWPSERIAL_STATUS_TXFULL;
-
-       up->port.ignore_status_mask = 0;
-       /* ignore all characters if CREAD is not set */
-       if ((termios->c_cflag & CREAD) == 0)
-               up->port.ignore_status_mask |= NWPSERIAL_STATUS_RXVALID;
-
-       /* Copy back the old hardware settings */
-       if (old)
-               tty_termios_copy_hw(termios, old);
-}
-
-static void nwpserial_break_ctl(struct uart_port *port, int ctl)
-{
-       /* N/A */
-}
-
-static void nwpserial_enable_ms(struct uart_port *port)
-{
-       /* N/A */
-}
-
-static void nwpserial_stop_rx(struct uart_port *port)
-{
-       struct nwpserial_port *up;
-       up = container_of(port, struct nwpserial_port, port);
-       /* don't forward any more data (like !CREAD) */
-       up->port.ignore_status_mask = NWPSERIAL_STATUS_RXVALID;
-}
-
-static void nwpserial_putchar(struct nwpserial_port *up, unsigned char c)
-{
-       /* check if tx buffer is full */
-       wait_for_bits(up, UART_LSR_THRE);
-       dcr_write(up->dcr_host, UART_TX, c);
-       up->port.icount.tx++;
-}
-
-static void nwpserial_start_tx(struct uart_port *port)
-{
-       struct nwpserial_port *up;
-       struct circ_buf *xmit;
-       up = container_of(port, struct nwpserial_port, port);
-       xmit  = &up->port.state->xmit;
-
-       if (port->x_char) {
-               nwpserial_putchar(up, up->port.x_char);
-               port->x_char = 0;
-       }
-
-       while (!(uart_circ_empty(xmit) || uart_tx_stopped(&up->port))) {
-               nwpserial_putchar(up, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
-       }
-}
-
-static unsigned int nwpserial_get_mctrl(struct uart_port *port)
-{
-       return 0;
-}
-
-static void nwpserial_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       /* N/A */
-}
-
-static void nwpserial_stop_tx(struct uart_port *port)
-{
-       /* N/A */
-}
-
-static unsigned int nwpserial_tx_empty(struct uart_port *port)
-{
-       struct nwpserial_port *up;
-       unsigned long flags;
-       int ret;
-       up = container_of(port, struct nwpserial_port, port);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       ret = dcr_read(up->dcr_host, UART_LSR);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       return ret & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
-}
-
-static struct uart_ops nwpserial_pops = {
-       .tx_empty     = nwpserial_tx_empty,
-       .set_mctrl    = nwpserial_set_mctrl,
-       .get_mctrl    = nwpserial_get_mctrl,
-       .stop_tx      = nwpserial_stop_tx,
-       .start_tx     = nwpserial_start_tx,
-       .stop_rx      = nwpserial_stop_rx,
-       .enable_ms    = nwpserial_enable_ms,
-       .break_ctl    = nwpserial_break_ctl,
-       .startup      = nwpserial_startup,
-       .shutdown     = nwpserial_shutdown,
-       .set_termios  = nwpserial_set_termios,
-       .type         = nwpserial_type,
-       .release_port = nwpserial_release_port,
-       .request_port = nwpserial_request_port,
-       .config_port  = nwpserial_config_port,
-       .verify_port  = nwpserial_verify_port,
-};
-
-static struct uart_driver nwpserial_reg = {
-       .owner       = THIS_MODULE,
-       .driver_name = "nwpserial",
-       .dev_name    = "ttySQ",
-       .major       = TTY_MAJOR,
-       .minor       = 68,
-       .nr          = NWPSERIAL_NR,
-       .cons        = NWPSERIAL_CONSOLE,
-};
-
-int nwpserial_register_port(struct uart_port *port)
-{
-       struct nwpserial_port *up = NULL;
-       int ret = -1;
-       int i;
-       static int first = 1;
-       int dcr_len;
-       int dcr_base;
-       struct device_node *dn;
-
-       mutex_lock(&nwpserial_mutex);
-
-       dn = port->dev->of_node;
-       if (dn == NULL)
-               goto out;
-
-       /* get dcr base. */
-       dcr_base = dcr_resource_start(dn, 0);
-
-       /* find matching entry */
-       for (i = 0; i < NWPSERIAL_NR; i++)
-               if (nwpserial_ports[i].port.iobase == dcr_base) {
-                       up = &nwpserial_ports[i];
-                       break;
-               }
-
-       /* we didn't find a mtching entry, search for a free port */
-       if (up == NULL)
-               for (i = 0; i < NWPSERIAL_NR; i++)
-                       if (nwpserial_ports[i].port.type == PORT_UNKNOWN &&
-                               nwpserial_ports[i].port.iobase == 0) {
-                               up = &nwpserial_ports[i];
-                               break;
-                       }
-
-       if (up == NULL) {
-               ret = -EBUSY;
-               goto out;
-       }
-
-       if (first)
-               uart_register_driver(&nwpserial_reg);
-       first = 0;
-
-       up->port.membase      = port->membase;
-       up->port.irq          = port->irq;
-       up->port.uartclk      = port->uartclk;
-       up->port.fifosize     = port->fifosize;
-       up->port.regshift     = port->regshift;
-       up->port.iotype       = port->iotype;
-       up->port.flags        = port->flags;
-       up->port.mapbase      = port->mapbase;
-       up->port.private_data = port->private_data;
-
-       if (port->dev)
-               up->port.dev = port->dev;
-
-       if (up->port.iobase != dcr_base) {
-               up->port.ops          = &nwpserial_pops;
-               up->port.fifosize     = 16;
-
-               spin_lock_init(&up->port.lock);
-
-               up->port.iobase = dcr_base;
-               dcr_len = dcr_resource_len(dn, 0);
-
-               up->dcr_host = dcr_map(dn, dcr_base, dcr_len);
-               if (!DCR_MAP_OK(up->dcr_host)) {
-                       printk(KERN_ERR "Cannot map DCR resources for NWPSERIAL");
-                       goto out;
-               }
-       }
-
-       ret = uart_add_one_port(&nwpserial_reg, &up->port);
-       if (ret == 0)
-               ret = up->port.line;
-
-out:
-       mutex_unlock(&nwpserial_mutex);
-
-       return ret;
-}
-EXPORT_SYMBOL(nwpserial_register_port);
-
-void nwpserial_unregister_port(int line)
-{
-       struct nwpserial_port *up = &nwpserial_ports[line];
-       mutex_lock(&nwpserial_mutex);
-       uart_remove_one_port(&nwpserial_reg, &up->port);
-
-       up->port.type = PORT_UNKNOWN;
-
-       mutex_unlock(&nwpserial_mutex);
-}
-EXPORT_SYMBOL(nwpserial_unregister_port);
-
-#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE
-static int __init nwpserial_console_init(void)
-{
-       struct nwpserial_port *up = NULL;
-       struct device_node *dn;
-       const char *name;
-       int dcr_base;
-       int dcr_len;
-       int i;
-
-       /* search for a free port */
-       for (i = 0; i < NWPSERIAL_NR; i++)
-               if (nwpserial_ports[i].port.type == PORT_UNKNOWN) {
-                       up = &nwpserial_ports[i];
-                       break;
-               }
-
-       if (up == NULL)
-               return -1;
-
-       name = of_get_property(of_chosen, "linux,stdout-path", NULL);
-       if (name == NULL)
-               return -1;
-
-       dn = of_find_node_by_path(name);
-       if (!dn)
-               return -1;
-
-       spin_lock_init(&up->port.lock);
-       up->port.ops = &nwpserial_pops;
-       up->port.type = PORT_NWPSERIAL;
-       up->port.fifosize = 16;
-
-       dcr_base = dcr_resource_start(dn, 0);
-       dcr_len = dcr_resource_len(dn, 0);
-       up->port.iobase = dcr_base;
-
-       up->dcr_host = dcr_map(dn, dcr_base, dcr_len);
-       if (!DCR_MAP_OK(up->dcr_host)) {
-               printk("Cannot map DCR resources for SERIAL");
-               return -1;
-       }
-       register_console(&nwpserial_console);
-       return 0;
-}
-console_initcall(nwpserial_console_init);
-#endif /* CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE */
diff --git a/drivers/serial/of_serial.c b/drivers/serial/of_serial.c
deleted file mode 100644 (file)
index 5c7abe4..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- *  Serial Port driver for Open Firmware platform devices
- *
- *    Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>, IBM Corp.
- *
- *  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.
- *
- */
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/serial_core.h>
-#include <linux/serial_8250.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
-#include <linux/nwpserial.h>
-
-struct of_serial_info {
-       int type;
-       int line;
-};
-
-/*
- * Fill a struct uart_port for a given device node
- */
-static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
-                                       int type, struct uart_port *port)
-{
-       struct resource resource;
-       struct device_node *np = ofdev->dev.of_node;
-       const __be32 *clk, *spd;
-       const __be32 *prop;
-       int ret, prop_size;
-
-       memset(port, 0, sizeof *port);
-       spd = of_get_property(np, "current-speed", NULL);
-       clk = of_get_property(np, "clock-frequency", NULL);
-       if (!clk) {
-               dev_warn(&ofdev->dev, "no clock-frequency property set\n");
-               return -ENODEV;
-       }
-
-       ret = of_address_to_resource(np, 0, &resource);
-       if (ret) {
-               dev_warn(&ofdev->dev, "invalid address\n");
-               return ret;
-       }
-
-       spin_lock_init(&port->lock);
-       port->mapbase = resource.start;
-
-       /* Check for shifted address mapping */
-       prop = of_get_property(np, "reg-offset", &prop_size);
-       if (prop && (prop_size == sizeof(u32)))
-               port->mapbase += be32_to_cpup(prop);
-
-       /* Check for registers offset within the devices address range */
-       prop = of_get_property(np, "reg-shift", &prop_size);
-       if (prop && (prop_size == sizeof(u32)))
-               port->regshift = be32_to_cpup(prop);
-
-       port->irq = irq_of_parse_and_map(np, 0);
-       port->iotype = UPIO_MEM;
-       port->type = type;
-       port->uartclk = be32_to_cpup(clk);
-       port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
-               | UPF_FIXED_PORT | UPF_FIXED_TYPE;
-       port->dev = &ofdev->dev;
-       /* If current-speed was set, then try not to change it. */
-       if (spd)
-               port->custom_divisor = be32_to_cpup(clk) / (16 * (be32_to_cpup(spd)));
-
-       return 0;
-}
-
-/*
- * Try to register a serial port
- */
-static int __devinit of_platform_serial_probe(struct platform_device *ofdev,
-                                               const struct of_device_id *id)
-{
-       struct of_serial_info *info;
-       struct uart_port port;
-       int port_type;
-       int ret;
-
-       if (of_find_property(ofdev->dev.of_node, "used-by-rtas", NULL))
-               return -EBUSY;
-
-       info = kmalloc(sizeof(*info), GFP_KERNEL);
-       if (info == NULL)
-               return -ENOMEM;
-
-       port_type = (unsigned long)id->data;
-       ret = of_platform_serial_setup(ofdev, port_type, &port);
-       if (ret)
-               goto out;
-
-       switch (port_type) {
-#ifdef CONFIG_SERIAL_8250
-       case PORT_8250 ... PORT_MAX_8250:
-               ret = serial8250_register_port(&port);
-               break;
-#endif
-#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
-       case PORT_NWPSERIAL:
-               ret = nwpserial_register_port(&port);
-               break;
-#endif
-       default:
-               /* need to add code for these */
-       case PORT_UNKNOWN:
-               dev_info(&ofdev->dev, "Unknown serial port found, ignored\n");
-               ret = -ENODEV;
-               break;
-       }
-       if (ret < 0)
-               goto out;
-
-       info->type = port_type;
-       info->line = ret;
-       dev_set_drvdata(&ofdev->dev, info);
-       return 0;
-out:
-       kfree(info);
-       irq_dispose_mapping(port.irq);
-       return ret;
-}
-
-/*
- * Release a line
- */
-static int of_platform_serial_remove(struct platform_device *ofdev)
-{
-       struct of_serial_info *info = dev_get_drvdata(&ofdev->dev);
-       switch (info->type) {
-#ifdef CONFIG_SERIAL_8250
-       case PORT_8250 ... PORT_MAX_8250:
-               serial8250_unregister_port(info->line);
-               break;
-#endif
-#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
-       case PORT_NWPSERIAL:
-               nwpserial_unregister_port(info->line);
-               break;
-#endif
-       default:
-               /* need to add code for these */
-               break;
-       }
-       kfree(info);
-       return 0;
-}
-
-/*
- * A few common types, add more as needed.
- */
-static struct of_device_id __devinitdata of_platform_serial_table[] = {
-       { .type = "serial", .compatible = "ns8250",   .data = (void *)PORT_8250, },
-       { .type = "serial", .compatible = "ns16450",  .data = (void *)PORT_16450, },
-       { .type = "serial", .compatible = "ns16550a", .data = (void *)PORT_16550A, },
-       { .type = "serial", .compatible = "ns16550",  .data = (void *)PORT_16550, },
-       { .type = "serial", .compatible = "ns16750",  .data = (void *)PORT_16750, },
-       { .type = "serial", .compatible = "ns16850",  .data = (void *)PORT_16850, },
-#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
-       { .type = "serial", .compatible = "ibm,qpace-nwp-serial",
-                                       .data = (void *)PORT_NWPSERIAL, },
-#endif
-       { .type = "serial",                           .data = (void *)PORT_UNKNOWN, },
-       { /* end of list */ },
-};
-
-static struct of_platform_driver of_platform_serial_driver = {
-       .driver = {
-               .name = "of_serial",
-               .owner = THIS_MODULE,
-               .of_match_table = of_platform_serial_table,
-       },
-       .probe = of_platform_serial_probe,
-       .remove = of_platform_serial_remove,
-};
-
-static int __init of_platform_serial_init(void)
-{
-       return of_register_platform_driver(&of_platform_serial_driver);
-}
-module_init(of_platform_serial_init);
-
-static void __exit of_platform_serial_exit(void)
-{
-       return of_unregister_platform_driver(&of_platform_serial_driver);
-};
-module_exit(of_platform_serial_exit);
-
-MODULE_AUTHOR("Arnd Bergmann <arnd@arndb.de>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Serial Port driver for Open Firmware platform devices");
diff --git a/drivers/serial/omap-serial.c b/drivers/serial/omap-serial.c
deleted file mode 100644 (file)
index 7f2f010..0000000
+++ /dev/null
@@ -1,1359 +0,0 @@
-/*
- * Driver for OMAP-UART controller.
- * Based on drivers/serial/8250.c
- *
- * Copyright (C) 2010 Texas Instruments.
- *
- * Authors:
- *     Govindraj R     <govindraj.raja@ti.com>
- *     Thara Gopinath  <thara@ti.com>
- *
- * 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.
- *
- * Note: This driver is made seperate from 8250 driver as we cannot
- * over load 8250 driver with omap platform specific configuration for
- * features like DMA, it makes easier to implement features like DMA and
- * hardware flow control and software flow control configuration with
- * this driver as required for the omap-platform.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/serial_reg.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/io.h>
-#include <linux/dma-mapping.h>
-#include <linux/clk.h>
-#include <linux/serial_core.h>
-#include <linux/irq.h>
-
-#include <plat/dma.h>
-#include <plat/dmtimer.h>
-#include <plat/omap-serial.h>
-
-static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
-
-/* Forward declaration of functions */
-static void uart_tx_dma_callback(int lch, u16 ch_status, void *data);
-static void serial_omap_rx_timeout(unsigned long uart_no);
-static int serial_omap_start_rxdma(struct uart_omap_port *up);
-
-static inline unsigned int serial_in(struct uart_omap_port *up, int offset)
-{
-       offset <<= up->port.regshift;
-       return readw(up->port.membase + offset);
-}
-
-static inline void serial_out(struct uart_omap_port *up, int offset, int value)
-{
-       offset <<= up->port.regshift;
-       writew(value, up->port.membase + offset);
-}
-
-static inline void serial_omap_clear_fifos(struct uart_omap_port *up)
-{
-       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
-                      UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
-       serial_out(up, UART_FCR, 0);
-}
-
-/*
- * serial_omap_get_divisor - calculate divisor value
- * @port: uart port info
- * @baud: baudrate for which divisor needs to be calculated.
- *
- * We have written our own function to get the divisor so as to support
- * 13x mode. 3Mbps Baudrate as an different divisor.
- * Reference OMAP TRM Chapter 17:
- * Table 17-1. UART Mode Baud Rates, Divisor Values, and Error Rates
- * referring to oversampling - divisor value
- * baudrate 460,800 to 3,686,400 all have divisor 13
- * except 3,000,000 which has divisor value 16
- */
-static unsigned int
-serial_omap_get_divisor(struct uart_port *port, unsigned int baud)
-{
-       unsigned int divisor;
-
-       if (baud > OMAP_MODE13X_SPEED && baud != 3000000)
-               divisor = 13;
-       else
-               divisor = 16;
-       return port->uartclk/(baud * divisor);
-}
-
-static void serial_omap_stop_rxdma(struct uart_omap_port *up)
-{
-       if (up->uart_dma.rx_dma_used) {
-               del_timer(&up->uart_dma.rx_timer);
-               omap_stop_dma(up->uart_dma.rx_dma_channel);
-               omap_free_dma(up->uart_dma.rx_dma_channel);
-               up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
-               up->uart_dma.rx_dma_used = false;
-       }
-}
-
-static void serial_omap_enable_ms(struct uart_port *port)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-
-       dev_dbg(up->port.dev, "serial_omap_enable_ms+%d\n", up->pdev->id);
-       up->ier |= UART_IER_MSI;
-       serial_out(up, UART_IER, up->ier);
-}
-
-static void serial_omap_stop_tx(struct uart_port *port)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-
-       if (up->use_dma &&
-               up->uart_dma.tx_dma_channel != OMAP_UART_DMA_CH_FREE) {
-               /*
-                * Check if dma is still active. If yes do nothing,
-                * return. Else stop dma
-                */
-               if (omap_get_dma_active_status(up->uart_dma.tx_dma_channel))
-                       return;
-               omap_stop_dma(up->uart_dma.tx_dma_channel);
-               omap_free_dma(up->uart_dma.tx_dma_channel);
-               up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE;
-       }
-
-       if (up->ier & UART_IER_THRI) {
-               up->ier &= ~UART_IER_THRI;
-               serial_out(up, UART_IER, up->ier);
-       }
-}
-
-static void serial_omap_stop_rx(struct uart_port *port)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-
-       if (up->use_dma)
-               serial_omap_stop_rxdma(up);
-       up->ier &= ~UART_IER_RLSI;
-       up->port.read_status_mask &= ~UART_LSR_DR;
-       serial_out(up, UART_IER, up->ier);
-}
-
-static inline void receive_chars(struct uart_omap_port *up, int *status)
-{
-       struct tty_struct *tty = up->port.state->port.tty;
-       unsigned int flag;
-       unsigned char ch, lsr = *status;
-       int max_count = 256;
-
-       do {
-               if (likely(lsr & UART_LSR_DR))
-                       ch = serial_in(up, UART_RX);
-               flag = TTY_NORMAL;
-               up->port.icount.rx++;
-
-               if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
-                       /*
-                        * For statistics only
-                        */
-                       if (lsr & UART_LSR_BI) {
-                               lsr &= ~(UART_LSR_FE | UART_LSR_PE);
-                               up->port.icount.brk++;
-                               /*
-                                * We do the SysRQ and SAK checking
-                                * here because otherwise the break
-                                * may get masked by ignore_status_mask
-                                * or read_status_mask.
-                                */
-                               if (uart_handle_break(&up->port))
-                                       goto ignore_char;
-                       } else if (lsr & UART_LSR_PE) {
-                               up->port.icount.parity++;
-                       } else if (lsr & UART_LSR_FE) {
-                               up->port.icount.frame++;
-                       }
-
-                       if (lsr & UART_LSR_OE)
-                               up->port.icount.overrun++;
-
-                       /*
-                        * Mask off conditions which should be ignored.
-                        */
-                       lsr &= up->port.read_status_mask;
-
-#ifdef CONFIG_SERIAL_OMAP_CONSOLE
-                       if (up->port.line == up->port.cons->index) {
-                               /* Recover the break flag from console xmit */
-                               lsr |= up->lsr_break_flag;
-                               up->lsr_break_flag = 0;
-                       }
-#endif
-                       if (lsr & UART_LSR_BI)
-                               flag = TTY_BREAK;
-                       else if (lsr & UART_LSR_PE)
-                               flag = TTY_PARITY;
-                       else if (lsr & UART_LSR_FE)
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(&up->port, ch))
-                       goto ignore_char;
-               uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);
-ignore_char:
-               lsr = serial_in(up, UART_LSR);
-       } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0));
-       spin_unlock(&up->port.lock);
-       tty_flip_buffer_push(tty);
-       spin_lock(&up->port.lock);
-}
-
-static void transmit_chars(struct uart_omap_port *up)
-{
-       struct circ_buf *xmit = &up->port.state->xmit;
-       int count;
-
-       if (up->port.x_char) {
-               serial_out(up, UART_TX, up->port.x_char);
-               up->port.icount.tx++;
-               up->port.x_char = 0;
-               return;
-       }
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
-               serial_omap_stop_tx(&up->port);
-               return;
-       }
-       count = up->port.fifosize / 4;
-       do {
-               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               up->port.icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (--count > 0);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&up->port);
-
-       if (uart_circ_empty(xmit))
-               serial_omap_stop_tx(&up->port);
-}
-
-static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up)
-{
-       if (!(up->ier & UART_IER_THRI)) {
-               up->ier |= UART_IER_THRI;
-               serial_out(up, UART_IER, up->ier);
-       }
-}
-
-static void serial_omap_start_tx(struct uart_port *port)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-       struct circ_buf *xmit;
-       unsigned int start;
-       int ret = 0;
-
-       if (!up->use_dma) {
-               serial_omap_enable_ier_thri(up);
-               return;
-       }
-
-       if (up->uart_dma.tx_dma_used)
-               return;
-
-       xmit = &up->port.state->xmit;
-
-       if (up->uart_dma.tx_dma_channel == OMAP_UART_DMA_CH_FREE) {
-               ret = omap_request_dma(up->uart_dma.uart_dma_tx,
-                               "UART Tx DMA",
-                               (void *)uart_tx_dma_callback, up,
-                               &(up->uart_dma.tx_dma_channel));
-
-               if (ret < 0) {
-                       serial_omap_enable_ier_thri(up);
-                       return;
-               }
-       }
-       spin_lock(&(up->uart_dma.tx_lock));
-       up->uart_dma.tx_dma_used = true;
-       spin_unlock(&(up->uart_dma.tx_lock));
-
-       start = up->uart_dma.tx_buf_dma_phys +
-                               (xmit->tail & (UART_XMIT_SIZE - 1));
-
-       up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit);
-       /*
-        * It is a circular buffer. See if the buffer has wounded back.
-        * If yes it will have to be transferred in two separate dma
-        * transfers
-        */
-       if (start + up->uart_dma.tx_buf_size >=
-                       up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE)
-               up->uart_dma.tx_buf_size =
-                       (up->uart_dma.tx_buf_dma_phys +
-                       UART_XMIT_SIZE) - start;
-
-       omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0,
-                               OMAP_DMA_AMODE_CONSTANT,
-                               up->uart_dma.uart_base, 0, 0);
-       omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0,
-                               OMAP_DMA_AMODE_POST_INC, start, 0, 0);
-       omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel,
-                               OMAP_DMA_DATA_TYPE_S8,
-                               up->uart_dma.tx_buf_size, 1,
-                               OMAP_DMA_SYNC_ELEMENT,
-                               up->uart_dma.uart_dma_tx, 0);
-       /* FIXME: Cache maintenance needed here? */
-       omap_start_dma(up->uart_dma.tx_dma_channel);
-}
-
-static unsigned int check_modem_status(struct uart_omap_port *up)
-{
-       unsigned int status;
-
-       status = serial_in(up, UART_MSR);
-       status |= up->msr_saved_flags;
-       up->msr_saved_flags = 0;
-       if ((status & UART_MSR_ANY_DELTA) == 0)
-               return status;
-
-       if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&
-           up->port.state != NULL) {
-               if (status & UART_MSR_TERI)
-                       up->port.icount.rng++;
-               if (status & UART_MSR_DDSR)
-                       up->port.icount.dsr++;
-               if (status & UART_MSR_DDCD)
-                       uart_handle_dcd_change
-                               (&up->port, status & UART_MSR_DCD);
-               if (status & UART_MSR_DCTS)
-                       uart_handle_cts_change
-                               (&up->port, status & UART_MSR_CTS);
-               wake_up_interruptible(&up->port.state->port.delta_msr_wait);
-       }
-
-       return status;
-}
-
-/**
- * serial_omap_irq() - This handles the interrupt from one port
- * @irq: uart port irq number
- * @dev_id: uart port info
- */
-static inline irqreturn_t serial_omap_irq(int irq, void *dev_id)
-{
-       struct uart_omap_port *up = dev_id;
-       unsigned int iir, lsr;
-       unsigned long flags;
-
-       iir = serial_in(up, UART_IIR);
-       if (iir & UART_IIR_NO_INT)
-               return IRQ_NONE;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       lsr = serial_in(up, UART_LSR);
-       if (iir & UART_IIR_RLSI) {
-               if (!up->use_dma) {
-                       if (lsr & UART_LSR_DR)
-                               receive_chars(up, &lsr);
-               } else {
-                       up->ier &= ~(UART_IER_RDI | UART_IER_RLSI);
-                       serial_out(up, UART_IER, up->ier);
-                       if ((serial_omap_start_rxdma(up) != 0) &&
-                                       (lsr & UART_LSR_DR))
-                               receive_chars(up, &lsr);
-               }
-       }
-
-       check_modem_status(up);
-       if ((lsr & UART_LSR_THRE) && (iir & UART_IIR_THRI))
-               transmit_chars(up);
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-       up->port_activity = jiffies;
-       return IRQ_HANDLED;
-}
-
-static unsigned int serial_omap_tx_empty(struct uart_port *port)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-       unsigned long flags = 0;
-       unsigned int ret = 0;
-
-       dev_dbg(up->port.dev, "serial_omap_tx_empty+%d\n", up->pdev->id);
-       spin_lock_irqsave(&up->port.lock, flags);
-       ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       return ret;
-}
-
-static unsigned int serial_omap_get_mctrl(struct uart_port *port)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-       unsigned char status;
-       unsigned int ret = 0;
-
-       status = check_modem_status(up);
-       dev_dbg(up->port.dev, "serial_omap_get_mctrl+%d\n", up->pdev->id);
-
-       if (status & UART_MSR_DCD)
-               ret |= TIOCM_CAR;
-       if (status & UART_MSR_RI)
-               ret |= TIOCM_RNG;
-       if (status & UART_MSR_DSR)
-               ret |= TIOCM_DSR;
-       if (status & UART_MSR_CTS)
-               ret |= TIOCM_CTS;
-       return ret;
-}
-
-static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-       unsigned char mcr = 0;
-
-       dev_dbg(up->port.dev, "serial_omap_set_mctrl+%d\n", up->pdev->id);
-       if (mctrl & TIOCM_RTS)
-               mcr |= UART_MCR_RTS;
-       if (mctrl & TIOCM_DTR)
-               mcr |= UART_MCR_DTR;
-       if (mctrl & TIOCM_OUT1)
-               mcr |= UART_MCR_OUT1;
-       if (mctrl & TIOCM_OUT2)
-               mcr |= UART_MCR_OUT2;
-       if (mctrl & TIOCM_LOOP)
-               mcr |= UART_MCR_LOOP;
-
-       mcr |= up->mcr;
-       serial_out(up, UART_MCR, mcr);
-}
-
-static void serial_omap_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-       unsigned long flags = 0;
-
-       dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->pdev->id);
-       spin_lock_irqsave(&up->port.lock, flags);
-       if (break_state == -1)
-               up->lcr |= UART_LCR_SBC;
-       else
-               up->lcr &= ~UART_LCR_SBC;
-       serial_out(up, UART_LCR, up->lcr);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static int serial_omap_startup(struct uart_port *port)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-       unsigned long flags = 0;
-       int retval;
-
-       /*
-        * Allocate the IRQ
-        */
-       retval = request_irq(up->port.irq, serial_omap_irq, up->port.irqflags,
-                               up->name, up);
-       if (retval)
-               return retval;
-
-       dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->pdev->id);
-
-       /*
-        * Clear the FIFO buffers and disable them.
-        * (they will be reenabled in set_termios())
-        */
-       serial_omap_clear_fifos(up);
-       /* For Hardware flow control */
-       serial_out(up, UART_MCR, UART_MCR_RTS);
-
-       /*
-        * Clear the interrupt registers.
-        */
-       (void) serial_in(up, UART_LSR);
-       if (serial_in(up, UART_LSR) & UART_LSR_DR)
-               (void) serial_in(up, UART_RX);
-       (void) serial_in(up, UART_IIR);
-       (void) serial_in(up, UART_MSR);
-
-       /*
-        * Now, initialize the UART
-        */
-       serial_out(up, UART_LCR, UART_LCR_WLEN8);
-       spin_lock_irqsave(&up->port.lock, flags);
-       /*
-        * Most PC uarts need OUT2 raised to enable interrupts.
-        */
-       up->port.mctrl |= TIOCM_OUT2;
-       serial_omap_set_mctrl(&up->port, up->port.mctrl);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       up->msr_saved_flags = 0;
-       if (up->use_dma) {
-               free_page((unsigned long)up->port.state->xmit.buf);
-               up->port.state->xmit.buf = dma_alloc_coherent(NULL,
-                       UART_XMIT_SIZE,
-                       (dma_addr_t *)&(up->uart_dma.tx_buf_dma_phys),
-                       0);
-               init_timer(&(up->uart_dma.rx_timer));
-               up->uart_dma.rx_timer.function = serial_omap_rx_timeout;
-               up->uart_dma.rx_timer.data = up->pdev->id;
-               /* Currently the buffer size is 4KB. Can increase it */
-               up->uart_dma.rx_buf = dma_alloc_coherent(NULL,
-                       up->uart_dma.rx_buf_size,
-                       (dma_addr_t *)&(up->uart_dma.rx_buf_dma_phys), 0);
-       }
-       /*
-        * Finally, enable interrupts. Note: Modem status interrupts
-        * are set via set_termios(), which will be occurring imminently
-        * anyway, so we don't enable them here.
-        */
-       up->ier = UART_IER_RLSI | UART_IER_RDI;
-       serial_out(up, UART_IER, up->ier);
-
-       up->port_activity = jiffies;
-       return 0;
-}
-
-static void serial_omap_shutdown(struct uart_port *port)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-       unsigned long flags = 0;
-
-       dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->pdev->id);
-       /*
-        * Disable interrupts from this port
-        */
-       up->ier = 0;
-       serial_out(up, UART_IER, 0);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       up->port.mctrl &= ~TIOCM_OUT2;
-       serial_omap_set_mctrl(&up->port, up->port.mctrl);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       /*
-        * Disable break condition and FIFOs
-        */
-       serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
-       serial_omap_clear_fifos(up);
-
-       /*
-        * Read data port to reset things, and then free the irq
-        */
-       if (serial_in(up, UART_LSR) & UART_LSR_DR)
-               (void) serial_in(up, UART_RX);
-       if (up->use_dma) {
-               dma_free_coherent(up->port.dev,
-                       UART_XMIT_SIZE, up->port.state->xmit.buf,
-                       up->uart_dma.tx_buf_dma_phys);
-               up->port.state->xmit.buf = NULL;
-               serial_omap_stop_rx(port);
-               dma_free_coherent(up->port.dev,
-                       up->uart_dma.rx_buf_size, up->uart_dma.rx_buf,
-                       up->uart_dma.rx_buf_dma_phys);
-               up->uart_dma.rx_buf = NULL;
-       }
-       free_irq(up->port.irq, up);
-}
-
-static inline void
-serial_omap_configure_xonxoff
-               (struct uart_omap_port *up, struct ktermios *termios)
-{
-       unsigned char efr = 0;
-
-       up->lcr = serial_in(up, UART_LCR);
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-       up->efr = serial_in(up, UART_EFR);
-       serial_out(up, UART_EFR, up->efr & ~UART_EFR_ECB);
-
-       serial_out(up, UART_XON1, termios->c_cc[VSTART]);
-       serial_out(up, UART_XOFF1, termios->c_cc[VSTOP]);
-
-       /* clear SW control mode bits */
-       efr = up->efr;
-       efr &= OMAP_UART_SW_CLR;
-
-       /*
-        * IXON Flag:
-        * Enable XON/XOFF flow control on output.
-        * Transmit XON1, XOFF1
-        */
-       if (termios->c_iflag & IXON)
-               efr |= OMAP_UART_SW_TX;
-
-       /*
-        * IXOFF Flag:
-        * Enable XON/XOFF flow control on input.
-        * Receiver compares XON1, XOFF1.
-        */
-       if (termios->c_iflag & IXOFF)
-               efr |= OMAP_UART_SW_RX;
-
-       serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
-
-       up->mcr = serial_in(up, UART_MCR);
-
-       /*
-        * IXANY Flag:
-        * Enable any character to restart output.
-        * Operation resumes after receiving any
-        * character after recognition of the XOFF character
-        */
-       if (termios->c_iflag & IXANY)
-               up->mcr |= UART_MCR_XONANY;
-
-       serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-       serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
-       /* Enable special char function UARTi.EFR_REG[5] and
-        * load the new software flow control mode IXON or IXOFF
-        * and restore the UARTi.EFR_REG[4] ENHANCED_EN value.
-        */
-       serial_out(up, UART_EFR, efr | UART_EFR_SCD);
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
-
-       serial_out(up, UART_MCR, up->mcr & ~UART_MCR_TCRTLR);
-       serial_out(up, UART_LCR, up->lcr);
-}
-
-static void
-serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
-                       struct ktermios *old)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-       unsigned char cval = 0;
-       unsigned char efr = 0;
-       unsigned long flags = 0;
-       unsigned int baud, quot;
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               cval = UART_LCR_WLEN5;
-               break;
-       case CS6:
-               cval = UART_LCR_WLEN6;
-               break;
-       case CS7:
-               cval = UART_LCR_WLEN7;
-               break;
-       default:
-       case CS8:
-               cval = UART_LCR_WLEN8;
-               break;
-       }
-
-       if (termios->c_cflag & CSTOPB)
-               cval |= UART_LCR_STOP;
-       if (termios->c_cflag & PARENB)
-               cval |= UART_LCR_PARITY;
-       if (!(termios->c_cflag & PARODD))
-               cval |= UART_LCR_EPAR;
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/13);
-       quot = serial_omap_get_divisor(port, baud);
-
-       up->fcr = UART_FCR_R_TRIG_01 | UART_FCR_T_TRIG_01 |
-                       UART_FCR_ENABLE_FIFO;
-       if (up->use_dma)
-               up->fcr |= UART_FCR_DMA_SELECT;
-
-       /*
-        * Ok, we're now changing the port state. Do it with
-        * interrupts disabled.
-        */
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
-       if (termios->c_iflag & INPCK)
-               up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               up->port.read_status_mask |= UART_LSR_BI;
-
-       /*
-        * Characters to ignore
-        */
-       up->port.ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
-       if (termios->c_iflag & IGNBRK) {
-               up->port.ignore_status_mask |= UART_LSR_BI;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       up->port.ignore_status_mask |= UART_LSR_OE;
-       }
-
-       /*
-        * ignore all characters if CREAD is not set
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               up->port.ignore_status_mask |= UART_LSR_DR;
-
-       /*
-        * Modem status interrupts
-        */
-       up->ier &= ~UART_IER_MSI;
-       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
-               up->ier |= UART_IER_MSI;
-       serial_out(up, UART_IER, up->ier);
-       serial_out(up, UART_LCR, cval);         /* reset DLAB */
-
-       /* FIFOs and DMA Settings */
-
-       /* FCR can be changed only when the
-        * baud clock is not running
-        * DLL_REG and DLH_REG set to 0.
-        */
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
-       serial_out(up, UART_DLL, 0);
-       serial_out(up, UART_DLM, 0);
-       serial_out(up, UART_LCR, 0);
-
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-
-       up->efr = serial_in(up, UART_EFR);
-       serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
-
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
-       up->mcr = serial_in(up, UART_MCR);
-       serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
-       /* FIFO ENABLE, DMA MODE */
-       serial_out(up, UART_FCR, up->fcr);
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-
-       if (up->use_dma) {
-               serial_out(up, UART_TI752_TLR, 0);
-               serial_out(up, UART_OMAP_SCR,
-                       (UART_FCR_TRIGGER_4 | UART_FCR_TRIGGER_8));
-       }
-
-       serial_out(up, UART_EFR, up->efr);
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
-       serial_out(up, UART_MCR, up->mcr);
-
-       /* Protocol, Baud Rate, and Interrupt Settings */
-
-       serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE);
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-
-       up->efr = serial_in(up, UART_EFR);
-       serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
-
-       serial_out(up, UART_LCR, 0);
-       serial_out(up, UART_IER, 0);
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-
-       serial_out(up, UART_DLL, quot & 0xff);          /* LS of divisor */
-       serial_out(up, UART_DLM, quot >> 8);            /* MS of divisor */
-
-       serial_out(up, UART_LCR, 0);
-       serial_out(up, UART_IER, up->ier);
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-
-       serial_out(up, UART_EFR, up->efr);
-       serial_out(up, UART_LCR, cval);
-
-       if (baud > 230400 && baud != 3000000)
-               serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_13X_MODE);
-       else
-               serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_16X_MODE);
-
-       /* Hardware Flow Control Configuration */
-
-       if (termios->c_cflag & CRTSCTS) {
-               efr |= (UART_EFR_CTS | UART_EFR_RTS);
-               serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
-
-               up->mcr = serial_in(up, UART_MCR);
-               serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
-
-               serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-               up->efr = serial_in(up, UART_EFR);
-               serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
-
-               serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
-               serial_out(up, UART_EFR, efr); /* Enable AUTORTS and AUTOCTS */
-               serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
-               serial_out(up, UART_MCR, up->mcr | UART_MCR_RTS);
-               serial_out(up, UART_LCR, cval);
-       }
-
-       serial_omap_set_mctrl(&up->port, up->port.mctrl);
-       /* Software Flow Control Configuration */
-       if (termios->c_iflag & (IXON | IXOFF))
-               serial_omap_configure_xonxoff(up, termios);
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-       dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->pdev->id);
-}
-
-static void
-serial_omap_pm(struct uart_port *port, unsigned int state,
-              unsigned int oldstate)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-       unsigned char efr;
-
-       dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->pdev->id);
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-       efr = serial_in(up, UART_EFR);
-       serial_out(up, UART_EFR, efr | UART_EFR_ECB);
-       serial_out(up, UART_LCR, 0);
-
-       serial_out(up, UART_IER, (state != 0) ? UART_IERX_SLEEP : 0);
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-       serial_out(up, UART_EFR, efr);
-       serial_out(up, UART_LCR, 0);
-       /* Enable module level wake up */
-       serial_out(up, UART_OMAP_WER,
-               (state != 0) ? OMAP_UART_WER_MOD_WKUP : 0);
-}
-
-static void serial_omap_release_port(struct uart_port *port)
-{
-       dev_dbg(port->dev, "serial_omap_release_port+\n");
-}
-
-static int serial_omap_request_port(struct uart_port *port)
-{
-       dev_dbg(port->dev, "serial_omap_request_port+\n");
-       return 0;
-}
-
-static void serial_omap_config_port(struct uart_port *port, int flags)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-
-       dev_dbg(up->port.dev, "serial_omap_config_port+%d\n",
-                                                       up->pdev->id);
-       up->port.type = PORT_OMAP;
-}
-
-static int
-serial_omap_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       /* we don't want the core code to modify any port params */
-       dev_dbg(port->dev, "serial_omap_verify_port+\n");
-       return -EINVAL;
-}
-
-static const char *
-serial_omap_type(struct uart_port *port)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-
-       dev_dbg(up->port.dev, "serial_omap_type+%d\n", up->pdev->id);
-       return up->name;
-}
-
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-
-static inline void wait_for_xmitr(struct uart_omap_port *up)
-{
-       unsigned int status, tmout = 10000;
-
-       /* Wait up to 10ms for the character(s) to be sent. */
-       do {
-               status = serial_in(up, UART_LSR);
-
-               if (status & UART_LSR_BI)
-                       up->lsr_break_flag = UART_LSR_BI;
-
-               if (--tmout == 0)
-                       break;
-               udelay(1);
-       } while ((status & BOTH_EMPTY) != BOTH_EMPTY);
-
-       /* Wait up to 1s for flow control if necessary */
-       if (up->port.flags & UPF_CONS_FLOW) {
-               tmout = 1000000;
-               for (tmout = 1000000; tmout; tmout--) {
-                       unsigned int msr = serial_in(up, UART_MSR);
-
-                       up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
-                       if (msr & UART_MSR_CTS)
-                               break;
-
-                       udelay(1);
-               }
-       }
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-
-static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-       wait_for_xmitr(up);
-       serial_out(up, UART_TX, ch);
-}
-
-static int serial_omap_poll_get_char(struct uart_port *port)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-       unsigned int status = serial_in(up, UART_LSR);
-
-       if (!(status & UART_LSR_DR))
-               return NO_POLL_CHAR;
-
-       return serial_in(up, UART_RX);
-}
-
-#endif /* CONFIG_CONSOLE_POLL */
-
-#ifdef CONFIG_SERIAL_OMAP_CONSOLE
-
-static struct uart_omap_port *serial_omap_console_ports[4];
-
-static struct uart_driver serial_omap_reg;
-
-static void serial_omap_console_putchar(struct uart_port *port, int ch)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-
-       wait_for_xmitr(up);
-       serial_out(up, UART_TX, ch);
-}
-
-static void
-serial_omap_console_write(struct console *co, const char *s,
-               unsigned int count)
-{
-       struct uart_omap_port *up = serial_omap_console_ports[co->index];
-       unsigned long flags;
-       unsigned int ier;
-       int locked = 1;
-
-       local_irq_save(flags);
-       if (up->port.sysrq)
-               locked = 0;
-       else if (oops_in_progress)
-               locked = spin_trylock(&up->port.lock);
-       else
-               spin_lock(&up->port.lock);
-
-       /*
-        * First save the IER then disable the interrupts
-        */
-       ier = serial_in(up, UART_IER);
-       serial_out(up, UART_IER, 0);
-
-       uart_console_write(&up->port, s, count, serial_omap_console_putchar);
-
-       /*
-        * Finally, wait for transmitter to become empty
-        * and restore the IER
-        */
-       wait_for_xmitr(up);
-       serial_out(up, UART_IER, ier);
-       /*
-        * The receive handling will happen properly because the
-        * receive ready bit will still be set; it is not cleared
-        * on read.  However, modem control will not, we must
-        * call it if we have saved something in the saved flags
-        * while processing with interrupts off.
-        */
-       if (up->msr_saved_flags)
-               check_modem_status(up);
-
-       if (locked)
-               spin_unlock(&up->port.lock);
-       local_irq_restore(flags);
-}
-
-static int __init
-serial_omap_console_setup(struct console *co, char *options)
-{
-       struct uart_omap_port *up;
-       int baud = 115200;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       if (serial_omap_console_ports[co->index] == NULL)
-               return -ENODEV;
-       up = serial_omap_console_ports[co->index];
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(&up->port, co, baud, parity, bits, flow);
-}
-
-static struct console serial_omap_console = {
-       .name           = OMAP_SERIAL_NAME,
-       .write          = serial_omap_console_write,
-       .device         = uart_console_device,
-       .setup          = serial_omap_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &serial_omap_reg,
-};
-
-static void serial_omap_add_console_port(struct uart_omap_port *up)
-{
-       serial_omap_console_ports[up->pdev->id] = up;
-}
-
-#define OMAP_CONSOLE   (&serial_omap_console)
-
-#else
-
-#define OMAP_CONSOLE   NULL
-
-static inline void serial_omap_add_console_port(struct uart_omap_port *up)
-{}
-
-#endif
-
-static struct uart_ops serial_omap_pops = {
-       .tx_empty       = serial_omap_tx_empty,
-       .set_mctrl      = serial_omap_set_mctrl,
-       .get_mctrl      = serial_omap_get_mctrl,
-       .stop_tx        = serial_omap_stop_tx,
-       .start_tx       = serial_omap_start_tx,
-       .stop_rx        = serial_omap_stop_rx,
-       .enable_ms      = serial_omap_enable_ms,
-       .break_ctl      = serial_omap_break_ctl,
-       .startup        = serial_omap_startup,
-       .shutdown       = serial_omap_shutdown,
-       .set_termios    = serial_omap_set_termios,
-       .pm             = serial_omap_pm,
-       .type           = serial_omap_type,
-       .release_port   = serial_omap_release_port,
-       .request_port   = serial_omap_request_port,
-       .config_port    = serial_omap_config_port,
-       .verify_port    = serial_omap_verify_port,
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_put_char  = serial_omap_poll_put_char,
-       .poll_get_char  = serial_omap_poll_get_char,
-#endif
-};
-
-static struct uart_driver serial_omap_reg = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "OMAP-SERIAL",
-       .dev_name       = OMAP_SERIAL_NAME,
-       .nr             = OMAP_MAX_HSUART_PORTS,
-       .cons           = OMAP_CONSOLE,
-};
-
-static int
-serial_omap_suspend(struct platform_device *pdev, pm_message_t state)
-{
-       struct uart_omap_port *up = platform_get_drvdata(pdev);
-
-       if (up)
-               uart_suspend_port(&serial_omap_reg, &up->port);
-       return 0;
-}
-
-static int serial_omap_resume(struct platform_device *dev)
-{
-       struct uart_omap_port *up = platform_get_drvdata(dev);
-
-       if (up)
-               uart_resume_port(&serial_omap_reg, &up->port);
-       return 0;
-}
-
-static void serial_omap_rx_timeout(unsigned long uart_no)
-{
-       struct uart_omap_port *up = ui[uart_no];
-       unsigned int curr_dma_pos, curr_transmitted_size;
-       int ret = 0;
-
-       curr_dma_pos = omap_get_dma_dst_pos(up->uart_dma.rx_dma_channel);
-       if ((curr_dma_pos == up->uart_dma.prev_rx_dma_pos) ||
-                            (curr_dma_pos == 0)) {
-               if (jiffies_to_msecs(jiffies - up->port_activity) <
-                                                       RX_TIMEOUT) {
-                       mod_timer(&up->uart_dma.rx_timer, jiffies +
-                               usecs_to_jiffies(up->uart_dma.rx_timeout));
-               } else {
-                       serial_omap_stop_rxdma(up);
-                       up->ier |= (UART_IER_RDI | UART_IER_RLSI);
-                       serial_out(up, UART_IER, up->ier);
-               }
-               return;
-       }
-
-       curr_transmitted_size = curr_dma_pos -
-                                       up->uart_dma.prev_rx_dma_pos;
-       up->port.icount.rx += curr_transmitted_size;
-       tty_insert_flip_string(up->port.state->port.tty,
-                       up->uart_dma.rx_buf +
-                       (up->uart_dma.prev_rx_dma_pos -
-                       up->uart_dma.rx_buf_dma_phys),
-                       curr_transmitted_size);
-       tty_flip_buffer_push(up->port.state->port.tty);
-       up->uart_dma.prev_rx_dma_pos = curr_dma_pos;
-       if (up->uart_dma.rx_buf_size +
-                       up->uart_dma.rx_buf_dma_phys == curr_dma_pos) {
-               ret = serial_omap_start_rxdma(up);
-               if (ret < 0) {
-                       serial_omap_stop_rxdma(up);
-                       up->ier |= (UART_IER_RDI | UART_IER_RLSI);
-                       serial_out(up, UART_IER, up->ier);
-               }
-       } else  {
-               mod_timer(&up->uart_dma.rx_timer, jiffies +
-                       usecs_to_jiffies(up->uart_dma.rx_timeout));
-       }
-       up->port_activity = jiffies;
-}
-
-static void uart_rx_dma_callback(int lch, u16 ch_status, void *data)
-{
-       return;
-}
-
-static int serial_omap_start_rxdma(struct uart_omap_port *up)
-{
-       int ret = 0;
-
-       if (up->uart_dma.rx_dma_channel == -1) {
-               ret = omap_request_dma(up->uart_dma.uart_dma_rx,
-                               "UART Rx DMA",
-                               (void *)uart_rx_dma_callback, up,
-                               &(up->uart_dma.rx_dma_channel));
-               if (ret < 0)
-                       return ret;
-
-               omap_set_dma_src_params(up->uart_dma.rx_dma_channel, 0,
-                               OMAP_DMA_AMODE_CONSTANT,
-                               up->uart_dma.uart_base, 0, 0);
-               omap_set_dma_dest_params(up->uart_dma.rx_dma_channel, 0,
-                               OMAP_DMA_AMODE_POST_INC,
-                               up->uart_dma.rx_buf_dma_phys, 0, 0);
-               omap_set_dma_transfer_params(up->uart_dma.rx_dma_channel,
-                               OMAP_DMA_DATA_TYPE_S8,
-                               up->uart_dma.rx_buf_size, 1,
-                               OMAP_DMA_SYNC_ELEMENT,
-                               up->uart_dma.uart_dma_rx, 0);
-       }
-       up->uart_dma.prev_rx_dma_pos = up->uart_dma.rx_buf_dma_phys;
-       /* FIXME: Cache maintenance needed here? */
-       omap_start_dma(up->uart_dma.rx_dma_channel);
-       mod_timer(&up->uart_dma.rx_timer, jiffies +
-                               usecs_to_jiffies(up->uart_dma.rx_timeout));
-       up->uart_dma.rx_dma_used = true;
-       return ret;
-}
-
-static void serial_omap_continue_tx(struct uart_omap_port *up)
-{
-       struct circ_buf *xmit = &up->port.state->xmit;
-       unsigned int start = up->uart_dma.tx_buf_dma_phys
-                       + (xmit->tail & (UART_XMIT_SIZE - 1));
-
-       if (uart_circ_empty(xmit))
-               return;
-
-       up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit);
-       /*
-        * It is a circular buffer. See if the buffer has wounded back.
-        * If yes it will have to be transferred in two separate dma
-        * transfers
-        */
-       if (start + up->uart_dma.tx_buf_size >=
-                       up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE)
-               up->uart_dma.tx_buf_size =
-                       (up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE) - start;
-       omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0,
-                               OMAP_DMA_AMODE_CONSTANT,
-                               up->uart_dma.uart_base, 0, 0);
-       omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0,
-                               OMAP_DMA_AMODE_POST_INC, start, 0, 0);
-       omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel,
-                               OMAP_DMA_DATA_TYPE_S8,
-                               up->uart_dma.tx_buf_size, 1,
-                               OMAP_DMA_SYNC_ELEMENT,
-                               up->uart_dma.uart_dma_tx, 0);
-       /* FIXME: Cache maintenance needed here? */
-       omap_start_dma(up->uart_dma.tx_dma_channel);
-}
-
-static void uart_tx_dma_callback(int lch, u16 ch_status, void *data)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)data;
-       struct circ_buf *xmit = &up->port.state->xmit;
-
-       xmit->tail = (xmit->tail + up->uart_dma.tx_buf_size) & \
-                       (UART_XMIT_SIZE - 1);
-       up->port.icount.tx += up->uart_dma.tx_buf_size;
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&up->port);
-
-       if (uart_circ_empty(xmit)) {
-               spin_lock(&(up->uart_dma.tx_lock));
-               serial_omap_stop_tx(&up->port);
-               up->uart_dma.tx_dma_used = false;
-               spin_unlock(&(up->uart_dma.tx_lock));
-       } else {
-               omap_stop_dma(up->uart_dma.tx_dma_channel);
-               serial_omap_continue_tx(up);
-       }
-       up->port_activity = jiffies;
-       return;
-}
-
-static int serial_omap_probe(struct platform_device *pdev)
-{
-       struct uart_omap_port   *up;
-       struct resource         *mem, *irq, *dma_tx, *dma_rx;
-       struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data;
-       int ret = -ENOSPC;
-
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!mem) {
-               dev_err(&pdev->dev, "no mem resource?\n");
-               return -ENODEV;
-       }
-
-       irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!irq) {
-               dev_err(&pdev->dev, "no irq resource?\n");
-               return -ENODEV;
-       }
-
-       if (!request_mem_region(mem->start, (mem->end - mem->start) + 1,
-                                    pdev->dev.driver->name)) {
-               dev_err(&pdev->dev, "memory region already claimed\n");
-               return -EBUSY;
-       }
-
-       dma_rx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
-       if (!dma_rx) {
-               ret = -EINVAL;
-               goto err;
-       }
-
-       dma_tx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
-       if (!dma_tx) {
-               ret = -EINVAL;
-               goto err;
-       }
-
-       up = kzalloc(sizeof(*up), GFP_KERNEL);
-       if (up == NULL) {
-               ret = -ENOMEM;
-               goto do_release_region;
-       }
-       sprintf(up->name, "OMAP UART%d", pdev->id);
-       up->pdev = pdev;
-       up->port.dev = &pdev->dev;
-       up->port.type = PORT_OMAP;
-       up->port.iotype = UPIO_MEM;
-       up->port.irq = irq->start;
-
-       up->port.regshift = 2;
-       up->port.fifosize = 64;
-       up->port.ops = &serial_omap_pops;
-       up->port.line = pdev->id;
-
-       up->port.membase = omap_up_info->membase;
-       up->port.mapbase = omap_up_info->mapbase;
-       up->port.flags = omap_up_info->flags;
-       up->port.irqflags = omap_up_info->irqflags;
-       up->port.uartclk = omap_up_info->uartclk;
-       up->uart_dma.uart_base = mem->start;
-
-       if (omap_up_info->dma_enabled) {
-               up->uart_dma.uart_dma_tx = dma_tx->start;
-               up->uart_dma.uart_dma_rx = dma_rx->start;
-               up->use_dma = 1;
-               up->uart_dma.rx_buf_size = 4096;
-               up->uart_dma.rx_timeout = 2;
-               spin_lock_init(&(up->uart_dma.tx_lock));
-               spin_lock_init(&(up->uart_dma.rx_lock));
-               up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE;
-               up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
-       }
-
-       ui[pdev->id] = up;
-       serial_omap_add_console_port(up);
-
-       ret = uart_add_one_port(&serial_omap_reg, &up->port);
-       if (ret != 0)
-               goto do_release_region;
-
-       platform_set_drvdata(pdev, up);
-       return 0;
-err:
-       dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n",
-                               pdev->id, __func__, ret);
-do_release_region:
-       release_mem_region(mem->start, (mem->end - mem->start) + 1);
-       return ret;
-}
-
-static int serial_omap_remove(struct platform_device *dev)
-{
-       struct uart_omap_port *up = platform_get_drvdata(dev);
-
-       platform_set_drvdata(dev, NULL);
-       if (up) {
-               uart_remove_one_port(&serial_omap_reg, &up->port);
-               kfree(up);
-       }
-       return 0;
-}
-
-static struct platform_driver serial_omap_driver = {
-       .probe          = serial_omap_probe,
-       .remove         = serial_omap_remove,
-
-       .suspend        = serial_omap_suspend,
-       .resume         = serial_omap_resume,
-       .driver         = {
-               .name   = DRIVER_NAME,
-       },
-};
-
-static int __init serial_omap_init(void)
-{
-       int ret;
-
-       ret = uart_register_driver(&serial_omap_reg);
-       if (ret != 0)
-               return ret;
-       ret = platform_driver_register(&serial_omap_driver);
-       if (ret != 0)
-               uart_unregister_driver(&serial_omap_reg);
-       return ret;
-}
-
-static void __exit serial_omap_exit(void)
-{
-       platform_driver_unregister(&serial_omap_driver);
-       uart_unregister_driver(&serial_omap_reg);
-}
-
-module_init(serial_omap_init);
-module_exit(serial_omap_exit);
-
-MODULE_DESCRIPTION("OMAP High Speed UART driver");
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Texas Instruments Inc");
diff --git a/drivers/serial/pch_uart.c b/drivers/serial/pch_uart.c
deleted file mode 100644 (file)
index 70a6145..0000000
+++ /dev/null
@@ -1,1451 +0,0 @@
-/*
- *Copyright (C) 2010 OKI SEMICONDUCTOR CO., 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; version 2 of the License.
- *
- *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/serial_reg.h>
-#include <linux/pci.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/serial_core.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-
-#include <linux/dmaengine.h>
-#include <linux/pch_dma.h>
-
-enum {
-       PCH_UART_HANDLED_RX_INT_SHIFT,
-       PCH_UART_HANDLED_TX_INT_SHIFT,
-       PCH_UART_HANDLED_RX_ERR_INT_SHIFT,
-       PCH_UART_HANDLED_RX_TRG_INT_SHIFT,
-       PCH_UART_HANDLED_MS_INT_SHIFT,
-};
-
-enum {
-       PCH_UART_8LINE,
-       PCH_UART_2LINE,
-};
-
-#define PCH_UART_DRIVER_DEVICE "ttyPCH"
-
-#define PCH_UART_NR_GE_256FIFO         1
-#define PCH_UART_NR_GE_64FIFO          3
-#define PCH_UART_NR_GE (PCH_UART_NR_GE_256FIFO+PCH_UART_NR_GE_64FIFO)
-#define PCH_UART_NR    PCH_UART_NR_GE
-
-#define PCH_UART_HANDLED_RX_INT        (1<<((PCH_UART_HANDLED_RX_INT_SHIFT)<<1))
-#define PCH_UART_HANDLED_TX_INT        (1<<((PCH_UART_HANDLED_TX_INT_SHIFT)<<1))
-#define PCH_UART_HANDLED_RX_ERR_INT    (1<<((\
-                                       PCH_UART_HANDLED_RX_ERR_INT_SHIFT)<<1))
-#define PCH_UART_HANDLED_RX_TRG_INT    (1<<((\
-                                       PCH_UART_HANDLED_RX_TRG_INT_SHIFT)<<1))
-#define PCH_UART_HANDLED_MS_INT        (1<<((PCH_UART_HANDLED_MS_INT_SHIFT)<<1))
-
-#define PCH_UART_RBR           0x00
-#define PCH_UART_THR           0x00
-
-#define PCH_UART_IER_MASK      (PCH_UART_IER_ERBFI|PCH_UART_IER_ETBEI|\
-                               PCH_UART_IER_ELSI|PCH_UART_IER_EDSSI)
-#define PCH_UART_IER_ERBFI     0x00000001
-#define PCH_UART_IER_ETBEI     0x00000002
-#define PCH_UART_IER_ELSI      0x00000004
-#define PCH_UART_IER_EDSSI     0x00000008
-
-#define PCH_UART_IIR_IP                        0x00000001
-#define PCH_UART_IIR_IID               0x00000006
-#define PCH_UART_IIR_MSI               0x00000000
-#define PCH_UART_IIR_TRI               0x00000002
-#define PCH_UART_IIR_RRI               0x00000004
-#define PCH_UART_IIR_REI               0x00000006
-#define PCH_UART_IIR_TOI               0x00000008
-#define PCH_UART_IIR_FIFO256           0x00000020
-#define PCH_UART_IIR_FIFO64            PCH_UART_IIR_FIFO256
-#define PCH_UART_IIR_FE                        0x000000C0
-
-#define PCH_UART_FCR_FIFOE             0x00000001
-#define PCH_UART_FCR_RFR               0x00000002
-#define PCH_UART_FCR_TFR               0x00000004
-#define PCH_UART_FCR_DMS               0x00000008
-#define PCH_UART_FCR_FIFO256           0x00000020
-#define PCH_UART_FCR_RFTL              0x000000C0
-
-#define PCH_UART_FCR_RFTL1             0x00000000
-#define PCH_UART_FCR_RFTL64            0x00000040
-#define PCH_UART_FCR_RFTL128           0x00000080
-#define PCH_UART_FCR_RFTL224           0x000000C0
-#define PCH_UART_FCR_RFTL16            PCH_UART_FCR_RFTL64
-#define PCH_UART_FCR_RFTL32            PCH_UART_FCR_RFTL128
-#define PCH_UART_FCR_RFTL56            PCH_UART_FCR_RFTL224
-#define PCH_UART_FCR_RFTL4             PCH_UART_FCR_RFTL64
-#define PCH_UART_FCR_RFTL8             PCH_UART_FCR_RFTL128
-#define PCH_UART_FCR_RFTL14            PCH_UART_FCR_RFTL224
-#define PCH_UART_FCR_RFTL_SHIFT                6
-
-#define PCH_UART_LCR_WLS       0x00000003
-#define PCH_UART_LCR_STB       0x00000004
-#define PCH_UART_LCR_PEN       0x00000008
-#define PCH_UART_LCR_EPS       0x00000010
-#define PCH_UART_LCR_SP                0x00000020
-#define PCH_UART_LCR_SB                0x00000040
-#define PCH_UART_LCR_DLAB      0x00000080
-#define PCH_UART_LCR_NP                0x00000000
-#define PCH_UART_LCR_OP                PCH_UART_LCR_PEN
-#define PCH_UART_LCR_EP                (PCH_UART_LCR_PEN | PCH_UART_LCR_EPS)
-#define PCH_UART_LCR_1P                (PCH_UART_LCR_PEN | PCH_UART_LCR_SP)
-#define PCH_UART_LCR_0P                (PCH_UART_LCR_PEN | PCH_UART_LCR_EPS |\
-                               PCH_UART_LCR_SP)
-
-#define PCH_UART_LCR_5BIT      0x00000000
-#define PCH_UART_LCR_6BIT      0x00000001
-#define PCH_UART_LCR_7BIT      0x00000002
-#define PCH_UART_LCR_8BIT      0x00000003
-
-#define PCH_UART_MCR_DTR       0x00000001
-#define PCH_UART_MCR_RTS       0x00000002
-#define PCH_UART_MCR_OUT       0x0000000C
-#define PCH_UART_MCR_LOOP      0x00000010
-#define PCH_UART_MCR_AFE       0x00000020
-
-#define PCH_UART_LSR_DR                0x00000001
-#define PCH_UART_LSR_ERR       (1<<7)
-
-#define PCH_UART_MSR_DCTS      0x00000001
-#define PCH_UART_MSR_DDSR      0x00000002
-#define PCH_UART_MSR_TERI      0x00000004
-#define PCH_UART_MSR_DDCD      0x00000008
-#define PCH_UART_MSR_CTS       0x00000010
-#define PCH_UART_MSR_DSR       0x00000020
-#define PCH_UART_MSR_RI                0x00000040
-#define PCH_UART_MSR_DCD       0x00000080
-#define PCH_UART_MSR_DELTA     (PCH_UART_MSR_DCTS | PCH_UART_MSR_DDSR |\
-                               PCH_UART_MSR_TERI | PCH_UART_MSR_DDCD)
-
-#define PCH_UART_DLL           0x00
-#define PCH_UART_DLM           0x01
-
-#define DIV_ROUND(a, b)        (((a) + ((b)/2)) / (b))
-
-#define PCH_UART_IID_RLS       (PCH_UART_IIR_REI)
-#define PCH_UART_IID_RDR       (PCH_UART_IIR_RRI)
-#define PCH_UART_IID_RDR_TO    (PCH_UART_IIR_RRI | PCH_UART_IIR_TOI)
-#define PCH_UART_IID_THRE      (PCH_UART_IIR_TRI)
-#define PCH_UART_IID_MS                (PCH_UART_IIR_MSI)
-
-#define PCH_UART_HAL_PARITY_NONE       (PCH_UART_LCR_NP)
-#define PCH_UART_HAL_PARITY_ODD                (PCH_UART_LCR_OP)
-#define PCH_UART_HAL_PARITY_EVEN       (PCH_UART_LCR_EP)
-#define PCH_UART_HAL_PARITY_FIX1       (PCH_UART_LCR_1P)
-#define PCH_UART_HAL_PARITY_FIX0       (PCH_UART_LCR_0P)
-#define PCH_UART_HAL_5BIT              (PCH_UART_LCR_5BIT)
-#define PCH_UART_HAL_6BIT              (PCH_UART_LCR_6BIT)
-#define PCH_UART_HAL_7BIT              (PCH_UART_LCR_7BIT)
-#define PCH_UART_HAL_8BIT              (PCH_UART_LCR_8BIT)
-#define PCH_UART_HAL_STB1              0
-#define PCH_UART_HAL_STB2              (PCH_UART_LCR_STB)
-
-#define PCH_UART_HAL_CLR_TX_FIFO       (PCH_UART_FCR_TFR)
-#define PCH_UART_HAL_CLR_RX_FIFO       (PCH_UART_FCR_RFR)
-#define PCH_UART_HAL_CLR_ALL_FIFO      (PCH_UART_HAL_CLR_TX_FIFO | \
-                                       PCH_UART_HAL_CLR_RX_FIFO)
-
-#define PCH_UART_HAL_DMA_MODE0         0
-#define PCH_UART_HAL_FIFO_DIS          0
-#define PCH_UART_HAL_FIFO16            (PCH_UART_FCR_FIFOE)
-#define PCH_UART_HAL_FIFO256           (PCH_UART_FCR_FIFOE | \
-                                       PCH_UART_FCR_FIFO256)
-#define PCH_UART_HAL_FIFO64            (PCH_UART_HAL_FIFO256)
-#define PCH_UART_HAL_TRIGGER1          (PCH_UART_FCR_RFTL1)
-#define PCH_UART_HAL_TRIGGER64         (PCH_UART_FCR_RFTL64)
-#define PCH_UART_HAL_TRIGGER128                (PCH_UART_FCR_RFTL128)
-#define PCH_UART_HAL_TRIGGER224                (PCH_UART_FCR_RFTL224)
-#define PCH_UART_HAL_TRIGGER16         (PCH_UART_FCR_RFTL16)
-#define PCH_UART_HAL_TRIGGER32         (PCH_UART_FCR_RFTL32)
-#define PCH_UART_HAL_TRIGGER56         (PCH_UART_FCR_RFTL56)
-#define PCH_UART_HAL_TRIGGER4          (PCH_UART_FCR_RFTL4)
-#define PCH_UART_HAL_TRIGGER8          (PCH_UART_FCR_RFTL8)
-#define PCH_UART_HAL_TRIGGER14         (PCH_UART_FCR_RFTL14)
-#define PCH_UART_HAL_TRIGGER_L         (PCH_UART_FCR_RFTL64)
-#define PCH_UART_HAL_TRIGGER_M         (PCH_UART_FCR_RFTL128)
-#define PCH_UART_HAL_TRIGGER_H         (PCH_UART_FCR_RFTL224)
-
-#define PCH_UART_HAL_RX_INT            (PCH_UART_IER_ERBFI)
-#define PCH_UART_HAL_TX_INT            (PCH_UART_IER_ETBEI)
-#define PCH_UART_HAL_RX_ERR_INT                (PCH_UART_IER_ELSI)
-#define PCH_UART_HAL_MS_INT            (PCH_UART_IER_EDSSI)
-#define PCH_UART_HAL_ALL_INT           (PCH_UART_IER_MASK)
-
-#define PCH_UART_HAL_DTR               (PCH_UART_MCR_DTR)
-#define PCH_UART_HAL_RTS               (PCH_UART_MCR_RTS)
-#define PCH_UART_HAL_OUT               (PCH_UART_MCR_OUT)
-#define PCH_UART_HAL_LOOP              (PCH_UART_MCR_LOOP)
-#define PCH_UART_HAL_AFE               (PCH_UART_MCR_AFE)
-
-struct pch_uart_buffer {
-       unsigned char *buf;
-       int size;
-};
-
-struct eg20t_port {
-       struct uart_port port;
-       int port_type;
-       void __iomem *membase;
-       resource_size_t mapbase;
-       unsigned int iobase;
-       struct pci_dev *pdev;
-       int fifo_size;
-       int base_baud;
-       int start_tx;
-       int start_rx;
-       int tx_empty;
-       int int_dis_flag;
-       int trigger;
-       int trigger_level;
-       struct pch_uart_buffer rxbuf;
-       unsigned int dmsr;
-       unsigned int fcr;
-       unsigned int use_dma;
-       unsigned int use_dma_flag;
-       struct dma_async_tx_descriptor  *desc_tx;
-       struct dma_async_tx_descriptor  *desc_rx;
-       struct pch_dma_slave            param_tx;
-       struct pch_dma_slave            param_rx;
-       struct dma_chan                 *chan_tx;
-       struct dma_chan                 *chan_rx;
-       struct scatterlist              sg_tx;
-       struct scatterlist              sg_rx;
-       int                             tx_dma_use;
-       void                            *rx_buf_virt;
-       dma_addr_t                      rx_buf_dma;
-};
-
-static unsigned int default_baud = 9600;
-static const int trigger_level_256[4] = { 1, 64, 128, 224 };
-static const int trigger_level_64[4] = { 1, 16, 32, 56 };
-static const int trigger_level_16[4] = { 1, 4, 8, 14 };
-static const int trigger_level_1[4] = { 1, 1, 1, 1 };
-
-static void pch_uart_hal_request(struct pci_dev *pdev, int fifosize,
-                                int base_baud)
-{
-       struct eg20t_port *priv = pci_get_drvdata(pdev);
-
-       priv->trigger_level = 1;
-       priv->fcr = 0;
-}
-
-static unsigned int get_msr(struct eg20t_port *priv, void __iomem *base)
-{
-       unsigned int msr = ioread8(base + UART_MSR);
-       priv->dmsr |= msr & PCH_UART_MSR_DELTA;
-
-       return msr;
-}
-
-static void pch_uart_hal_enable_interrupt(struct eg20t_port *priv,
-                                         unsigned int flag)
-{
-       u8 ier = ioread8(priv->membase + UART_IER);
-       ier |= flag & PCH_UART_IER_MASK;
-       iowrite8(ier, priv->membase + UART_IER);
-}
-
-static void pch_uart_hal_disable_interrupt(struct eg20t_port *priv,
-                                          unsigned int flag)
-{
-       u8 ier = ioread8(priv->membase + UART_IER);
-       ier &= ~(flag & PCH_UART_IER_MASK);
-       iowrite8(ier, priv->membase + UART_IER);
-}
-
-static int pch_uart_hal_set_line(struct eg20t_port *priv, int baud,
-                                unsigned int parity, unsigned int bits,
-                                unsigned int stb)
-{
-       unsigned int dll, dlm, lcr;
-       int div;
-
-       div = DIV_ROUND(priv->base_baud / 16, baud);
-       if (div < 0 || USHRT_MAX <= div) {
-               pr_err("Invalid Baud(div=0x%x)\n", div);
-               return -EINVAL;
-       }
-
-       dll = (unsigned int)div & 0x00FFU;
-       dlm = ((unsigned int)div >> 8) & 0x00FFU;
-
-       if (parity & ~(PCH_UART_LCR_PEN | PCH_UART_LCR_EPS | PCH_UART_LCR_SP)) {
-               pr_err("Invalid parity(0x%x)\n", parity);
-               return -EINVAL;
-       }
-
-       if (bits & ~PCH_UART_LCR_WLS) {
-               pr_err("Invalid bits(0x%x)\n", bits);
-               return -EINVAL;
-       }
-
-       if (stb & ~PCH_UART_LCR_STB) {
-               pr_err("Invalid STB(0x%x)\n", stb);
-               return -EINVAL;
-       }
-
-       lcr = parity;
-       lcr |= bits;
-       lcr |= stb;
-
-       pr_debug("%s:baud = %d, div = %04x, lcr = %02x (%lu)\n",
-                __func__, baud, div, lcr, jiffies);
-       iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR);
-       iowrite8(dll, priv->membase + PCH_UART_DLL);
-       iowrite8(dlm, priv->membase + PCH_UART_DLM);
-       iowrite8(lcr, priv->membase + UART_LCR);
-
-       return 0;
-}
-
-static int pch_uart_hal_fifo_reset(struct eg20t_port *priv,
-                                   unsigned int flag)
-{
-       if (flag & ~(PCH_UART_FCR_TFR | PCH_UART_FCR_RFR)) {
-               pr_err("%s:Invalid flag(0x%x)\n", __func__, flag);
-               return -EINVAL;
-       }
-
-       iowrite8(PCH_UART_FCR_FIFOE | priv->fcr, priv->membase + UART_FCR);
-       iowrite8(PCH_UART_FCR_FIFOE | priv->fcr | flag,
-                priv->membase + UART_FCR);
-       iowrite8(priv->fcr, priv->membase + UART_FCR);
-
-       return 0;
-}
-
-static int pch_uart_hal_set_fifo(struct eg20t_port *priv,
-                                unsigned int dmamode,
-                                unsigned int fifo_size, unsigned int trigger)
-{
-       u8 fcr;
-
-       if (dmamode & ~PCH_UART_FCR_DMS) {
-               pr_err("%s:Invalid DMA Mode(0x%x)\n", __func__, dmamode);
-               return -EINVAL;
-       }
-
-       if (fifo_size & ~(PCH_UART_FCR_FIFOE | PCH_UART_FCR_FIFO256)) {
-               pr_err("%s:Invalid FIFO SIZE(0x%x)\n", __func__, fifo_size);
-               return -EINVAL;
-       }
-
-       if (trigger & ~PCH_UART_FCR_RFTL) {
-               pr_err("%s:Invalid TRIGGER(0x%x)\n", __func__, trigger);
-               return -EINVAL;
-       }
-
-       switch (priv->fifo_size) {
-       case 256:
-               priv->trigger_level =
-                   trigger_level_256[trigger >> PCH_UART_FCR_RFTL_SHIFT];
-               break;
-       case 64:
-               priv->trigger_level =
-                   trigger_level_64[trigger >> PCH_UART_FCR_RFTL_SHIFT];
-               break;
-       case 16:
-               priv->trigger_level =
-                   trigger_level_16[trigger >> PCH_UART_FCR_RFTL_SHIFT];
-               break;
-       default:
-               priv->trigger_level =
-                   trigger_level_1[trigger >> PCH_UART_FCR_RFTL_SHIFT];
-               break;
-       }
-       fcr =
-           dmamode | fifo_size | trigger | PCH_UART_FCR_RFR | PCH_UART_FCR_TFR;
-       iowrite8(PCH_UART_FCR_FIFOE, priv->membase + UART_FCR);
-       iowrite8(PCH_UART_FCR_FIFOE | PCH_UART_FCR_RFR | PCH_UART_FCR_TFR,
-                priv->membase + UART_FCR);
-       iowrite8(fcr, priv->membase + UART_FCR);
-       priv->fcr = fcr;
-
-       return 0;
-}
-
-static u8 pch_uart_hal_get_modem(struct eg20t_port *priv)
-{
-       priv->dmsr = 0;
-       return get_msr(priv, priv->membase);
-}
-
-static int pch_uart_hal_write(struct eg20t_port *priv,
-                             const unsigned char *buf, int tx_size)
-{
-       int i;
-       unsigned int thr;
-
-       for (i = 0; i < tx_size;) {
-               thr = buf[i++];
-               iowrite8(thr, priv->membase + PCH_UART_THR);
-       }
-       return i;
-}
-
-static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf,
-                            int rx_size)
-{
-       int i;
-       u8 rbr, lsr;
-
-       lsr = ioread8(priv->membase + UART_LSR);
-       for (i = 0, lsr = ioread8(priv->membase + UART_LSR);
-            i < rx_size && lsr & UART_LSR_DR;
-            lsr = ioread8(priv->membase + UART_LSR)) {
-               rbr = ioread8(priv->membase + PCH_UART_RBR);
-               buf[i++] = rbr;
-       }
-       return i;
-}
-
-static unsigned int pch_uart_hal_get_iid(struct eg20t_port *priv)
-{
-       unsigned int iir;
-       int ret;
-
-       iir = ioread8(priv->membase + UART_IIR);
-       ret = (iir & (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP));
-       return ret;
-}
-
-static u8 pch_uart_hal_get_line_status(struct eg20t_port *priv)
-{
-       return ioread8(priv->membase + UART_LSR);
-}
-
-static void pch_uart_hal_set_break(struct eg20t_port *priv, int on)
-{
-       unsigned int lcr;
-
-       lcr = ioread8(priv->membase + UART_LCR);
-       if (on)
-               lcr |= PCH_UART_LCR_SB;
-       else
-               lcr &= ~PCH_UART_LCR_SB;
-
-       iowrite8(lcr, priv->membase + UART_LCR);
-}
-
-static int push_rx(struct eg20t_port *priv, const unsigned char *buf,
-                  int size)
-{
-       struct uart_port *port;
-       struct tty_struct *tty;
-
-       port = &priv->port;
-       tty = tty_port_tty_get(&port->state->port);
-       if (!tty) {
-               pr_debug("%s:tty is busy now", __func__);
-               return -EBUSY;
-       }
-
-       tty_insert_flip_string(tty, buf, size);
-       tty_flip_buffer_push(tty);
-       tty_kref_put(tty);
-
-       return 0;
-}
-
-static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf)
-{
-       int ret;
-       struct uart_port *port = &priv->port;
-
-       if (port->x_char) {
-               pr_debug("%s:X character send %02x (%lu)\n", __func__,
-                       port->x_char, jiffies);
-               buf[0] = port->x_char;
-               port->x_char = 0;
-               ret = 1;
-       } else {
-               ret = 0;
-       }
-
-       return ret;
-}
-
-static int dma_push_rx(struct eg20t_port *priv, int size)
-{
-       struct tty_struct *tty;
-       int room;
-       struct uart_port *port = &priv->port;
-
-       port = &priv->port;
-       tty = tty_port_tty_get(&port->state->port);
-       if (!tty) {
-               pr_debug("%s:tty is busy now", __func__);
-               return 0;
-       }
-
-       room = tty_buffer_request_room(tty, size);
-
-       if (room < size)
-               dev_warn(port->dev, "Rx overrun: dropping %u bytes\n",
-                        size - room);
-       if (!room)
-               return room;
-
-       tty_insert_flip_string(tty, sg_virt(&priv->sg_rx), size);
-
-       port->icount.rx += room;
-       tty_kref_put(tty);
-
-       return room;
-}
-
-static void pch_free_dma(struct uart_port *port)
-{
-       struct eg20t_port *priv;
-       priv = container_of(port, struct eg20t_port, port);
-
-       if (priv->chan_tx) {
-               dma_release_channel(priv->chan_tx);
-               priv->chan_tx = NULL;
-       }
-       if (priv->chan_rx) {
-               dma_release_channel(priv->chan_rx);
-               priv->chan_rx = NULL;
-       }
-       if (sg_dma_address(&priv->sg_rx))
-               dma_free_coherent(port->dev, port->fifosize,
-                                 sg_virt(&priv->sg_rx),
-                                 sg_dma_address(&priv->sg_rx));
-
-       return;
-}
-
-static bool filter(struct dma_chan *chan, void *slave)
-{
-       struct pch_dma_slave *param = slave;
-
-       if ((chan->chan_id == param->chan_id) && (param->dma_dev ==
-                                                 chan->device->dev)) {
-               chan->private = param;
-               return true;
-       } else {
-               return false;
-       }
-}
-
-static void pch_request_dma(struct uart_port *port)
-{
-       dma_cap_mask_t mask;
-       struct dma_chan *chan;
-       struct pci_dev *dma_dev;
-       struct pch_dma_slave *param;
-       struct eg20t_port *priv =
-                               container_of(port, struct eg20t_port, port);
-       dma_cap_zero(mask);
-       dma_cap_set(DMA_SLAVE, mask);
-
-       dma_dev = pci_get_bus_and_slot(2, PCI_DEVFN(0xa, 0)); /* Get DMA's dev
-                                                               information */
-       /* Set Tx DMA */
-       param = &priv->param_tx;
-       param->dma_dev = &dma_dev->dev;
-       param->chan_id = priv->port.line;
-       param->tx_reg = port->mapbase + UART_TX;
-       chan = dma_request_channel(mask, filter, param);
-       if (!chan) {
-               pr_err("%s:dma_request_channel FAILS(Tx)\n", __func__);
-               return;
-       }
-       priv->chan_tx = chan;
-
-       /* Set Rx DMA */
-       param = &priv->param_rx;
-       param->dma_dev = &dma_dev->dev;
-       param->chan_id = priv->port.line + 1; /* Rx = Tx + 1 */
-       param->rx_reg = port->mapbase + UART_RX;
-       chan = dma_request_channel(mask, filter, param);
-       if (!chan) {
-               pr_err("%s:dma_request_channel FAILS(Rx)\n", __func__);
-               dma_release_channel(priv->chan_tx);
-               return;
-       }
-
-       /* Get Consistent memory for DMA */
-       priv->rx_buf_virt = dma_alloc_coherent(port->dev, port->fifosize,
-                                   &priv->rx_buf_dma, GFP_KERNEL);
-       priv->chan_rx = chan;
-}
-
-static void pch_dma_rx_complete(void *arg)
-{
-       struct eg20t_port *priv = arg;
-       struct uart_port *port = &priv->port;
-       struct tty_struct *tty = tty_port_tty_get(&port->state->port);
-
-       if (!tty) {
-               pr_debug("%s:tty is busy now", __func__);
-               return;
-       }
-
-       if (dma_push_rx(priv, priv->trigger_level))
-               tty_flip_buffer_push(tty);
-
-       tty_kref_put(tty);
-}
-
-static void pch_dma_tx_complete(void *arg)
-{
-       struct eg20t_port *priv = arg;
-       struct uart_port *port = &priv->port;
-       struct circ_buf *xmit = &port->state->xmit;
-
-       xmit->tail += sg_dma_len(&priv->sg_tx);
-       xmit->tail &= UART_XMIT_SIZE - 1;
-       port->icount.tx += sg_dma_len(&priv->sg_tx);
-
-       async_tx_ack(priv->desc_tx);
-       priv->tx_dma_use = 0;
-}
-
-static int pop_tx(struct eg20t_port *priv, unsigned char *buf, int size)
-{
-       int count = 0;
-       struct uart_port *port = &priv->port;
-       struct circ_buf *xmit = &port->state->xmit;
-
-       if (uart_tx_stopped(port) || uart_circ_empty(xmit) || count >= size)
-               goto pop_tx_end;
-
-       do {
-               int cnt_to_end =
-                   CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
-               int sz = min(size - count, cnt_to_end);
-               memcpy(&buf[count], &xmit->buf[xmit->tail], sz);
-               xmit->tail = (xmit->tail + sz) & (UART_XMIT_SIZE - 1);
-               count += sz;
-       } while (!uart_circ_empty(xmit) && count < size);
-
-pop_tx_end:
-       pr_debug("%d characters. Remained %d characters. (%lu)\n",
-                count, size - count, jiffies);
-
-       return count;
-}
-
-static int handle_rx_to(struct eg20t_port *priv)
-{
-       struct pch_uart_buffer *buf;
-       int rx_size;
-       int ret;
-       if (!priv->start_rx) {
-               pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT);
-               return 0;
-       }
-       buf = &priv->rxbuf;
-       do {
-               rx_size = pch_uart_hal_read(priv, buf->buf, buf->size);
-               ret = push_rx(priv, buf->buf, rx_size);
-               if (ret)
-                       return 0;
-       } while (rx_size == buf->size);
-
-       return PCH_UART_HANDLED_RX_INT;
-}
-
-static int handle_rx(struct eg20t_port *priv)
-{
-       return handle_rx_to(priv);
-}
-
-static int dma_handle_rx(struct eg20t_port *priv)
-{
-       struct uart_port *port = &priv->port;
-       struct dma_async_tx_descriptor *desc;
-       struct scatterlist *sg;
-
-       priv = container_of(port, struct eg20t_port, port);
-       sg = &priv->sg_rx;
-
-       sg_init_table(&priv->sg_rx, 1); /* Initialize SG table */
-
-       sg_dma_len(sg) = priv->fifo_size;
-
-       sg_set_page(&priv->sg_rx, virt_to_page(priv->rx_buf_virt),
-                    sg_dma_len(sg), (unsigned long)priv->rx_buf_virt &
-                    ~PAGE_MASK);
-
-       sg_dma_address(sg) = priv->rx_buf_dma;
-
-       desc = priv->chan_rx->device->device_prep_slave_sg(priv->chan_rx,
-                       sg, 1, DMA_FROM_DEVICE,
-                       DMA_PREP_INTERRUPT);
-       if (!desc)
-               return 0;
-
-       priv->desc_rx = desc;
-       desc->callback = pch_dma_rx_complete;
-       desc->callback_param = priv;
-       desc->tx_submit(desc);
-       dma_async_issue_pending(priv->chan_rx);
-
-       return PCH_UART_HANDLED_RX_INT;
-}
-
-static unsigned int handle_tx(struct eg20t_port *priv)
-{
-       struct uart_port *port = &priv->port;
-       struct circ_buf *xmit = &port->state->xmit;
-       int ret;
-       int fifo_size;
-       int tx_size;
-       int size;
-       int tx_empty;
-
-       if (!priv->start_tx) {
-               pr_info("%s:Tx isn't started. (%lu)\n", __func__, jiffies);
-               pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
-               priv->tx_empty = 1;
-               return 0;
-       }
-
-       fifo_size = max(priv->fifo_size, 1);
-       tx_empty = 1;
-       if (pop_tx_x(priv, xmit->buf)) {
-               pch_uart_hal_write(priv, xmit->buf, 1);
-               port->icount.tx++;
-               tx_empty = 0;
-               fifo_size--;
-       }
-       size = min(xmit->head - xmit->tail, fifo_size);
-       tx_size = pop_tx(priv, xmit->buf, size);
-       if (tx_size > 0) {
-               ret = pch_uart_hal_write(priv, xmit->buf, tx_size);
-               port->icount.tx += ret;
-               tx_empty = 0;
-       }
-
-       priv->tx_empty = tx_empty;
-
-       if (tx_empty)
-               pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
-
-       return PCH_UART_HANDLED_TX_INT;
-}
-
-static unsigned int dma_handle_tx(struct eg20t_port *priv)
-{
-       struct uart_port *port = &priv->port;
-       struct circ_buf *xmit = &port->state->xmit;
-       struct scatterlist *sg = &priv->sg_tx;
-       int nent;
-       int fifo_size;
-       int tx_empty;
-       struct dma_async_tx_descriptor *desc;
-
-       if (!priv->start_tx) {
-               pr_info("%s:Tx isn't started. (%lu)\n", __func__, jiffies);
-               pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
-               priv->tx_empty = 1;
-               return 0;
-       }
-
-       fifo_size = max(priv->fifo_size, 1);
-       tx_empty = 1;
-       if (pop_tx_x(priv, xmit->buf)) {
-               pch_uart_hal_write(priv, xmit->buf, 1);
-               port->icount.tx++;
-               tx_empty = 0;
-               fifo_size--;
-       }
-
-       pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
-
-       priv->tx_dma_use = 1;
-
-       sg_init_table(&priv->sg_tx, 1); /* Initialize SG table */
-
-       sg_set_page(&priv->sg_tx, virt_to_page(xmit->buf),
-                   UART_XMIT_SIZE, (int)xmit->buf & ~PAGE_MASK);
-
-       nent = dma_map_sg(port->dev, &priv->sg_tx, 1, DMA_TO_DEVICE);
-       if (!nent) {
-               pr_err("%s:dma_map_sg Failed\n", __func__);
-               return 0;
-       }
-
-       sg->offset = xmit->tail & (UART_XMIT_SIZE - 1);
-       sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) +
-                             sg->offset;
-       sg_dma_len(sg) = min((int)CIRC_CNT(xmit->head, xmit->tail,
-                            UART_XMIT_SIZE), CIRC_CNT_TO_END(xmit->head,
-                            xmit->tail, UART_XMIT_SIZE));
-
-       desc = priv->chan_tx->device->device_prep_slave_sg(priv->chan_tx,
-               sg, nent, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-       if (!desc) {
-               pr_err("%s:device_prep_slave_sg Failed\n", __func__);
-               return 0;
-       }
-
-       dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE);
-
-       priv->desc_tx = desc;
-       desc->callback = pch_dma_tx_complete;
-       desc->callback_param = priv;
-
-       desc->tx_submit(desc);
-
-       dma_async_issue_pending(priv->chan_tx);
-
-       return PCH_UART_HANDLED_TX_INT;
-}
-
-static void pch_uart_err_ir(struct eg20t_port *priv, unsigned int lsr)
-{
-       u8 fcr = ioread8(priv->membase + UART_FCR);
-
-       /* Reset FIFO */
-       fcr |= UART_FCR_CLEAR_RCVR;
-       iowrite8(fcr, priv->membase + UART_FCR);
-
-       if (lsr & PCH_UART_LSR_ERR)
-               dev_err(&priv->pdev->dev, "Error data in FIFO\n");
-
-       if (lsr & UART_LSR_FE)
-               dev_err(&priv->pdev->dev, "Framing Error\n");
-
-       if (lsr & UART_LSR_PE)
-               dev_err(&priv->pdev->dev, "Parity Error\n");
-
-       if (lsr & UART_LSR_OE)
-               dev_err(&priv->pdev->dev, "Overrun Error\n");
-}
-
-static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
-{
-       struct eg20t_port *priv = dev_id;
-       unsigned int handled;
-       u8 lsr;
-       int ret = 0;
-       unsigned int iid;
-       unsigned long flags;
-
-       spin_lock_irqsave(&priv->port.lock, flags);
-       handled = 0;
-       while ((iid = pch_uart_hal_get_iid(priv)) > 1) {
-               switch (iid) {
-               case PCH_UART_IID_RLS:  /* Receiver Line Status */
-                       lsr = pch_uart_hal_get_line_status(priv);
-                       if (lsr & (PCH_UART_LSR_ERR | UART_LSR_FE |
-                                               UART_LSR_PE | UART_LSR_OE)) {
-                               pch_uart_err_ir(priv, lsr);
-                               ret = PCH_UART_HANDLED_RX_ERR_INT;
-                       }
-                       break;
-               case PCH_UART_IID_RDR:  /* Received Data Ready */
-                       if (priv->use_dma)
-                               ret = dma_handle_rx(priv);
-                       else
-                               ret = handle_rx(priv);
-                       break;
-               case PCH_UART_IID_RDR_TO:       /* Received Data Ready
-                                                  (FIFO Timeout) */
-                       ret = handle_rx_to(priv);
-                       break;
-               case PCH_UART_IID_THRE: /* Transmitter Holding Register
-                                                  Empty */
-                       if (priv->use_dma)
-                               ret = dma_handle_tx(priv);
-                       else
-                               ret = handle_tx(priv);
-                       break;
-               case PCH_UART_IID_MS:   /* Modem Status */
-                       ret = PCH_UART_HANDLED_MS_INT;
-                       break;
-               default:        /* Never junp to this label */
-                       pr_err("%s:iid=%d (%lu)\n", __func__, iid, jiffies);
-                       ret = -1;
-                       break;
-               }
-               handled |= (unsigned int)ret;
-       }
-       if (handled == 0 && iid <= 1) {
-               if (priv->int_dis_flag)
-                       priv->int_dis_flag = 0;
-       }
-
-       spin_unlock_irqrestore(&priv->port.lock, flags);
-       return IRQ_RETVAL(handled);
-}
-
-/* This function tests whether the transmitter fifo and shifter for the port
-                                               described by 'port' is empty. */
-static unsigned int pch_uart_tx_empty(struct uart_port *port)
-{
-       struct eg20t_port *priv;
-       int ret;
-       priv = container_of(port, struct eg20t_port, port);
-       if (priv->tx_empty)
-               ret = TIOCSER_TEMT;
-       else
-               ret = 0;
-
-       return ret;
-}
-
-/* Returns the current state of modem control inputs. */
-static unsigned int pch_uart_get_mctrl(struct uart_port *port)
-{
-       struct eg20t_port *priv;
-       u8 modem;
-       unsigned int ret = 0;
-
-       priv = container_of(port, struct eg20t_port, port);
-       modem = pch_uart_hal_get_modem(priv);
-
-       if (modem & UART_MSR_DCD)
-               ret |= TIOCM_CAR;
-
-       if (modem & UART_MSR_RI)
-               ret |= TIOCM_RNG;
-
-       if (modem & UART_MSR_DSR)
-               ret |= TIOCM_DSR;
-
-       if (modem & UART_MSR_CTS)
-               ret |= TIOCM_CTS;
-
-       return ret;
-}
-
-static void pch_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       u32 mcr = 0;
-       unsigned int dat;
-       struct eg20t_port *priv = container_of(port, struct eg20t_port, port);
-
-       if (mctrl & TIOCM_DTR)
-               mcr |= UART_MCR_DTR;
-       if (mctrl & TIOCM_RTS)
-               mcr |= UART_MCR_RTS;
-       if (mctrl & TIOCM_LOOP)
-               mcr |= UART_MCR_LOOP;
-
-       if (mctrl) {
-               dat = pch_uart_get_mctrl(port);
-               dat |= mcr;
-               iowrite8(dat, priv->membase + UART_MCR);
-       }
-}
-
-static void pch_uart_stop_tx(struct uart_port *port)
-{
-       struct eg20t_port *priv;
-       priv = container_of(port, struct eg20t_port, port);
-       priv->start_tx = 0;
-       priv->tx_dma_use = 0;
-}
-
-static void pch_uart_start_tx(struct uart_port *port)
-{
-       struct eg20t_port *priv;
-
-       priv = container_of(port, struct eg20t_port, port);
-
-       if (priv->use_dma)
-               if (priv->tx_dma_use)
-                       return;
-
-       priv->start_tx = 1;
-       pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_TX_INT);
-}
-
-static void pch_uart_stop_rx(struct uart_port *port)
-{
-       struct eg20t_port *priv;
-       priv = container_of(port, struct eg20t_port, port);
-       priv->start_rx = 0;
-       pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT);
-       priv->int_dis_flag = 1;
-}
-
-/* Enable the modem status interrupts. */
-static void pch_uart_enable_ms(struct uart_port *port)
-{
-       struct eg20t_port *priv;
-       priv = container_of(port, struct eg20t_port, port);
-       pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_MS_INT);
-}
-
-/* Control the transmission of a break signal. */
-static void pch_uart_break_ctl(struct uart_port *port, int ctl)
-{
-       struct eg20t_port *priv;
-       unsigned long flags;
-
-       priv = container_of(port, struct eg20t_port, port);
-       spin_lock_irqsave(&port->lock, flags);
-       pch_uart_hal_set_break(priv, ctl);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/* Grab any interrupt resources and initialise any low level driver state. */
-static int pch_uart_startup(struct uart_port *port)
-{
-       struct eg20t_port *priv;
-       int ret;
-       int fifo_size;
-       int trigger_level;
-
-       priv = container_of(port, struct eg20t_port, port);
-       priv->tx_empty = 1;
-       port->uartclk = priv->base_baud;
-       pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT);
-       ret = pch_uart_hal_set_line(priv, default_baud,
-                             PCH_UART_HAL_PARITY_NONE, PCH_UART_HAL_8BIT,
-                             PCH_UART_HAL_STB1);
-       if (ret)
-               return ret;
-
-       switch (priv->fifo_size) {
-       case 256:
-               fifo_size = PCH_UART_HAL_FIFO256;
-               break;
-       case 64:
-               fifo_size = PCH_UART_HAL_FIFO64;
-               break;
-       case 16:
-               fifo_size = PCH_UART_HAL_FIFO16;
-       case 1:
-       default:
-               fifo_size = PCH_UART_HAL_FIFO_DIS;
-               break;
-       }
-
-       switch (priv->trigger) {
-       case PCH_UART_HAL_TRIGGER1:
-               trigger_level = 1;
-               break;
-       case PCH_UART_HAL_TRIGGER_L:
-               trigger_level = priv->fifo_size / 4;
-               break;
-       case PCH_UART_HAL_TRIGGER_M:
-               trigger_level = priv->fifo_size / 2;
-               break;
-       case PCH_UART_HAL_TRIGGER_H:
-       default:
-               trigger_level = priv->fifo_size - (priv->fifo_size / 8);
-               break;
-       }
-
-       priv->trigger_level = trigger_level;
-       ret = pch_uart_hal_set_fifo(priv, PCH_UART_HAL_DMA_MODE0,
-                                   fifo_size, priv->trigger);
-       if (ret < 0)
-               return ret;
-
-       ret = request_irq(priv->port.irq, pch_uart_interrupt, IRQF_SHARED,
-                       KBUILD_MODNAME, priv);
-       if (ret < 0)
-               return ret;
-
-       if (priv->use_dma)
-               pch_request_dma(port);
-
-       priv->start_rx = 1;
-       pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT);
-       uart_update_timeout(port, CS8, default_baud);
-
-       return 0;
-}
-
-static void pch_uart_shutdown(struct uart_port *port)
-{
-       struct eg20t_port *priv;
-       int ret;
-
-       priv = container_of(port, struct eg20t_port, port);
-       pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT);
-       pch_uart_hal_fifo_reset(priv, PCH_UART_HAL_CLR_ALL_FIFO);
-       ret = pch_uart_hal_set_fifo(priv, PCH_UART_HAL_DMA_MODE0,
-                             PCH_UART_HAL_FIFO_DIS, PCH_UART_HAL_TRIGGER1);
-       if (ret)
-               pr_err("pch_uart_hal_set_fifo Failed(ret=%d)\n", ret);
-
-       if (priv->use_dma_flag)
-               pch_free_dma(port);
-
-       free_irq(priv->port.irq, priv);
-}
-
-/* Change the port parameters, including word length, parity, stop
- *bits.  Update read_status_mask and ignore_status_mask to indicate
- *the types of events we are interested in receiving.  */
-static void pch_uart_set_termios(struct uart_port *port,
-                                struct ktermios *termios, struct ktermios *old)
-{
-       int baud;
-       int rtn;
-       unsigned int parity, bits, stb;
-       struct eg20t_port *priv;
-       unsigned long flags;
-
-       priv = container_of(port, struct eg20t_port, port);
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               bits = PCH_UART_HAL_5BIT;
-               break;
-       case CS6:
-               bits = PCH_UART_HAL_6BIT;
-               break;
-       case CS7:
-               bits = PCH_UART_HAL_7BIT;
-               break;
-       default:                /* CS8 */
-               bits = PCH_UART_HAL_8BIT;
-               break;
-       }
-       if (termios->c_cflag & CSTOPB)
-               stb = PCH_UART_HAL_STB2;
-       else
-               stb = PCH_UART_HAL_STB1;
-
-       if (termios->c_cflag & PARENB) {
-               if (!(termios->c_cflag & PARODD))
-                       parity = PCH_UART_HAL_PARITY_ODD;
-               else
-                       parity = PCH_UART_HAL_PARITY_EVEN;
-
-       } else {
-               parity = PCH_UART_HAL_PARITY_NONE;
-       }
-       termios->c_cflag &= ~CMSPAR; /* Mark/Space parity is not supported */
-
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       uart_update_timeout(port, termios->c_cflag, baud);
-       rtn = pch_uart_hal_set_line(priv, baud, parity, bits, stb);
-       if (rtn)
-               goto out;
-
-       /* Don't rewrite B0 */
-       if (tty_termios_baud_rate(termios))
-               tty_termios_encode_baud_rate(termios, baud, baud);
-
-out:
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *pch_uart_type(struct uart_port *port)
-{
-       return KBUILD_MODNAME;
-}
-
-static void pch_uart_release_port(struct uart_port *port)
-{
-       struct eg20t_port *priv;
-
-       priv = container_of(port, struct eg20t_port, port);
-       pci_iounmap(priv->pdev, priv->membase);
-       pci_release_regions(priv->pdev);
-}
-
-static int pch_uart_request_port(struct uart_port *port)
-{
-       struct eg20t_port *priv;
-       int ret;
-       void __iomem *membase;
-
-       priv = container_of(port, struct eg20t_port, port);
-       ret = pci_request_regions(priv->pdev, KBUILD_MODNAME);
-       if (ret < 0)
-               return -EBUSY;
-
-       membase = pci_iomap(priv->pdev, 1, 0);
-       if (!membase) {
-               pci_release_regions(priv->pdev);
-               return -EBUSY;
-       }
-       priv->membase = port->membase = membase;
-
-       return 0;
-}
-
-static void pch_uart_config_port(struct uart_port *port, int type)
-{
-       struct eg20t_port *priv;
-
-       priv = container_of(port, struct eg20t_port, port);
-       if (type & UART_CONFIG_TYPE) {
-               port->type = priv->port_type;
-               pch_uart_request_port(port);
-       }
-}
-
-static int pch_uart_verify_port(struct uart_port *port,
-                               struct serial_struct *serinfo)
-{
-       struct eg20t_port *priv;
-
-       priv = container_of(port, struct eg20t_port, port);
-       if (serinfo->flags & UPF_LOW_LATENCY) {
-               pr_info("PCH UART : Use PIO Mode (without DMA)\n");
-               priv->use_dma = 0;
-               serinfo->flags &= ~UPF_LOW_LATENCY;
-       } else {
-#ifndef CONFIG_PCH_DMA
-               pr_err("%s : PCH DMA is not Loaded.\n", __func__);
-               return -EOPNOTSUPP;
-#endif
-               priv->use_dma = 1;
-               priv->use_dma_flag = 1;
-               pr_info("PCH UART : Use DMA Mode\n");
-       }
-
-       return 0;
-}
-
-static struct uart_ops pch_uart_ops = {
-       .tx_empty = pch_uart_tx_empty,
-       .set_mctrl = pch_uart_set_mctrl,
-       .get_mctrl = pch_uart_get_mctrl,
-       .stop_tx = pch_uart_stop_tx,
-       .start_tx = pch_uart_start_tx,
-       .stop_rx = pch_uart_stop_rx,
-       .enable_ms = pch_uart_enable_ms,
-       .break_ctl = pch_uart_break_ctl,
-       .startup = pch_uart_startup,
-       .shutdown = pch_uart_shutdown,
-       .set_termios = pch_uart_set_termios,
-/*     .pm             = pch_uart_pm,          Not supported yet */
-/*     .set_wake       = pch_uart_set_wake,    Not supported yet */
-       .type = pch_uart_type,
-       .release_port = pch_uart_release_port,
-       .request_port = pch_uart_request_port,
-       .config_port = pch_uart_config_port,
-       .verify_port = pch_uart_verify_port
-};
-
-static struct uart_driver pch_uart_driver = {
-       .owner = THIS_MODULE,
-       .driver_name = KBUILD_MODNAME,
-       .dev_name = PCH_UART_DRIVER_DEVICE,
-       .major = 0,
-       .minor = 0,
-       .nr = PCH_UART_NR,
-};
-
-static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
-                                               int port_type)
-{
-       struct eg20t_port *priv;
-       int ret;
-       unsigned int iobase;
-       unsigned int mapbase;
-       unsigned char *rxbuf;
-       int fifosize, base_baud;
-       static int num;
-
-       priv = kzalloc(sizeof(struct eg20t_port), GFP_KERNEL);
-       if (priv == NULL)
-               goto init_port_alloc_err;
-
-       rxbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
-       if (!rxbuf)
-               goto init_port_free_txbuf;
-
-       switch (port_type) {
-       case PORT_UNKNOWN:
-               fifosize = 256; /* UART0 */
-               base_baud = 1843200; /* 1.8432MHz */
-               break;
-       case PORT_8250:
-               fifosize = 64; /* UART1~3 */
-               base_baud = 1843200; /* 1.8432MHz */
-               break;
-       default:
-               dev_err(&pdev->dev, "Invalid Port Type(=%d)\n", port_type);
-               goto init_port_hal_free;
-       }
-
-       iobase = pci_resource_start(pdev, 0);
-       mapbase = pci_resource_start(pdev, 1);
-       priv->mapbase = mapbase;
-       priv->iobase = iobase;
-       priv->pdev = pdev;
-       priv->tx_empty = 1;
-       priv->rxbuf.buf = rxbuf;
-       priv->rxbuf.size = PAGE_SIZE;
-
-       priv->fifo_size = fifosize;
-       priv->base_baud = base_baud;
-       priv->port_type = PORT_MAX_8250 + port_type + 1;
-       priv->port.dev = &pdev->dev;
-       priv->port.iobase = iobase;
-       priv->port.membase = NULL;
-       priv->port.mapbase = mapbase;
-       priv->port.irq = pdev->irq;
-       priv->port.iotype = UPIO_PORT;
-       priv->port.ops = &pch_uart_ops;
-       priv->port.flags = UPF_BOOT_AUTOCONF;
-       priv->port.fifosize = fifosize;
-       priv->port.line = num++;
-       priv->trigger = PCH_UART_HAL_TRIGGER_M;
-
-       pci_set_drvdata(pdev, priv);
-       pch_uart_hal_request(pdev, fifosize, base_baud);
-       ret = uart_add_one_port(&pch_uart_driver, &priv->port);
-       if (ret < 0)
-               goto init_port_hal_free;
-
-       return priv;
-
-init_port_hal_free:
-       free_page((unsigned long)rxbuf);
-init_port_free_txbuf:
-       kfree(priv);
-init_port_alloc_err:
-
-       return NULL;
-}
-
-static void pch_uart_exit_port(struct eg20t_port *priv)
-{
-       uart_remove_one_port(&pch_uart_driver, &priv->port);
-       pci_set_drvdata(priv->pdev, NULL);
-       free_page((unsigned long)priv->rxbuf.buf);
-}
-
-static void pch_uart_pci_remove(struct pci_dev *pdev)
-{
-       struct eg20t_port *priv;
-
-       priv = (struct eg20t_port *)pci_get_drvdata(pdev);
-       pch_uart_exit_port(priv);
-       pci_disable_device(pdev);
-       kfree(priv);
-       return;
-}
-#ifdef CONFIG_PM
-static int pch_uart_pci_suspend(struct pci_dev *pdev, pm_message_t state)
-{
-       struct eg20t_port *priv = pci_get_drvdata(pdev);
-
-       uart_suspend_port(&pch_uart_driver, &priv->port);
-
-       pci_save_state(pdev);
-       pci_set_power_state(pdev, pci_choose_state(pdev, state));
-       return 0;
-}
-
-static int pch_uart_pci_resume(struct pci_dev *pdev)
-{
-       struct eg20t_port *priv = pci_get_drvdata(pdev);
-       int ret;
-
-       pci_set_power_state(pdev, PCI_D0);
-       pci_restore_state(pdev);
-
-       ret = pci_enable_device(pdev);
-       if (ret) {
-               dev_err(&pdev->dev,
-               "%s-pci_enable_device failed(ret=%d) ", __func__, ret);
-               return ret;
-       }
-
-       uart_resume_port(&pch_uart_driver, &priv->port);
-
-       return 0;
-}
-#else
-#define pch_uart_pci_suspend NULL
-#define pch_uart_pci_resume NULL
-#endif
-
-static DEFINE_PCI_DEVICE_TABLE(pch_uart_pci_id) = {
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8811),
-        .driver_data = PCH_UART_8LINE},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8812),
-        .driver_data = PCH_UART_2LINE},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8813),
-        .driver_data = PCH_UART_2LINE},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8814),
-        .driver_data = PCH_UART_2LINE},
-       {0,},
-};
-
-static int __devinit pch_uart_pci_probe(struct pci_dev *pdev,
-                                       const struct pci_device_id *id)
-{
-       int ret;
-       struct eg20t_port *priv;
-
-       ret = pci_enable_device(pdev);
-       if (ret < 0)
-               goto probe_error;
-
-       priv = pch_uart_init_port(pdev, id->driver_data);
-       if (!priv) {
-               ret = -EBUSY;
-               goto probe_disable_device;
-       }
-       pci_set_drvdata(pdev, priv);
-
-       return ret;
-
-probe_disable_device:
-       pci_disable_device(pdev);
-probe_error:
-       return ret;
-}
-
-static struct pci_driver pch_uart_pci_driver = {
-       .name = "pch_uart",
-       .id_table = pch_uart_pci_id,
-       .probe = pch_uart_pci_probe,
-       .remove = __devexit_p(pch_uart_pci_remove),
-       .suspend = pch_uart_pci_suspend,
-       .resume = pch_uart_pci_resume,
-};
-
-static int __init pch_uart_module_init(void)
-{
-       int ret;
-
-       /* register as UART driver */
-       ret = uart_register_driver(&pch_uart_driver);
-       if (ret < 0)
-               return ret;
-
-       /* register as PCI driver */
-       ret = pci_register_driver(&pch_uart_pci_driver);
-       if (ret < 0)
-               uart_unregister_driver(&pch_uart_driver);
-
-       return ret;
-}
-module_init(pch_uart_module_init);
-
-static void __exit pch_uart_module_exit(void)
-{
-       pci_unregister_driver(&pch_uart_pci_driver);
-       uart_unregister_driver(&pch_uart_driver);
-}
-module_exit(pch_uart_module_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel EG20T PCH UART PCI Driver");
-module_param(default_baud, uint, S_IRUGO);
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
deleted file mode 100644 (file)
index 5b9cde7..0000000
+++ /dev/null
@@ -1,2208 +0,0 @@
-/*
- * linux/drivers/serial/pmac_zilog.c
- * 
- * Driver for PowerMac Z85c30 based ESCC cell found in the
- * "macio" ASICs of various PowerMac models
- * 
- * Copyright (C) 2003 Ben. Herrenschmidt (benh@kernel.crashing.org)
- *
- * Derived from drivers/macintosh/macserial.c by Paul Mackerras
- * and drivers/serial/sunzilog.c by David S. Miller
- *
- * Hrm... actually, I ripped most of sunzilog (Thanks David !) and
- * adapted special tweaks needed for us. I don't think it's worth
- * merging back those though. The DMA code still has to get in
- * and once done, I expect that driver to remain fairly stable in
- * the long term, unless we change the driver model again...
- *
- * 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
- *
- * 2004-08-06 Harald Welte <laforge@gnumonks.org>
- *     - Enable BREAK interrupt
- *     - Add support for sysreq
- *
- * TODO:   - Add DMA support
- *         - Defer port shutdown to a few seconds after close
- *         - maybe put something right into uap->clk_divisor
- */
-
-#undef DEBUG
-#undef DEBUG_HARD
-#undef USE_CTRL_O_SYSRQ
-
-#include <linux/module.h>
-#include <linux/tty.h>
-
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#include <linux/bitops.h>
-#include <linux/sysrq.h>
-#include <linux/mutex.h>
-#include <asm/sections.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#ifdef CONFIG_PPC_PMAC
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/dbdma.h>
-#include <asm/macio.h>
-#else
-#include <linux/platform_device.h>
-#define of_machine_is_compatible(x) (0)
-#endif
-
-#if defined (CONFIG_SERIAL_PMACZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-
-#include "pmac_zilog.h"
-
-/* Not yet implemented */
-#undef HAS_DBDMA
-
-static char version[] __initdata = "pmac_zilog: 0.6 (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
-MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
-MODULE_DESCRIPTION("Driver for the Mac and PowerMac serial ports.");
-MODULE_LICENSE("GPL");
-
-#ifdef CONFIG_SERIAL_PMACZILOG_TTYS
-#define PMACZILOG_MAJOR                TTY_MAJOR
-#define PMACZILOG_MINOR                64
-#define PMACZILOG_NAME         "ttyS"
-#else
-#define PMACZILOG_MAJOR                204
-#define PMACZILOG_MINOR                192
-#define PMACZILOG_NAME         "ttyPZ"
-#endif
-
-
-/*
- * For the sake of early serial console, we can do a pre-probe
- * (optional) of the ports at rather early boot time.
- */
-static struct uart_pmac_port   pmz_ports[MAX_ZS_PORTS];
-static int                     pmz_ports_count;
-static DEFINE_MUTEX(pmz_irq_mutex);
-
-static struct uart_driver pmz_uart_reg = {
-       .owner          =       THIS_MODULE,
-       .driver_name    =       PMACZILOG_NAME,
-       .dev_name       =       PMACZILOG_NAME,
-       .major          =       PMACZILOG_MAJOR,
-       .minor          =       PMACZILOG_MINOR,
-};
-
-
-/* 
- * Load all registers to reprogram the port
- * This function must only be called when the TX is not busy.  The UART
- * port lock must be held and local interrupts disabled.
- */
-static void pmz_load_zsregs(struct uart_pmac_port *uap, u8 *regs)
-{
-       int i;
-
-       if (ZS_IS_ASLEEP(uap))
-               return;
-
-       /* Let pending transmits finish.  */
-       for (i = 0; i < 1000; i++) {
-               unsigned char stat = read_zsreg(uap, R1);
-               if (stat & ALL_SNT)
-                       break;
-               udelay(100);
-       }
-
-       ZS_CLEARERR(uap);
-       zssync(uap);
-       ZS_CLEARFIFO(uap);
-       zssync(uap);
-       ZS_CLEARERR(uap);
-
-       /* Disable all interrupts.  */
-       write_zsreg(uap, R1,
-                   regs[R1] & ~(RxINT_MASK | TxINT_ENAB | EXT_INT_ENAB));
-
-       /* Set parity, sync config, stop bits, and clock divisor.  */
-       write_zsreg(uap, R4, regs[R4]);
-
-       /* Set misc. TX/RX control bits.  */
-       write_zsreg(uap, R10, regs[R10]);
-
-       /* Set TX/RX controls sans the enable bits.  */
-       write_zsreg(uap, R3, regs[R3] & ~RxENABLE);
-       write_zsreg(uap, R5, regs[R5] & ~TxENABLE);
-
-       /* now set R7 "prime" on ESCC */
-       write_zsreg(uap, R15, regs[R15] | EN85C30);
-       write_zsreg(uap, R7, regs[R7P]);
-
-       /* make sure we use R7 "non-prime" on ESCC */
-       write_zsreg(uap, R15, regs[R15] & ~EN85C30);
-
-       /* Synchronous mode config.  */
-       write_zsreg(uap, R6, regs[R6]);
-       write_zsreg(uap, R7, regs[R7]);
-
-       /* Disable baud generator.  */
-       write_zsreg(uap, R14, regs[R14] & ~BRENAB);
-
-       /* Clock mode control.  */
-       write_zsreg(uap, R11, regs[R11]);
-
-       /* Lower and upper byte of baud rate generator divisor.  */
-       write_zsreg(uap, R12, regs[R12]);
-       write_zsreg(uap, R13, regs[R13]);
-       
-       /* Now rewrite R14, with BRENAB (if set).  */
-       write_zsreg(uap, R14, regs[R14]);
-
-       /* Reset external status interrupts.  */
-       write_zsreg(uap, R0, RES_EXT_INT);
-       write_zsreg(uap, R0, RES_EXT_INT);
-
-       /* Rewrite R3/R5, this time without enables masked.  */
-       write_zsreg(uap, R3, regs[R3]);
-       write_zsreg(uap, R5, regs[R5]);
-
-       /* Rewrite R1, this time without IRQ enabled masked.  */
-       write_zsreg(uap, R1, regs[R1]);
-
-       /* Enable interrupts */
-       write_zsreg(uap, R9, regs[R9]);
-}
-
-/* 
- * We do like sunzilog to avoid disrupting pending Tx
- * Reprogram the Zilog channel HW registers with the copies found in the
- * software state struct.  If the transmitter is busy, we defer this update
- * until the next TX complete interrupt.  Else, we do it right now.
- *
- * The UART port lock must be held and local interrupts disabled.
- */
-static void pmz_maybe_update_regs(struct uart_pmac_port *uap)
-{
-       if (!ZS_REGS_HELD(uap)) {
-               if (ZS_TX_ACTIVE(uap)) {
-                       uap->flags |= PMACZILOG_FLAG_REGS_HELD;
-               } else {
-                       pmz_debug("pmz: maybe_update_regs: updating\n");
-                       pmz_load_zsregs(uap, uap->curregs);
-               }
-       }
-}
-
-static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
-{
-       struct tty_struct *tty = NULL;
-       unsigned char ch, r1, drop, error, flag;
-       int loops = 0;
-
-       /* The interrupt can be enabled when the port isn't open, typically
-        * that happens when using one port is open and the other closed (stale
-        * interrupt) or when one port is used as a console.
-        */
-       if (!ZS_IS_OPEN(uap)) {
-               pmz_debug("pmz: draining input\n");
-               /* Port is closed, drain input data */
-               for (;;) {
-                       if ((++loops) > 1000)
-                               goto flood;
-                       (void)read_zsreg(uap, R1);
-                       write_zsreg(uap, R0, ERR_RES);
-                       (void)read_zsdata(uap);
-                       ch = read_zsreg(uap, R0);
-                       if (!(ch & Rx_CH_AV))
-                               break;
-               }
-               return NULL;
-       }
-
-       /* Sanity check, make sure the old bug is no longer happening */
-       if (uap->port.state == NULL || uap->port.state->port.tty == NULL) {
-               WARN_ON(1);
-               (void)read_zsdata(uap);
-               return NULL;
-       }
-       tty = uap->port.state->port.tty;
-
-       while (1) {
-               error = 0;
-               drop = 0;
-
-               r1 = read_zsreg(uap, R1);
-               ch = read_zsdata(uap);
-
-               if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
-                       write_zsreg(uap, R0, ERR_RES);
-                       zssync(uap);
-               }
-
-               ch &= uap->parity_mask;
-               if (ch == 0 && uap->flags & PMACZILOG_FLAG_BREAK) {
-                       uap->flags &= ~PMACZILOG_FLAG_BREAK;
-               }
-
-#if defined(CONFIG_MAGIC_SYSRQ) && defined(CONFIG_SERIAL_CORE_CONSOLE)
-#ifdef USE_CTRL_O_SYSRQ
-               /* Handle the SysRq ^O Hack */
-               if (ch == '\x0f') {
-                       uap->port.sysrq = jiffies + HZ*5;
-                       goto next_char;
-               }
-#endif /* USE_CTRL_O_SYSRQ */
-               if (uap->port.sysrq) {
-                       int swallow;
-                       spin_unlock(&uap->port.lock);
-                       swallow = uart_handle_sysrq_char(&uap->port, ch);
-                       spin_lock(&uap->port.lock);
-                       if (swallow)
-                               goto next_char;
-               }
-#endif /* CONFIG_MAGIC_SYSRQ && CONFIG_SERIAL_CORE_CONSOLE */
-
-               /* A real serial line, record the character and status.  */
-               if (drop)
-                       goto next_char;
-
-               flag = TTY_NORMAL;
-               uap->port.icount.rx++;
-
-               if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | BRK_ABRT)) {
-                       error = 1;
-                       if (r1 & BRK_ABRT) {
-                               pmz_debug("pmz: got break !\n");
-                               r1 &= ~(PAR_ERR | CRC_ERR);
-                               uap->port.icount.brk++;
-                               if (uart_handle_break(&uap->port))
-                                       goto next_char;
-                       }
-                       else if (r1 & PAR_ERR)
-                               uap->port.icount.parity++;
-                       else if (r1 & CRC_ERR)
-                               uap->port.icount.frame++;
-                       if (r1 & Rx_OVR)
-                               uap->port.icount.overrun++;
-                       r1 &= uap->port.read_status_mask;
-                       if (r1 & BRK_ABRT)
-                               flag = TTY_BREAK;
-                       else if (r1 & PAR_ERR)
-                               flag = TTY_PARITY;
-                       else if (r1 & CRC_ERR)
-                               flag = TTY_FRAME;
-               }
-
-               if (uap->port.ignore_status_mask == 0xff ||
-                   (r1 & uap->port.ignore_status_mask) == 0) {
-                       tty_insert_flip_char(tty, ch, flag);
-               }
-               if (r1 & Rx_OVR)
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-       next_char:
-               /* We can get stuck in an infinite loop getting char 0 when the
-                * line is in a wrong HW state, we break that here.
-                * When that happens, I disable the receive side of the driver.
-                * Note that what I've been experiencing is a real irq loop where
-                * I'm getting flooded regardless of the actual port speed.
-                * Something stange is going on with the HW
-                */
-               if ((++loops) > 1000)
-                       goto flood;
-               ch = read_zsreg(uap, R0);
-               if (!(ch & Rx_CH_AV))
-                       break;
-       }
-
-       return tty;
- flood:
-       uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
-       write_zsreg(uap, R1, uap->curregs[R1]);
-       zssync(uap);
-       pmz_error("pmz: rx irq flood !\n");
-       return tty;
-}
-
-static void pmz_status_handle(struct uart_pmac_port *uap)
-{
-       unsigned char status;
-
-       status = read_zsreg(uap, R0);
-       write_zsreg(uap, R0, RES_EXT_INT);
-       zssync(uap);
-
-       if (ZS_IS_OPEN(uap) && ZS_WANTS_MODEM_STATUS(uap)) {
-               if (status & SYNC_HUNT)
-                       uap->port.icount.dsr++;
-
-               /* The Zilog just gives us an interrupt when DCD/CTS/etc. change.
-                * But it does not tell us which bit has changed, we have to keep
-                * track of this ourselves.
-                * The CTS input is inverted for some reason.  -- paulus
-                */
-               if ((status ^ uap->prev_status) & DCD)
-                       uart_handle_dcd_change(&uap->port,
-                                              (status & DCD));
-               if ((status ^ uap->prev_status) & CTS)
-                       uart_handle_cts_change(&uap->port,
-                                              !(status & CTS));
-
-               wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
-       }
-
-       if (status & BRK_ABRT)
-               uap->flags |= PMACZILOG_FLAG_BREAK;
-
-       uap->prev_status = status;
-}
-
-static void pmz_transmit_chars(struct uart_pmac_port *uap)
-{
-       struct circ_buf *xmit;
-
-       if (ZS_IS_ASLEEP(uap))
-               return;
-       if (ZS_IS_CONS(uap)) {
-               unsigned char status = read_zsreg(uap, R0);
-
-               /* TX still busy?  Just wait for the next TX done interrupt.
-                *
-                * It can occur because of how we do serial console writes.  It would
-                * be nice to transmit console writes just like we normally would for
-                * a TTY line. (ie. buffered and TX interrupt driven).  That is not
-                * easy because console writes cannot sleep.  One solution might be
-                * to poll on enough port->xmit space becomming free.  -DaveM
-                */
-               if (!(status & Tx_BUF_EMP))
-                       return;
-       }
-
-       uap->flags &= ~PMACZILOG_FLAG_TX_ACTIVE;
-
-       if (ZS_REGS_HELD(uap)) {
-               pmz_load_zsregs(uap, uap->curregs);
-               uap->flags &= ~PMACZILOG_FLAG_REGS_HELD;
-       }
-
-       if (ZS_TX_STOPPED(uap)) {
-               uap->flags &= ~PMACZILOG_FLAG_TX_STOPPED;
-               goto ack_tx_int;
-       }
-
-       /* Under some circumstances, we see interrupts reported for
-        * a closed channel. The interrupt mask in R1 is clear, but
-        * R3 still signals the interrupts and we see them when taking
-        * an interrupt for the other channel (this could be a qemu
-        * bug but since the ESCC doc doesn't specify precsiely whether
-        * R3 interrup status bits are masked by R1 interrupt enable
-        * bits, better safe than sorry). --BenH.
-        */
-       if (!ZS_IS_OPEN(uap))
-               goto ack_tx_int;
-
-       if (uap->port.x_char) {
-               uap->flags |= PMACZILOG_FLAG_TX_ACTIVE;
-               write_zsdata(uap, uap->port.x_char);
-               zssync(uap);
-               uap->port.icount.tx++;
-               uap->port.x_char = 0;
-               return;
-       }
-
-       if (uap->port.state == NULL)
-               goto ack_tx_int;
-       xmit = &uap->port.state->xmit;
-       if (uart_circ_empty(xmit)) {
-               uart_write_wakeup(&uap->port);
-               goto ack_tx_int;
-       }
-       if (uart_tx_stopped(&uap->port))
-               goto ack_tx_int;
-
-       uap->flags |= PMACZILOG_FLAG_TX_ACTIVE;
-       write_zsdata(uap, xmit->buf[xmit->tail]);
-       zssync(uap);
-
-       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-       uap->port.icount.tx++;
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&uap->port);
-
-       return;
-
-ack_tx_int:
-       write_zsreg(uap, R0, RES_Tx_P);
-       zssync(uap);
-}
-
-/* Hrm... we register that twice, fixme later.... */
-static irqreturn_t pmz_interrupt(int irq, void *dev_id)
-{
-       struct uart_pmac_port *uap = dev_id;
-       struct uart_pmac_port *uap_a;
-       struct uart_pmac_port *uap_b;
-       int rc = IRQ_NONE;
-       struct tty_struct *tty;
-       u8 r3;
-
-       uap_a = pmz_get_port_A(uap);
-       uap_b = uap_a->mate;
-
-       spin_lock(&uap_a->port.lock);
-       r3 = read_zsreg(uap_a, R3);
-
-#ifdef DEBUG_HARD
-       pmz_debug("irq, r3: %x\n", r3);
-#endif
-       /* Channel A */
-       tty = NULL;
-       if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
-               write_zsreg(uap_a, R0, RES_H_IUS);
-               zssync(uap_a);          
-               if (r3 & CHAEXT)
-                       pmz_status_handle(uap_a);
-               if (r3 & CHARxIP)
-                       tty = pmz_receive_chars(uap_a);
-               if (r3 & CHATxIP)
-                       pmz_transmit_chars(uap_a);
-               rc = IRQ_HANDLED;
-       }
-       spin_unlock(&uap_a->port.lock);
-       if (tty != NULL)
-               tty_flip_buffer_push(tty);
-
-       if (uap_b->node == NULL)
-               goto out;
-
-       spin_lock(&uap_b->port.lock);
-       tty = NULL;
-       if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
-               write_zsreg(uap_b, R0, RES_H_IUS);
-               zssync(uap_b);
-               if (r3 & CHBEXT)
-                       pmz_status_handle(uap_b);
-               if (r3 & CHBRxIP)
-                       tty = pmz_receive_chars(uap_b);
-               if (r3 & CHBTxIP)
-                       pmz_transmit_chars(uap_b);
-               rc = IRQ_HANDLED;
-       }
-       spin_unlock(&uap_b->port.lock);
-       if (tty != NULL)
-               tty_flip_buffer_push(tty);
-
- out:
-#ifdef DEBUG_HARD
-       pmz_debug("irq done.\n");
-#endif
-       return rc;
-}
-
-/*
- * Peek the status register, lock not held by caller
- */
-static inline u8 pmz_peek_status(struct uart_pmac_port *uap)
-{
-       unsigned long flags;
-       u8 status;
-       
-       spin_lock_irqsave(&uap->port.lock, flags);
-       status = read_zsreg(uap, R0);
-       spin_unlock_irqrestore(&uap->port.lock, flags);
-
-       return status;
-}
-
-/* 
- * Check if transmitter is empty
- * The port lock is not held.
- */
-static unsigned int pmz_tx_empty(struct uart_port *port)
-{
-       struct uart_pmac_port *uap = to_pmz(port);
-       unsigned char status;
-
-       if (ZS_IS_ASLEEP(uap) || uap->node == NULL)
-               return TIOCSER_TEMT;
-
-       status = pmz_peek_status(to_pmz(port));
-       if (status & Tx_BUF_EMP)
-               return TIOCSER_TEMT;
-       return 0;
-}
-
-/* 
- * Set Modem Control (RTS & DTR) bits
- * The port lock is held and interrupts are disabled.
- * Note: Shall we really filter out RTS on external ports or
- * should that be dealt at higher level only ?
- */
-static void pmz_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_pmac_port *uap = to_pmz(port);
-       unsigned char set_bits, clear_bits;
-
-        /* Do nothing for irda for now... */
-       if (ZS_IS_IRDA(uap))
-               return;
-       /* We get called during boot with a port not up yet */
-       if (ZS_IS_ASLEEP(uap) ||
-           !(ZS_IS_OPEN(uap) || ZS_IS_CONS(uap)))
-               return;
-
-       set_bits = clear_bits = 0;
-
-       if (ZS_IS_INTMODEM(uap)) {
-               if (mctrl & TIOCM_RTS)
-                       set_bits |= RTS;
-               else
-                       clear_bits |= RTS;
-       }
-       if (mctrl & TIOCM_DTR)
-               set_bits |= DTR;
-       else
-               clear_bits |= DTR;
-
-       /* NOTE: Not subject to 'transmitter active' rule.  */ 
-       uap->curregs[R5] |= set_bits;
-       uap->curregs[R5] &= ~clear_bits;
-       if (ZS_IS_ASLEEP(uap))
-               return;
-       write_zsreg(uap, R5, uap->curregs[R5]);
-       pmz_debug("pmz_set_mctrl: set bits: %x, clear bits: %x -> %x\n",
-                 set_bits, clear_bits, uap->curregs[R5]);
-       zssync(uap);
-}
-
-/* 
- * Get Modem Control bits (only the input ones, the core will
- * or that with a cached value of the control ones)
- * The port lock is held and interrupts are disabled.
- */
-static unsigned int pmz_get_mctrl(struct uart_port *port)
-{
-       struct uart_pmac_port *uap = to_pmz(port);
-       unsigned char status;
-       unsigned int ret;
-
-       if (ZS_IS_ASLEEP(uap) || uap->node == NULL)
-               return 0;
-
-       status = read_zsreg(uap, R0);
-
-       ret = 0;
-       if (status & DCD)
-               ret |= TIOCM_CAR;
-       if (status & SYNC_HUNT)
-               ret |= TIOCM_DSR;
-       if (!(status & CTS))
-               ret |= TIOCM_CTS;
-
-       return ret;
-}
-
-/* 
- * Stop TX side. Dealt like sunzilog at next Tx interrupt,
- * though for DMA, we will have to do a bit more.
- * The port lock is held and interrupts are disabled.
- */
-static void pmz_stop_tx(struct uart_port *port)
-{
-       to_pmz(port)->flags |= PMACZILOG_FLAG_TX_STOPPED;
-}
-
-/* 
- * Kick the Tx side.
- * The port lock is held and interrupts are disabled.
- */
-static void pmz_start_tx(struct uart_port *port)
-{
-       struct uart_pmac_port *uap = to_pmz(port);
-       unsigned char status;
-
-       pmz_debug("pmz: start_tx()\n");
-
-       uap->flags |= PMACZILOG_FLAG_TX_ACTIVE;
-       uap->flags &= ~PMACZILOG_FLAG_TX_STOPPED;
-
-       if (ZS_IS_ASLEEP(uap) || uap->node == NULL)
-               return;
-
-       status = read_zsreg(uap, R0);
-
-       /* TX busy?  Just wait for the TX done interrupt.  */
-       if (!(status & Tx_BUF_EMP))
-               return;
-
-       /* Send the first character to jump-start the TX done
-        * IRQ sending engine.
-        */
-       if (port->x_char) {
-               write_zsdata(uap, port->x_char);
-               zssync(uap);
-               port->icount.tx++;
-               port->x_char = 0;
-       } else {
-               struct circ_buf *xmit = &port->state->xmit;
-
-               write_zsdata(uap, xmit->buf[xmit->tail]);
-               zssync(uap);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-
-               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-                       uart_write_wakeup(&uap->port);
-       }
-       pmz_debug("pmz: start_tx() done.\n");
-}
-
-/* 
- * Stop Rx side, basically disable emitting of
- * Rx interrupts on the port. We don't disable the rx
- * side of the chip proper though
- * The port lock is held.
- */
-static void pmz_stop_rx(struct uart_port *port)
-{
-       struct uart_pmac_port *uap = to_pmz(port);
-
-       if (ZS_IS_ASLEEP(uap) || uap->node == NULL)
-               return;
-
-       pmz_debug("pmz: stop_rx()()\n");
-
-       /* Disable all RX interrupts.  */
-       uap->curregs[R1] &= ~RxINT_MASK;
-       pmz_maybe_update_regs(uap);
-
-       pmz_debug("pmz: stop_rx() done.\n");
-}
-
-/* 
- * Enable modem status change interrupts
- * The port lock is held.
- */
-static void pmz_enable_ms(struct uart_port *port)
-{
-       struct uart_pmac_port *uap = to_pmz(port);
-       unsigned char new_reg;
-
-       if (ZS_IS_IRDA(uap) || uap->node == NULL)
-               return;
-       new_reg = uap->curregs[R15] | (DCDIE | SYNCIE | CTSIE);
-       if (new_reg != uap->curregs[R15]) {
-               uap->curregs[R15] = new_reg;
-
-               if (ZS_IS_ASLEEP(uap))
-                       return;
-               /* NOTE: Not subject to 'transmitter active' rule. */
-               write_zsreg(uap, R15, uap->curregs[R15]);
-       }
-}
-
-/* 
- * Control break state emission
- * The port lock is not held.
- */
-static void pmz_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_pmac_port *uap = to_pmz(port);
-       unsigned char set_bits, clear_bits, new_reg;
-       unsigned long flags;
-
-       if (uap->node == NULL)
-               return;
-       set_bits = clear_bits = 0;
-
-       if (break_state)
-               set_bits |= SND_BRK;
-       else
-               clear_bits |= SND_BRK;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       new_reg = (uap->curregs[R5] | set_bits) & ~clear_bits;
-       if (new_reg != uap->curregs[R5]) {
-               uap->curregs[R5] = new_reg;
-
-               /* NOTE: Not subject to 'transmitter active' rule. */
-               if (ZS_IS_ASLEEP(uap)) {
-                       spin_unlock_irqrestore(&port->lock, flags);
-                       return;
-               }
-               write_zsreg(uap, R5, uap->curregs[R5]);
-       }
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-#ifdef CONFIG_PPC_PMAC
-
-/*
- * Turn power on or off to the SCC and associated stuff
- * (port drivers, modem, IR port, etc.)
- * Returns the number of milliseconds we should wait before
- * trying to use the port.
- */
-static int pmz_set_scc_power(struct uart_pmac_port *uap, int state)
-{
-       int delay = 0;
-       int rc;
-
-       if (state) {
-               rc = pmac_call_feature(
-                       PMAC_FTR_SCC_ENABLE, uap->node, uap->port_type, 1);
-               pmz_debug("port power on result: %d\n", rc);
-               if (ZS_IS_INTMODEM(uap)) {
-                       rc = pmac_call_feature(
-                               PMAC_FTR_MODEM_ENABLE, uap->node, 0, 1);
-                       delay = 2500;   /* wait for 2.5s before using */
-                       pmz_debug("modem power result: %d\n", rc);
-               }
-       } else {
-               /* TODO: Make that depend on a timer, don't power down
-                * immediately
-                */
-               if (ZS_IS_INTMODEM(uap)) {
-                       rc = pmac_call_feature(
-                               PMAC_FTR_MODEM_ENABLE, uap->node, 0, 0);
-                       pmz_debug("port power off result: %d\n", rc);
-               }
-               pmac_call_feature(PMAC_FTR_SCC_ENABLE, uap->node, uap->port_type, 0);
-       }
-       return delay;
-}
-
-#else
-
-static int pmz_set_scc_power(struct uart_pmac_port *uap, int state)
-{
-       return 0;
-}
-
-#endif /* !CONFIG_PPC_PMAC */
-
-/*
- * FixZeroBug....Works around a bug in the SCC receving channel.
- * Inspired from Darwin code, 15 Sept. 2000  -DanM
- *
- * The following sequence prevents a problem that is seen with O'Hare ASICs
- * (most versions -- also with some Heathrow and Hydra ASICs) where a zero
- * at the input to the receiver becomes 'stuck' and locks up the receiver.
- * This problem can occur as a result of a zero bit at the receiver input
- * coincident with any of the following events:
- *
- *     The SCC is initialized (hardware or software).
- *     A framing error is detected.
- *     The clocking option changes from synchronous or X1 asynchronous
- *             clocking to X16, X32, or X64 asynchronous clocking.
- *     The decoding mode is changed among NRZ, NRZI, FM0, or FM1.
- *
- * This workaround attempts to recover from the lockup condition by placing
- * the SCC in synchronous loopback mode with a fast clock before programming
- * any of the asynchronous modes.
- */
-static void pmz_fix_zero_bug_scc(struct uart_pmac_port *uap)
-{
-       write_zsreg(uap, 9, ZS_IS_CHANNEL_A(uap) ? CHRA : CHRB);
-       zssync(uap);
-       udelay(10);
-       write_zsreg(uap, 9, (ZS_IS_CHANNEL_A(uap) ? CHRA : CHRB) | NV);
-       zssync(uap);
-
-       write_zsreg(uap, 4, X1CLK | MONSYNC);
-       write_zsreg(uap, 3, Rx8);
-       write_zsreg(uap, 5, Tx8 | RTS);
-       write_zsreg(uap, 9, NV);        /* Didn't we already do this? */
-       write_zsreg(uap, 11, RCBR | TCBR);
-       write_zsreg(uap, 12, 0);
-       write_zsreg(uap, 13, 0);
-       write_zsreg(uap, 14, (LOOPBAK | BRSRC));
-       write_zsreg(uap, 14, (LOOPBAK | BRSRC | BRENAB));
-       write_zsreg(uap, 3, Rx8 | RxENABLE);
-       write_zsreg(uap, 0, RES_EXT_INT);
-       write_zsreg(uap, 0, RES_EXT_INT);
-       write_zsreg(uap, 0, RES_EXT_INT);       /* to kill some time */
-
-       /* The channel should be OK now, but it is probably receiving
-        * loopback garbage.
-        * Switch to asynchronous mode, disable the receiver,
-        * and discard everything in the receive buffer.
-        */
-       write_zsreg(uap, 9, NV);
-       write_zsreg(uap, 4, X16CLK | SB_MASK);
-       write_zsreg(uap, 3, Rx8);
-
-       while (read_zsreg(uap, 0) & Rx_CH_AV) {
-               (void)read_zsreg(uap, 8);
-               write_zsreg(uap, 0, RES_EXT_INT);
-               write_zsreg(uap, 0, ERR_RES);
-       }
-}
-
-/*
- * Real startup routine, powers up the hardware and sets up
- * the SCC. Returns a delay in ms where you need to wait before
- * actually using the port, this is typically the internal modem
- * powerup delay. This routine expect the lock to be taken.
- */
-static int __pmz_startup(struct uart_pmac_port *uap)
-{
-       int pwr_delay = 0;
-
-       memset(&uap->curregs, 0, sizeof(uap->curregs));
-
-       /* Power up the SCC & underlying hardware (modem/irda) */
-       pwr_delay = pmz_set_scc_power(uap, 1);
-
-       /* Nice buggy HW ... */
-       pmz_fix_zero_bug_scc(uap);
-
-       /* Reset the channel */
-       uap->curregs[R9] = 0;
-       write_zsreg(uap, 9, ZS_IS_CHANNEL_A(uap) ? CHRA : CHRB);
-       zssync(uap);
-       udelay(10);
-       write_zsreg(uap, 9, 0);
-       zssync(uap);
-
-       /* Clear the interrupt registers */
-       write_zsreg(uap, R1, 0);
-       write_zsreg(uap, R0, ERR_RES);
-       write_zsreg(uap, R0, ERR_RES);
-       write_zsreg(uap, R0, RES_H_IUS);
-       write_zsreg(uap, R0, RES_H_IUS);
-
-       /* Setup some valid baud rate */
-       uap->curregs[R4] = X16CLK | SB1;
-       uap->curregs[R3] = Rx8;
-       uap->curregs[R5] = Tx8 | RTS;
-       if (!ZS_IS_IRDA(uap))
-               uap->curregs[R5] |= DTR;
-       uap->curregs[R12] = 0;
-       uap->curregs[R13] = 0;
-       uap->curregs[R14] = BRENAB;
-
-       /* Clear handshaking, enable BREAK interrupts */
-       uap->curregs[R15] = BRKIE;
-
-       /* Master interrupt enable */
-       uap->curregs[R9] |= NV | MIE;
-
-       pmz_load_zsregs(uap, uap->curregs);
-
-       /* Enable receiver and transmitter.  */
-       write_zsreg(uap, R3, uap->curregs[R3] |= RxENABLE);
-       write_zsreg(uap, R5, uap->curregs[R5] |= TxENABLE);
-
-       /* Remember status for DCD/CTS changes */
-       uap->prev_status = read_zsreg(uap, R0);
-
-       return pwr_delay;
-}
-
-static void pmz_irda_reset(struct uart_pmac_port *uap)
-{
-       uap->curregs[R5] |= DTR;
-       write_zsreg(uap, R5, uap->curregs[R5]);
-       zssync(uap);
-       mdelay(110);
-       uap->curregs[R5] &= ~DTR;
-       write_zsreg(uap, R5, uap->curregs[R5]);
-       zssync(uap);
-       mdelay(10);
-}
-
-/*
- * This is the "normal" startup routine, using the above one
- * wrapped with the lock and doing a schedule delay
- */
-static int pmz_startup(struct uart_port *port)
-{
-       struct uart_pmac_port *uap = to_pmz(port);
-       unsigned long flags;
-       int pwr_delay = 0;
-
-       pmz_debug("pmz: startup()\n");
-
-       if (ZS_IS_ASLEEP(uap))
-               return -EAGAIN;
-       if (uap->node == NULL)
-               return -ENODEV;
-
-       mutex_lock(&pmz_irq_mutex);
-
-       uap->flags |= PMACZILOG_FLAG_IS_OPEN;
-
-       /* A console is never powered down. Else, power up and
-        * initialize the chip
-        */
-       if (!ZS_IS_CONS(uap)) {
-               spin_lock_irqsave(&port->lock, flags);
-               pwr_delay = __pmz_startup(uap);
-               spin_unlock_irqrestore(&port->lock, flags);
-       }       
-
-       pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON;
-       if (request_irq(uap->port.irq, pmz_interrupt, IRQF_SHARED,
-                       "SCC", uap)) {
-               pmz_error("Unable to register zs interrupt handler.\n");
-               pmz_set_scc_power(uap, 0);
-               mutex_unlock(&pmz_irq_mutex);
-               return -ENXIO;
-       }
-
-       mutex_unlock(&pmz_irq_mutex);
-
-       /* Right now, we deal with delay by blocking here, I'll be
-        * smarter later on
-        */
-       if (pwr_delay != 0) {
-               pmz_debug("pmz: delaying %d ms\n", pwr_delay);
-               msleep(pwr_delay);
-       }
-
-       /* IrDA reset is done now */
-       if (ZS_IS_IRDA(uap))
-               pmz_irda_reset(uap);
-
-       /* Enable interrupts emission from the chip */
-       spin_lock_irqsave(&port->lock, flags);
-       uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;
-       if (!ZS_IS_EXTCLK(uap))
-               uap->curregs[R1] |= EXT_INT_ENAB;
-       write_zsreg(uap, R1, uap->curregs[R1]);
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       pmz_debug("pmz: startup() done.\n");
-
-       return 0;
-}
-
-static void pmz_shutdown(struct uart_port *port)
-{
-       struct uart_pmac_port *uap = to_pmz(port);
-       unsigned long flags;
-
-       pmz_debug("pmz: shutdown()\n");
-
-       if (uap->node == NULL)
-               return;
-
-       mutex_lock(&pmz_irq_mutex);
-
-       /* Release interrupt handler */
-       free_irq(uap->port.irq, uap);
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       uap->flags &= ~PMACZILOG_FLAG_IS_OPEN;
-
-       if (!ZS_IS_OPEN(uap->mate))
-               pmz_get_port_A(uap)->flags &= ~PMACZILOG_FLAG_IS_IRQ_ON;
-
-       /* Disable interrupts */
-       if (!ZS_IS_ASLEEP(uap)) {
-               uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
-               write_zsreg(uap, R1, uap->curregs[R1]);
-               zssync(uap);
-       }
-
-       if (ZS_IS_CONS(uap) || ZS_IS_ASLEEP(uap)) {
-               spin_unlock_irqrestore(&port->lock, flags);
-               mutex_unlock(&pmz_irq_mutex);
-               return;
-       }
-
-       /* Disable receiver and transmitter.  */
-       uap->curregs[R3] &= ~RxENABLE;
-       uap->curregs[R5] &= ~TxENABLE;
-
-       /* Disable all interrupts and BRK assertion.  */
-       uap->curregs[R5] &= ~SND_BRK;
-       pmz_maybe_update_regs(uap);
-
-       /* Shut the chip down */
-       pmz_set_scc_power(uap, 0);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       mutex_unlock(&pmz_irq_mutex);
-
-       pmz_debug("pmz: shutdown() done.\n");
-}
-
-/* Shared by TTY driver and serial console setup.  The port lock is held
- * and local interrupts are disabled.
- */
-static void pmz_convert_to_zs(struct uart_pmac_port *uap, unsigned int cflag,
-                             unsigned int iflag, unsigned long baud)
-{
-       int brg;
-
-       /* Switch to external clocking for IrDA high clock rates. That
-        * code could be re-used for Midi interfaces with different
-        * multipliers
-        */
-       if (baud >= 115200 && ZS_IS_IRDA(uap)) {
-               uap->curregs[R4] = X1CLK;
-               uap->curregs[R11] = RCTRxCP | TCTRxCP;
-               uap->curregs[R14] = 0; /* BRG off */
-               uap->curregs[R12] = 0;
-               uap->curregs[R13] = 0;
-               uap->flags |= PMACZILOG_FLAG_IS_EXTCLK;
-       } else {
-               switch (baud) {
-               case ZS_CLOCK/16:       /* 230400 */
-                       uap->curregs[R4] = X16CLK;
-                       uap->curregs[R11] = 0;
-                       uap->curregs[R14] = 0;
-                       break;
-               case ZS_CLOCK/32:       /* 115200 */
-                       uap->curregs[R4] = X32CLK;
-                       uap->curregs[R11] = 0;
-                       uap->curregs[R14] = 0;
-                       break;
-               default:
-                       uap->curregs[R4] = X16CLK;
-                       uap->curregs[R11] = TCBR | RCBR;
-                       brg = BPS_TO_BRG(baud, ZS_CLOCK / 16);
-                       uap->curregs[R12] = (brg & 255);
-                       uap->curregs[R13] = ((brg >> 8) & 255);
-                       uap->curregs[R14] = BRENAB;
-               }
-               uap->flags &= ~PMACZILOG_FLAG_IS_EXTCLK;
-       }
-
-       /* Character size, stop bits, and parity. */
-       uap->curregs[3] &= ~RxN_MASK;
-       uap->curregs[5] &= ~TxN_MASK;
-
-       switch (cflag & CSIZE) {
-       case CS5:
-               uap->curregs[3] |= Rx5;
-               uap->curregs[5] |= Tx5;
-               uap->parity_mask = 0x1f;
-               break;
-       case CS6:
-               uap->curregs[3] |= Rx6;
-               uap->curregs[5] |= Tx6;
-               uap->parity_mask = 0x3f;
-               break;
-       case CS7:
-               uap->curregs[3] |= Rx7;
-               uap->curregs[5] |= Tx7;
-               uap->parity_mask = 0x7f;
-               break;
-       case CS8:
-       default:
-               uap->curregs[3] |= Rx8;
-               uap->curregs[5] |= Tx8;
-               uap->parity_mask = 0xff;
-               break;
-       };
-       uap->curregs[4] &= ~(SB_MASK);
-       if (cflag & CSTOPB)
-               uap->curregs[4] |= SB2;
-       else
-               uap->curregs[4] |= SB1;
-       if (cflag & PARENB)
-               uap->curregs[4] |= PAR_ENAB;
-       else
-               uap->curregs[4] &= ~PAR_ENAB;
-       if (!(cflag & PARODD))
-               uap->curregs[4] |= PAR_EVEN;
-       else
-               uap->curregs[4] &= ~PAR_EVEN;
-
-       uap->port.read_status_mask = Rx_OVR;
-       if (iflag & INPCK)
-               uap->port.read_status_mask |= CRC_ERR | PAR_ERR;
-       if (iflag & (BRKINT | PARMRK))
-               uap->port.read_status_mask |= BRK_ABRT;
-
-       uap->port.ignore_status_mask = 0;
-       if (iflag & IGNPAR)
-               uap->port.ignore_status_mask |= CRC_ERR | PAR_ERR;
-       if (iflag & IGNBRK) {
-               uap->port.ignore_status_mask |= BRK_ABRT;
-               if (iflag & IGNPAR)
-                       uap->port.ignore_status_mask |= Rx_OVR;
-       }
-
-       if ((cflag & CREAD) == 0)
-               uap->port.ignore_status_mask = 0xff;
-}
-
-
-/*
- * Set the irda codec on the imac to the specified baud rate.
- */
-static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud)
-{
-       u8 cmdbyte;
-       int t, version;
-
-       switch (*baud) {
-       /* SIR modes */
-       case 2400:
-               cmdbyte = 0x53;
-               break;
-       case 4800:
-               cmdbyte = 0x52;
-               break;
-       case 9600:
-               cmdbyte = 0x51;
-               break;
-       case 19200:
-               cmdbyte = 0x50;
-               break;
-       case 38400:
-               cmdbyte = 0x4f;
-               break;
-       case 57600:
-               cmdbyte = 0x4e;
-               break;
-       case 115200:
-               cmdbyte = 0x4d;
-               break;
-       /* The FIR modes aren't really supported at this point, how
-        * do we select the speed ? via the FCR on KeyLargo ?
-        */
-       case 1152000:
-               cmdbyte = 0;
-               break;
-       case 4000000:
-               cmdbyte = 0;
-               break;
-       default: /* 9600 */
-               cmdbyte = 0x51;
-               *baud = 9600;
-               break;
-       }
-
-       /* Wait for transmitter to drain */
-       t = 10000;
-       while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0
-              || (read_zsreg(uap, R1) & ALL_SNT) == 0) {
-               if (--t <= 0) {
-                       pmz_error("transmitter didn't drain\n");
-                       return;
-               }
-               udelay(10);
-       }
-
-       /* Drain the receiver too */
-       t = 100;
-       (void)read_zsdata(uap);
-       (void)read_zsdata(uap);
-       (void)read_zsdata(uap);
-       mdelay(10);
-       while (read_zsreg(uap, R0) & Rx_CH_AV) {
-               read_zsdata(uap);
-               mdelay(10);
-               if (--t <= 0) {
-                       pmz_error("receiver didn't drain\n");
-                       return;
-               }
-       }
-
-       /* Switch to command mode */
-       uap->curregs[R5] |= DTR;
-       write_zsreg(uap, R5, uap->curregs[R5]);
-       zssync(uap);
-       mdelay(1);
-
-       /* Switch SCC to 19200 */
-       pmz_convert_to_zs(uap, CS8, 0, 19200);          
-       pmz_load_zsregs(uap, uap->curregs);
-       mdelay(1);
-
-       /* Write get_version command byte */
-       write_zsdata(uap, 1);
-       t = 5000;
-       while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) {
-               if (--t <= 0) {
-                       pmz_error("irda_setup timed out on get_version byte\n");
-                       goto out;
-               }
-               udelay(10);
-       }
-       version = read_zsdata(uap);
-
-       if (version < 4) {
-               pmz_info("IrDA: dongle version %d not supported\n", version);
-               goto out;
-       }
-
-       /* Send speed mode */
-       write_zsdata(uap, cmdbyte);
-       t = 5000;
-       while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) {
-               if (--t <= 0) {
-                       pmz_error("irda_setup timed out on speed mode byte\n");
-                       goto out;
-               }
-               udelay(10);
-       }
-       t = read_zsdata(uap);
-       if (t != cmdbyte)
-               pmz_error("irda_setup speed mode byte = %x (%x)\n", t, cmdbyte);
-
-       pmz_info("IrDA setup for %ld bps, dongle version: %d\n",
-                *baud, version);
-
-       (void)read_zsdata(uap);
-       (void)read_zsdata(uap);
-       (void)read_zsdata(uap);
-
- out:
-       /* Switch back to data mode */
-       uap->curregs[R5] &= ~DTR;
-       write_zsreg(uap, R5, uap->curregs[R5]);
-       zssync(uap);
-
-       (void)read_zsdata(uap);
-       (void)read_zsdata(uap);
-       (void)read_zsdata(uap);
-}
-
-
-static void __pmz_set_termios(struct uart_port *port, struct ktermios *termios,
-                             struct ktermios *old)
-{
-       struct uart_pmac_port *uap = to_pmz(port);
-       unsigned long baud;
-
-       pmz_debug("pmz: set_termios()\n");
-
-       if (ZS_IS_ASLEEP(uap))
-               return;
-
-       memcpy(&uap->termios_cache, termios, sizeof(struct ktermios));
-
-       /* XXX Check which revs of machines actually allow 1 and 4Mb speeds
-        * on the IR dongle. Note that the IRTTY driver currently doesn't know
-        * about the FIR mode and high speed modes. So these are unused. For
-        * implementing proper support for these, we should probably add some
-        * DMA as well, at least on the Rx side, which isn't a simple thing
-        * at this point.
-        */
-       if (ZS_IS_IRDA(uap)) {
-               /* Calc baud rate */
-               baud = uart_get_baud_rate(port, termios, old, 1200, 4000000);
-               pmz_debug("pmz: switch IRDA to %ld bauds\n", baud);
-               /* Cet the irda codec to the right rate */
-               pmz_irda_setup(uap, &baud);
-               /* Set final baud rate */
-               pmz_convert_to_zs(uap, termios->c_cflag, termios->c_iflag, baud);
-               pmz_load_zsregs(uap, uap->curregs);
-               zssync(uap);
-       } else {
-               baud = uart_get_baud_rate(port, termios, old, 1200, 230400);
-               pmz_convert_to_zs(uap, termios->c_cflag, termios->c_iflag, baud);
-               /* Make sure modem status interrupts are correctly configured */
-               if (UART_ENABLE_MS(&uap->port, termios->c_cflag)) {
-                       uap->curregs[R15] |= DCDIE | SYNCIE | CTSIE;
-                       uap->flags |= PMACZILOG_FLAG_MODEM_STATUS;
-               } else {
-                       uap->curregs[R15] &= ~(DCDIE | SYNCIE | CTSIE);
-                       uap->flags &= ~PMACZILOG_FLAG_MODEM_STATUS;
-               }
-
-               /* Load registers to the chip */
-               pmz_maybe_update_regs(uap);
-       }
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       pmz_debug("pmz: set_termios() done.\n");
-}
-
-/* The port lock is not held.  */
-static void pmz_set_termios(struct uart_port *port, struct ktermios *termios,
-                           struct ktermios *old)
-{
-       struct uart_pmac_port *uap = to_pmz(port);
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);  
-
-       /* Disable IRQs on the port */
-       uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
-       write_zsreg(uap, R1, uap->curregs[R1]);
-
-       /* Setup new port configuration */
-       __pmz_set_termios(port, termios, old);
-
-       /* Re-enable IRQs on the port */
-       if (ZS_IS_OPEN(uap)) {
-               uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;
-               if (!ZS_IS_EXTCLK(uap))
-                       uap->curregs[R1] |= EXT_INT_ENAB;
-               write_zsreg(uap, R1, uap->curregs[R1]);
-       }
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *pmz_type(struct uart_port *port)
-{
-       struct uart_pmac_port *uap = to_pmz(port);
-
-       if (ZS_IS_IRDA(uap))
-               return "Z85c30 ESCC - Infrared port";
-       else if (ZS_IS_INTMODEM(uap))
-               return "Z85c30 ESCC - Internal modem";
-       return "Z85c30 ESCC - Serial port";
-}
-
-/* We do not request/release mappings of the registers here, this
- * happens at early serial probe time.
- */
-static void pmz_release_port(struct uart_port *port)
-{
-}
-
-static int pmz_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-/* These do not need to do anything interesting either.  */
-static void pmz_config_port(struct uart_port *port, int flags)
-{
-}
-
-/* We do not support letting the user mess with the divisor, IRQ, etc. */
-static int pmz_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       return -EINVAL;
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-
-static int pmz_poll_get_char(struct uart_port *port)
-{
-       struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
-
-       while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0)
-               udelay(5);
-       return read_zsdata(uap);
-}
-
-static void pmz_poll_put_char(struct uart_port *port, unsigned char c)
-{
-       struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
-
-       /* Wait for the transmit buffer to empty. */
-       while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0)
-               udelay(5);
-       write_zsdata(uap, c);
-}
-
-#endif /* CONFIG_CONSOLE_POLL */
-
-static struct uart_ops pmz_pops = {
-       .tx_empty       =       pmz_tx_empty,
-       .set_mctrl      =       pmz_set_mctrl,
-       .get_mctrl      =       pmz_get_mctrl,
-       .stop_tx        =       pmz_stop_tx,
-       .start_tx       =       pmz_start_tx,
-       .stop_rx        =       pmz_stop_rx,
-       .enable_ms      =       pmz_enable_ms,
-       .break_ctl      =       pmz_break_ctl,
-       .startup        =       pmz_startup,
-       .shutdown       =       pmz_shutdown,
-       .set_termios    =       pmz_set_termios,
-       .type           =       pmz_type,
-       .release_port   =       pmz_release_port,
-       .request_port   =       pmz_request_port,
-       .config_port    =       pmz_config_port,
-       .verify_port    =       pmz_verify_port,
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_get_char  =       pmz_poll_get_char,
-       .poll_put_char  =       pmz_poll_put_char,
-#endif
-};
-
-#ifdef CONFIG_PPC_PMAC
-
-/*
- * Setup one port structure after probing, HW is down at this point,
- * Unlike sunzilog, we don't need to pre-init the spinlock as we don't
- * register our console before uart_add_one_port() is called
- */
-static int __init pmz_init_port(struct uart_pmac_port *uap)
-{
-       struct device_node *np = uap->node;
-       const char *conn;
-       const struct slot_names_prop {
-               int     count;
-               char    name[1];
-       } *slots;
-       int len;
-       struct resource r_ports, r_rxdma, r_txdma;
-
-       /*
-        * Request & map chip registers
-        */
-       if (of_address_to_resource(np, 0, &r_ports))
-               return -ENODEV;
-       uap->port.mapbase = r_ports.start;
-       uap->port.membase = ioremap(uap->port.mapbase, 0x1000);
-
-       uap->control_reg = uap->port.membase;
-       uap->data_reg = uap->control_reg + 0x10;
-       
-       /*
-        * Request & map DBDMA registers
-        */
-#ifdef HAS_DBDMA
-       if (of_address_to_resource(np, 1, &r_txdma) == 0 &&
-           of_address_to_resource(np, 2, &r_rxdma) == 0)
-               uap->flags |= PMACZILOG_FLAG_HAS_DMA;
-#else
-       memset(&r_txdma, 0, sizeof(struct resource));
-       memset(&r_rxdma, 0, sizeof(struct resource));
-#endif 
-       if (ZS_HAS_DMA(uap)) {
-               uap->tx_dma_regs = ioremap(r_txdma.start, 0x100);
-               if (uap->tx_dma_regs == NULL) { 
-                       uap->flags &= ~PMACZILOG_FLAG_HAS_DMA;
-                       goto no_dma;
-               }
-               uap->rx_dma_regs = ioremap(r_rxdma.start, 0x100);
-               if (uap->rx_dma_regs == NULL) { 
-                       iounmap(uap->tx_dma_regs);
-                       uap->tx_dma_regs = NULL;
-                       uap->flags &= ~PMACZILOG_FLAG_HAS_DMA;
-                       goto no_dma;
-               }
-               uap->tx_dma_irq = irq_of_parse_and_map(np, 1);
-               uap->rx_dma_irq = irq_of_parse_and_map(np, 2);
-       }
-no_dma:
-
-       /*
-        * Detect port type
-        */
-       if (of_device_is_compatible(np, "cobalt"))
-               uap->flags |= PMACZILOG_FLAG_IS_INTMODEM;
-       conn = of_get_property(np, "AAPL,connector", &len);
-       if (conn && (strcmp(conn, "infrared") == 0))
-               uap->flags |= PMACZILOG_FLAG_IS_IRDA;
-       uap->port_type = PMAC_SCC_ASYNC;
-       /* 1999 Powerbook G3 has slot-names property instead */
-       slots = of_get_property(np, "slot-names", &len);
-       if (slots && slots->count > 0) {
-               if (strcmp(slots->name, "IrDA") == 0)
-                       uap->flags |= PMACZILOG_FLAG_IS_IRDA;
-               else if (strcmp(slots->name, "Modem") == 0)
-                       uap->flags |= PMACZILOG_FLAG_IS_INTMODEM;
-       }
-       if (ZS_IS_IRDA(uap))
-               uap->port_type = PMAC_SCC_IRDA;
-       if (ZS_IS_INTMODEM(uap)) {
-               struct device_node* i2c_modem =
-                       of_find_node_by_name(NULL, "i2c-modem");
-               if (i2c_modem) {
-                       const char* mid =
-                               of_get_property(i2c_modem, "modem-id", NULL);
-                       if (mid) switch(*mid) {
-                       case 0x04 :
-                       case 0x05 :
-                       case 0x07 :
-                       case 0x08 :
-                       case 0x0b :
-                       case 0x0c :
-                               uap->port_type = PMAC_SCC_I2S1;
-                       }
-                       printk(KERN_INFO "pmac_zilog: i2c-modem detected, id: %d\n",
-                               mid ? (*mid) : 0);
-                       of_node_put(i2c_modem);
-               } else {
-                       printk(KERN_INFO "pmac_zilog: serial modem detected\n");
-               }
-       }
-
-       /*
-        * Init remaining bits of "port" structure
-        */
-       uap->port.iotype = UPIO_MEM;
-       uap->port.irq = irq_of_parse_and_map(np, 0);
-       uap->port.uartclk = ZS_CLOCK;
-       uap->port.fifosize = 1;
-       uap->port.ops = &pmz_pops;
-       uap->port.type = PORT_PMAC_ZILOG;
-       uap->port.flags = 0;
-
-       /*
-        * Fixup for the port on Gatwick for which the device-tree has
-        * missing interrupts. Normally, the macio_dev would contain
-        * fixed up interrupt info, but we use the device-tree directly
-        * here due to early probing so we need the fixup too.
-        */
-       if (uap->port.irq == NO_IRQ &&
-           np->parent && np->parent->parent &&
-           of_device_is_compatible(np->parent->parent, "gatwick")) {
-               /* IRQs on gatwick are offset by 64 */
-               uap->port.irq = irq_create_mapping(NULL, 64 + 15);
-               uap->tx_dma_irq = irq_create_mapping(NULL, 64 + 4);
-               uap->rx_dma_irq = irq_create_mapping(NULL, 64 + 5);
-       }
-
-       /* Setup some valid baud rate information in the register
-        * shadows so we don't write crap there before baud rate is
-        * first initialized.
-        */
-       pmz_convert_to_zs(uap, CS8, 0, 9600);
-
-       return 0;
-}
-
-/*
- * Get rid of a port on module removal
- */
-static void pmz_dispose_port(struct uart_pmac_port *uap)
-{
-       struct device_node *np;
-
-       np = uap->node;
-       iounmap(uap->rx_dma_regs);
-       iounmap(uap->tx_dma_regs);
-       iounmap(uap->control_reg);
-       uap->node = NULL;
-       of_node_put(np);
-       memset(uap, 0, sizeof(struct uart_pmac_port));
-}
-
-/*
- * Called upon match with an escc node in the device-tree.
- */
-static int pmz_attach(struct macio_dev *mdev, const struct of_device_id *match)
-{
-       int i;
-       
-       /* Iterate the pmz_ports array to find a matching entry
-        */
-       for (i = 0; i < MAX_ZS_PORTS; i++)
-               if (pmz_ports[i].node == mdev->ofdev.dev.of_node) {
-                       struct uart_pmac_port *uap = &pmz_ports[i];
-
-                       uap->dev = mdev;
-                       dev_set_drvdata(&mdev->ofdev.dev, uap);
-                       if (macio_request_resources(uap->dev, "pmac_zilog"))
-                               printk(KERN_WARNING "%s: Failed to request resource"
-                                      ", port still active\n",
-                                      uap->node->name);
-                       else
-                               uap->flags |= PMACZILOG_FLAG_RSRC_REQUESTED;                            
-                       return 0;
-               }
-       return -ENODEV;
-}
-
-/*
- * That one should not be called, macio isn't really a hotswap device,
- * we don't expect one of those serial ports to go away...
- */
-static int pmz_detach(struct macio_dev *mdev)
-{
-       struct uart_pmac_port   *uap = dev_get_drvdata(&mdev->ofdev.dev);
-       
-       if (!uap)
-               return -ENODEV;
-
-       if (uap->flags & PMACZILOG_FLAG_RSRC_REQUESTED) {
-               macio_release_resources(uap->dev);
-               uap->flags &= ~PMACZILOG_FLAG_RSRC_REQUESTED;
-       }
-       dev_set_drvdata(&mdev->ofdev.dev, NULL);
-       uap->dev = NULL;
-       
-       return 0;
-}
-
-
-static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state)
-{
-       struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev);
-       struct uart_state *state;
-       unsigned long flags;
-
-       if (uap == NULL) {
-               printk("HRM... pmz_suspend with NULL uap\n");
-               return 0;
-       }
-
-       if (pm_state.event == mdev->ofdev.dev.power.power_state.event)
-               return 0;
-
-       pmz_debug("suspend, switching to state %d\n", pm_state.event);
-
-       state = pmz_uart_reg.state + uap->port.line;
-
-       mutex_lock(&pmz_irq_mutex);
-       mutex_lock(&state->port.mutex);
-
-       spin_lock_irqsave(&uap->port.lock, flags);
-
-       if (ZS_IS_OPEN(uap) || ZS_IS_CONS(uap)) {
-               /* Disable receiver and transmitter.  */
-               uap->curregs[R3] &= ~RxENABLE;
-               uap->curregs[R5] &= ~TxENABLE;
-
-               /* Disable all interrupts and BRK assertion.  */
-               uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
-               uap->curregs[R5] &= ~SND_BRK;
-               pmz_load_zsregs(uap, uap->curregs);
-               uap->flags |= PMACZILOG_FLAG_IS_ASLEEP;
-               mb();
-       }
-
-       spin_unlock_irqrestore(&uap->port.lock, flags);
-
-       if (ZS_IS_OPEN(uap) || ZS_IS_OPEN(uap->mate))
-               if (ZS_IS_ASLEEP(uap->mate) && ZS_IS_IRQ_ON(pmz_get_port_A(uap))) {
-                       pmz_get_port_A(uap)->flags &= ~PMACZILOG_FLAG_IS_IRQ_ON;
-                       disable_irq(uap->port.irq);
-               }
-
-       if (ZS_IS_CONS(uap))
-               uap->port.cons->flags &= ~CON_ENABLED;
-
-       /* Shut the chip down */
-       pmz_set_scc_power(uap, 0);
-
-       mutex_unlock(&state->port.mutex);
-       mutex_unlock(&pmz_irq_mutex);
-
-       pmz_debug("suspend, switching complete\n");
-
-       mdev->ofdev.dev.power.power_state = pm_state;
-
-       return 0;
-}
-
-
-static int pmz_resume(struct macio_dev *mdev)
-{
-       struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev);
-       struct uart_state *state;
-       unsigned long flags;
-       int pwr_delay = 0;
-
-       if (uap == NULL)
-               return 0;
-
-       if (mdev->ofdev.dev.power.power_state.event == PM_EVENT_ON)
-               return 0;
-       
-       pmz_debug("resume, switching to state 0\n");
-
-       state = pmz_uart_reg.state + uap->port.line;
-
-       mutex_lock(&pmz_irq_mutex);
-       mutex_lock(&state->port.mutex);
-
-       spin_lock_irqsave(&uap->port.lock, flags);
-       if (!ZS_IS_OPEN(uap) && !ZS_IS_CONS(uap)) {
-               spin_unlock_irqrestore(&uap->port.lock, flags);
-               goto bail;
-       }
-       pwr_delay = __pmz_startup(uap);
-
-       /* Take care of config that may have changed while asleep */
-       __pmz_set_termios(&uap->port, &uap->termios_cache, NULL);
-
-       if (ZS_IS_OPEN(uap)) {
-               /* Enable interrupts */         
-               uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;
-               if (!ZS_IS_EXTCLK(uap))
-                       uap->curregs[R1] |= EXT_INT_ENAB;
-               write_zsreg(uap, R1, uap->curregs[R1]);
-       }
-
-       spin_unlock_irqrestore(&uap->port.lock, flags);
-
-       if (ZS_IS_CONS(uap))
-               uap->port.cons->flags |= CON_ENABLED;
-
-       /* Re-enable IRQ on the controller */
-       if (ZS_IS_OPEN(uap) && !ZS_IS_IRQ_ON(pmz_get_port_A(uap))) {
-               pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON;
-               enable_irq(uap->port.irq);
-       }
-
- bail:
-       mutex_unlock(&state->port.mutex);
-       mutex_unlock(&pmz_irq_mutex);
-
-       /* Right now, we deal with delay by blocking here, I'll be
-        * smarter later on
-        */
-       if (pwr_delay != 0) {
-               pmz_debug("pmz: delaying %d ms\n", pwr_delay);
-               msleep(pwr_delay);
-       }
-
-       pmz_debug("resume, switching complete\n");
-
-       mdev->ofdev.dev.power.power_state.event = PM_EVENT_ON;
-
-       return 0;
-}
-
-/*
- * Probe all ports in the system and build the ports array, we register
- * with the serial layer at this point, the macio-type probing is only
- * used later to "attach" to the sysfs tree so we get power management
- * events
- */
-static int __init pmz_probe(void)
-{
-       struct device_node      *node_p, *node_a, *node_b, *np;
-       int                     count = 0;
-       int                     rc;
-
-       /*
-        * Find all escc chips in the system
-        */
-       node_p = of_find_node_by_name(NULL, "escc");
-       while (node_p) {
-               /*
-                * First get channel A/B node pointers
-                * 
-                * TODO: Add routines with proper locking to do that...
-                */
-               node_a = node_b = NULL;
-               for (np = NULL; (np = of_get_next_child(node_p, np)) != NULL;) {
-                       if (strncmp(np->name, "ch-a", 4) == 0)
-                               node_a = of_node_get(np);
-                       else if (strncmp(np->name, "ch-b", 4) == 0)
-                               node_b = of_node_get(np);
-               }
-               if (!node_a && !node_b) {
-                       of_node_put(node_a);
-                       of_node_put(node_b);
-                       printk(KERN_ERR "pmac_zilog: missing node %c for escc %s\n",
-                               (!node_a) ? 'a' : 'b', node_p->full_name);
-                       goto next;
-               }
-
-               /*
-                * Fill basic fields in the port structures
-                */
-               pmz_ports[count].mate           = &pmz_ports[count+1];
-               pmz_ports[count+1].mate         = &pmz_ports[count];
-               pmz_ports[count].flags          = PMACZILOG_FLAG_IS_CHANNEL_A;
-               pmz_ports[count].node           = node_a;
-               pmz_ports[count+1].node         = node_b;
-               pmz_ports[count].port.line      = count;
-               pmz_ports[count+1].port.line    = count+1;
-
-               /*
-                * Setup the ports for real
-                */
-               rc = pmz_init_port(&pmz_ports[count]);
-               if (rc == 0 && node_b != NULL)
-                       rc = pmz_init_port(&pmz_ports[count+1]);
-               if (rc != 0) {
-                       of_node_put(node_a);
-                       of_node_put(node_b);
-                       memset(&pmz_ports[count], 0, sizeof(struct uart_pmac_port));
-                       memset(&pmz_ports[count+1], 0, sizeof(struct uart_pmac_port));
-                       goto next;
-               }
-               count += 2;
-next:
-               node_p = of_find_node_by_name(node_p, "escc");
-       }
-       pmz_ports_count = count;
-
-       return 0;
-}
-
-#else
-
-extern struct platform_device scc_a_pdev, scc_b_pdev;
-
-static int __init pmz_init_port(struct uart_pmac_port *uap)
-{
-       struct resource *r_ports;
-       int irq;
-
-       r_ports = platform_get_resource(uap->node, IORESOURCE_MEM, 0);
-       irq = platform_get_irq(uap->node, 0);
-       if (!r_ports || !irq)
-               return -ENODEV;
-
-       uap->port.mapbase  = r_ports->start;
-       uap->port.membase  = (unsigned char __iomem *) r_ports->start;
-       uap->port.iotype   = UPIO_MEM;
-       uap->port.irq      = irq;
-       uap->port.uartclk  = ZS_CLOCK;
-       uap->port.fifosize = 1;
-       uap->port.ops      = &pmz_pops;
-       uap->port.type     = PORT_PMAC_ZILOG;
-       uap->port.flags    = 0;
-
-       uap->control_reg   = uap->port.membase;
-       uap->data_reg      = uap->control_reg + 4;
-       uap->port_type     = 0;
-
-       pmz_convert_to_zs(uap, CS8, 0, 9600);
-
-       return 0;
-}
-
-static int __init pmz_probe(void)
-{
-       int err;
-
-       pmz_ports_count = 0;
-
-       pmz_ports[0].mate      = &pmz_ports[1];
-       pmz_ports[0].port.line = 0;
-       pmz_ports[0].flags     = PMACZILOG_FLAG_IS_CHANNEL_A;
-       pmz_ports[0].node      = &scc_a_pdev;
-       err = pmz_init_port(&pmz_ports[0]);
-       if (err)
-               return err;
-       pmz_ports_count++;
-
-       pmz_ports[1].mate      = &pmz_ports[0];
-       pmz_ports[1].port.line = 1;
-       pmz_ports[1].flags     = 0;
-       pmz_ports[1].node      = &scc_b_pdev;
-       err = pmz_init_port(&pmz_ports[1]);
-       if (err)
-               return err;
-       pmz_ports_count++;
-
-       return 0;
-}
-
-static void pmz_dispose_port(struct uart_pmac_port *uap)
-{
-       memset(uap, 0, sizeof(struct uart_pmac_port));
-}
-
-static int __init pmz_attach(struct platform_device *pdev)
-{
-       int i;
-
-       for (i = 0; i < pmz_ports_count; i++)
-               if (pmz_ports[i].node == pdev)
-                       return 0;
-       return -ENODEV;
-}
-
-static int __exit pmz_detach(struct platform_device *pdev)
-{
-       return 0;
-}
-
-#endif /* !CONFIG_PPC_PMAC */
-
-#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
-
-static void pmz_console_write(struct console *con, const char *s, unsigned int count);
-static int __init pmz_console_setup(struct console *co, char *options);
-
-static struct console pmz_console = {
-       .name   =       PMACZILOG_NAME,
-       .write  =       pmz_console_write,
-       .device =       uart_console_device,
-       .setup  =       pmz_console_setup,
-       .flags  =       CON_PRINTBUFFER,
-       .index  =       -1,
-       .data   =       &pmz_uart_reg,
-};
-
-#define PMACZILOG_CONSOLE      &pmz_console
-#else /* CONFIG_SERIAL_PMACZILOG_CONSOLE */
-#define PMACZILOG_CONSOLE      (NULL)
-#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */
-
-/*
- * Register the driver, console driver and ports with the serial
- * core
- */
-static int __init pmz_register(void)
-{
-       int i, rc;
-       
-       pmz_uart_reg.nr = pmz_ports_count;
-       pmz_uart_reg.cons = PMACZILOG_CONSOLE;
-
-       /*
-        * Register this driver with the serial core
-        */
-       rc = uart_register_driver(&pmz_uart_reg);
-       if (rc)
-               return rc;
-
-       /*
-        * Register each port with the serial core
-        */
-       for (i = 0; i < pmz_ports_count; i++) {
-               struct uart_pmac_port *uport = &pmz_ports[i];
-               /* NULL node may happen on wallstreet */
-               if (uport->node != NULL)
-                       rc = uart_add_one_port(&pmz_uart_reg, &uport->port);
-               if (rc)
-                       goto err_out;
-       }
-
-       return 0;
-err_out:
-       while (i-- > 0) {
-               struct uart_pmac_port *uport = &pmz_ports[i];
-               uart_remove_one_port(&pmz_uart_reg, &uport->port);
-       }
-       uart_unregister_driver(&pmz_uart_reg);
-       return rc;
-}
-
-#ifdef CONFIG_PPC_PMAC
-
-static struct of_device_id pmz_match[] = 
-{
-       {
-       .name           = "ch-a",
-       },
-       {
-       .name           = "ch-b",
-       },
-       {},
-};
-MODULE_DEVICE_TABLE (of, pmz_match);
-
-static struct macio_driver pmz_driver = {
-       .driver = {
-               .name           = "pmac_zilog",
-               .owner          = THIS_MODULE,
-               .of_match_table = pmz_match,
-       },
-       .probe          = pmz_attach,
-       .remove         = pmz_detach,
-       .suspend        = pmz_suspend,
-       .resume         = pmz_resume,
-};
-
-#else
-
-static struct platform_driver pmz_driver = {
-       .remove         = __exit_p(pmz_detach),
-       .driver         = {
-               .name           = "scc",
-               .owner          = THIS_MODULE,
-       },
-};
-
-#endif /* !CONFIG_PPC_PMAC */
-
-static int __init init_pmz(void)
-{
-       int rc, i;
-       printk(KERN_INFO "%s\n", version);
-
-       /* 
-        * First, we need to do a direct OF-based probe pass. We
-        * do that because we want serial console up before the
-        * macio stuffs calls us back, and since that makes it
-        * easier to pass the proper number of channels to
-        * uart_register_driver()
-        */
-       if (pmz_ports_count == 0)
-               pmz_probe();
-
-       /*
-        * Bail early if no port found
-        */
-       if (pmz_ports_count == 0)
-               return -ENODEV;
-
-       /*
-        * Now we register with the serial layer
-        */
-       rc = pmz_register();
-       if (rc) {
-               printk(KERN_ERR 
-                       "pmac_zilog: Error registering serial device, disabling pmac_zilog.\n"
-                       "pmac_zilog: Did another serial driver already claim the minors?\n"); 
-               /* effectively "pmz_unprobe()" */
-               for (i=0; i < pmz_ports_count; i++)
-                       pmz_dispose_port(&pmz_ports[i]);
-               return rc;
-       }
-
-       /*
-        * Then we register the macio driver itself
-        */
-#ifdef CONFIG_PPC_PMAC
-       return macio_register_driver(&pmz_driver);
-#else
-       return platform_driver_probe(&pmz_driver, pmz_attach);
-#endif
-}
-
-static void __exit exit_pmz(void)
-{
-       int i;
-
-#ifdef CONFIG_PPC_PMAC
-       /* Get rid of macio-driver (detach from macio) */
-       macio_unregister_driver(&pmz_driver);
-#else
-       platform_driver_unregister(&pmz_driver);
-#endif
-
-       for (i = 0; i < pmz_ports_count; i++) {
-               struct uart_pmac_port *uport = &pmz_ports[i];
-               if (uport->node != NULL) {
-                       uart_remove_one_port(&pmz_uart_reg, &uport->port);
-                       pmz_dispose_port(uport);
-               }
-       }
-       /* Unregister UART driver */
-       uart_unregister_driver(&pmz_uart_reg);
-}
-
-#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
-
-static void pmz_console_putchar(struct uart_port *port, int ch)
-{
-       struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
-
-       /* Wait for the transmit buffer to empty. */
-       while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0)
-               udelay(5);
-       write_zsdata(uap, ch);
-}
-
-/*
- * Print a string to the serial port trying not to disturb
- * any possible real use of the port...
- */
-static void pmz_console_write(struct console *con, const char *s, unsigned int count)
-{
-       struct uart_pmac_port *uap = &pmz_ports[con->index];
-       unsigned long flags;
-
-       if (ZS_IS_ASLEEP(uap))
-               return;
-       spin_lock_irqsave(&uap->port.lock, flags);
-
-       /* Turn of interrupts and enable the transmitter. */
-       write_zsreg(uap, R1, uap->curregs[1] & ~TxINT_ENAB);
-       write_zsreg(uap, R5, uap->curregs[5] | TxENABLE | RTS | DTR);
-
-       uart_console_write(&uap->port, s, count, pmz_console_putchar);
-
-       /* Restore the values in the registers. */
-       write_zsreg(uap, R1, uap->curregs[1]);
-       /* Don't disable the transmitter. */
-
-       spin_unlock_irqrestore(&uap->port.lock, flags);
-}
-
-/*
- * Setup the serial console
- */
-static int __init pmz_console_setup(struct console *co, char *options)
-{
-       struct uart_pmac_port *uap;
-       struct uart_port *port;
-       int baud = 38400;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-       unsigned long pwr_delay;
-
-       /*
-        * XServe's default to 57600 bps
-        */
-       if (of_machine_is_compatible("RackMac1,1")
-           || of_machine_is_compatible("RackMac1,2")
-           || of_machine_is_compatible("MacRISC4"))
-               baud = 57600;
-
-       /*
-        * Check whether an invalid uart number has been specified, and
-        * if so, search for the first available port that does have
-        * console support.
-        */
-       if (co->index >= pmz_ports_count)
-               co->index = 0;
-       uap = &pmz_ports[co->index];
-       if (uap->node == NULL)
-               return -ENODEV;
-       port = &uap->port;
-
-       /*
-        * Mark port as beeing a console
-        */
-       uap->flags |= PMACZILOG_FLAG_IS_CONS;
-
-       /*
-        * Temporary fix for uart layer who didn't setup the spinlock yet
-        */
-       spin_lock_init(&port->lock);
-
-       /*
-        * Enable the hardware
-        */
-       pwr_delay = __pmz_startup(uap);
-       if (pwr_delay)
-               mdelay(pwr_delay);
-       
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static int __init pmz_console_init(void)
-{
-       /* Probe ports */
-       pmz_probe();
-
-       /* TODO: Autoprobe console based on OF */
-       /* pmz_console.index = i; */
-       register_console(&pmz_console);
-
-       return 0;
-
-}
-console_initcall(pmz_console_init);
-#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */
-
-module_init(init_pmz);
-module_exit(exit_pmz);
diff --git a/drivers/serial/pmac_zilog.h b/drivers/serial/pmac_zilog.h
deleted file mode 100644 (file)
index cbc34fb..0000000
+++ /dev/null
@@ -1,396 +0,0 @@
-#ifndef __PMAC_ZILOG_H__
-#define __PMAC_ZILOG_H__
-
-#ifdef CONFIG_PPC_PMAC
-#define pmz_debug(fmt, arg...) dev_dbg(&uap->dev->ofdev.dev, fmt, ## arg)
-#define pmz_error(fmt, arg...) dev_err(&uap->dev->ofdev.dev, fmt, ## arg)
-#define pmz_info(fmt, arg...)  dev_info(&uap->dev->ofdev.dev, fmt, ## arg)
-#else
-#define pmz_debug(fmt, arg...) dev_dbg(&uap->node->dev, fmt, ## arg)
-#define pmz_error(fmt, arg...) dev_err(&uap->node->dev, fmt, ## arg)
-#define pmz_info(fmt, arg...)  dev_info(&uap->node->dev, fmt, ## arg)
-#endif
-
-/*
- * At most 2 ESCCs with 2 ports each
- */
-#define MAX_ZS_PORTS   4
-
-/* 
- * We wrap our port structure around the generic uart_port.
- */
-#define NUM_ZSREGS    17
-
-struct uart_pmac_port {
-       struct uart_port                port;
-       struct uart_pmac_port           *mate;
-
-#ifdef CONFIG_PPC_PMAC
-       /* macio_dev for the escc holding this port (maybe be null on
-        * early inited port)
-        */
-       struct macio_dev                *dev;
-       /* device node to this port, this points to one of 2 childs
-        * of "escc" node (ie. ch-a or ch-b)
-        */
-       struct device_node              *node;
-#else
-       struct platform_device          *node;
-#endif
-
-       /* Port type as obtained from device tree (IRDA, modem, ...) */
-       int                             port_type;
-       u8                              curregs[NUM_ZSREGS];
-
-       unsigned int                    flags;
-#define PMACZILOG_FLAG_IS_CONS         0x00000001
-#define PMACZILOG_FLAG_IS_KGDB         0x00000002
-#define PMACZILOG_FLAG_MODEM_STATUS    0x00000004
-#define PMACZILOG_FLAG_IS_CHANNEL_A    0x00000008
-#define PMACZILOG_FLAG_REGS_HELD       0x00000010
-#define PMACZILOG_FLAG_TX_STOPPED      0x00000020
-#define PMACZILOG_FLAG_TX_ACTIVE       0x00000040
-#define PMACZILOG_FLAG_ENABLED          0x00000080
-#define PMACZILOG_FLAG_IS_IRDA         0x00000100
-#define PMACZILOG_FLAG_IS_INTMODEM     0x00000200
-#define PMACZILOG_FLAG_HAS_DMA         0x00000400
-#define PMACZILOG_FLAG_RSRC_REQUESTED  0x00000800
-#define PMACZILOG_FLAG_IS_ASLEEP       0x00001000
-#define PMACZILOG_FLAG_IS_OPEN         0x00002000
-#define PMACZILOG_FLAG_IS_IRQ_ON       0x00004000
-#define PMACZILOG_FLAG_IS_EXTCLK       0x00008000
-#define PMACZILOG_FLAG_BREAK           0x00010000
-
-       unsigned char                   parity_mask;
-       unsigned char                   prev_status;
-
-       volatile u8                     __iomem *control_reg;
-       volatile u8                     __iomem *data_reg;
-
-#ifdef CONFIG_PPC_PMAC
-       unsigned int                    tx_dma_irq;
-       unsigned int                    rx_dma_irq;
-       volatile struct dbdma_regs      __iomem *tx_dma_regs;
-       volatile struct dbdma_regs      __iomem *rx_dma_regs;
-#endif
-
-       struct ktermios                 termios_cache;
-};
-
-#define to_pmz(p) ((struct uart_pmac_port *)(p))
-
-static inline struct uart_pmac_port *pmz_get_port_A(struct uart_pmac_port *uap)
-{
-       if (uap->flags & PMACZILOG_FLAG_IS_CHANNEL_A)
-               return uap;
-       return uap->mate;
-}
-
-/*
- * Register accessors. Note that we don't need to enforce a recovery
- * delay on PCI PowerMac hardware, it's dealt in HW by the MacIO chip,
- * though if we try to use this driver on older machines, we might have
- * to add it back
- */
-static inline u8 read_zsreg(struct uart_pmac_port *port, u8 reg)
-{
-       if (reg != 0)
-               writeb(reg, port->control_reg);
-       return readb(port->control_reg);
-}
-
-static inline void write_zsreg(struct uart_pmac_port *port, u8 reg, u8 value)
-{
-       if (reg != 0)
-               writeb(reg, port->control_reg);
-       writeb(value, port->control_reg);
-}
-
-static inline u8 read_zsdata(struct uart_pmac_port *port)
-{
-       return readb(port->data_reg);
-}
-
-static inline void write_zsdata(struct uart_pmac_port *port, u8 data)
-{
-       writeb(data, port->data_reg);
-}
-
-static inline void zssync(struct uart_pmac_port *port)
-{
-       (void)readb(port->control_reg);
-}
-
-/* Conversion routines to/from brg time constants from/to bits
- * per second.
- */
-#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
-#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
-
-#define ZS_CLOCK         3686400       /* Z8530 RTxC input clock rate */
-
-/* The Zilog register set */
-
-#define        FLAG    0x7e
-
-/* Write Register 0 */
-#define        R0      0               /* Register selects */
-#define        R1      1
-#define        R2      2
-#define        R3      3
-#define        R4      4
-#define        R5      5
-#define        R6      6
-#define        R7      7
-#define        R8      8
-#define        R9      9
-#define        R10     10
-#define        R11     11
-#define        R12     12
-#define        R13     13
-#define        R14     14
-#define        R15     15
-#define        R7P     16
-
-#define        NULLCODE        0       /* Null Code */
-#define        POINT_HIGH      0x8     /* Select upper half of registers */
-#define        RES_EXT_INT     0x10    /* Reset Ext. Status Interrupts */
-#define        SEND_ABORT      0x18    /* HDLC Abort */
-#define        RES_RxINT_FC    0x20    /* Reset RxINT on First Character */
-#define        RES_Tx_P        0x28    /* Reset TxINT Pending */
-#define        ERR_RES         0x30    /* Error Reset */
-#define        RES_H_IUS       0x38    /* Reset highest IUS */
-
-#define        RES_Rx_CRC      0x40    /* Reset Rx CRC Checker */
-#define        RES_Tx_CRC      0x80    /* Reset Tx CRC Checker */
-#define        RES_EOM_L       0xC0    /* Reset EOM latch */
-
-/* Write Register 1 */
-
-#define        EXT_INT_ENAB    0x1     /* Ext Int Enable */
-#define        TxINT_ENAB      0x2     /* Tx Int Enable */
-#define        PAR_SPEC        0x4     /* Parity is special condition */
-
-#define        RxINT_DISAB     0       /* Rx Int Disable */
-#define        RxINT_FCERR     0x8     /* Rx Int on First Character Only or Error */
-#define        INT_ALL_Rx      0x10    /* Int on all Rx Characters or error */
-#define        INT_ERR_Rx      0x18    /* Int on error only */
-#define RxINT_MASK     0x18
-
-#define        WT_RDY_RT       0x20    /* W/Req reflects recv if 1, xmit if 0 */
-#define        WT_FN_RDYFN     0x40    /* W/Req pin is DMA request if 1, wait if 0 */
-#define        WT_RDY_ENAB     0x80    /* Enable W/Req pin */
-
-/* Write Register #2 (Interrupt Vector) */
-
-/* Write Register 3 */
-
-#define        RxENABLE        0x1     /* Rx Enable */
-#define        SYNC_L_INH      0x2     /* Sync Character Load Inhibit */
-#define        ADD_SM          0x4     /* Address Search Mode (SDLC) */
-#define        RxCRC_ENAB      0x8     /* Rx CRC Enable */
-#define        ENT_HM          0x10    /* Enter Hunt Mode */
-#define        AUTO_ENAB       0x20    /* Auto Enables */
-#define        Rx5             0x0     /* Rx 5 Bits/Character */
-#define        Rx7             0x40    /* Rx 7 Bits/Character */
-#define        Rx6             0x80    /* Rx 6 Bits/Character */
-#define        Rx8             0xc0    /* Rx 8 Bits/Character */
-#define RxN_MASK       0xc0
-
-/* Write Register 4 */
-
-#define        PAR_ENAB        0x1     /* Parity Enable */
-#define        PAR_EVEN        0x2     /* Parity Even/Odd* */
-
-#define        SYNC_ENAB       0       /* Sync Modes Enable */
-#define        SB1             0x4     /* 1 stop bit/char */
-#define        SB15            0x8     /* 1.5 stop bits/char */
-#define        SB2             0xc     /* 2 stop bits/char */
-#define SB_MASK                0xc
-
-#define        MONSYNC         0       /* 8 Bit Sync character */
-#define        BISYNC          0x10    /* 16 bit sync character */
-#define        SDLC            0x20    /* SDLC Mode (01111110 Sync Flag) */
-#define        EXTSYNC         0x30    /* External Sync Mode */
-
-#define        X1CLK           0x0     /* x1 clock mode */
-#define        X16CLK          0x40    /* x16 clock mode */
-#define        X32CLK          0x80    /* x32 clock mode */
-#define        X64CLK          0xC0    /* x64 clock mode */
-#define XCLK_MASK      0xC0
-
-/* Write Register 5 */
-
-#define        TxCRC_ENAB      0x1     /* Tx CRC Enable */
-#define        RTS             0x2     /* RTS */
-#define        SDLC_CRC        0x4     /* SDLC/CRC-16 */
-#define        TxENABLE        0x8     /* Tx Enable */
-#define        SND_BRK         0x10    /* Send Break */
-#define        Tx5             0x0     /* Tx 5 bits (or less)/character */
-#define        Tx7             0x20    /* Tx 7 bits/character */
-#define        Tx6             0x40    /* Tx 6 bits/character */
-#define        Tx8             0x60    /* Tx 8 bits/character */
-#define TxN_MASK       0x60
-#define        DTR             0x80    /* DTR */
-
-/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
-
-/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
-
-/* Write Register 7' (Some enhanced feature control) */
-#define        ENEXREAD        0x40    /* Enable read of some write registers */
-
-/* Write Register 8 (transmit buffer) */
-
-/* Write Register 9 (Master interrupt control) */
-#define        VIS     1       /* Vector Includes Status */
-#define        NV      2       /* No Vector */
-#define        DLC     4       /* Disable Lower Chain */
-#define        MIE     8       /* Master Interrupt Enable */
-#define        STATHI  0x10    /* Status high */
-#define        NORESET 0       /* No reset on write to R9 */
-#define        CHRB    0x40    /* Reset channel B */
-#define        CHRA    0x80    /* Reset channel A */
-#define        FHWRES  0xc0    /* Force hardware reset */
-
-/* Write Register 10 (misc control bits) */
-#define        BIT6    1       /* 6 bit/8bit sync */
-#define        LOOPMODE 2      /* SDLC Loop mode */
-#define        ABUNDER 4       /* Abort/flag on SDLC xmit underrun */
-#define        MARKIDLE 8      /* Mark/flag on idle */
-#define        GAOP    0x10    /* Go active on poll */
-#define        NRZ     0       /* NRZ mode */
-#define        NRZI    0x20    /* NRZI mode */
-#define        FM1     0x40    /* FM1 (transition = 1) */
-#define        FM0     0x60    /* FM0 (transition = 0) */
-#define        CRCPS   0x80    /* CRC Preset I/O */
-
-/* Write Register 11 (Clock Mode control) */
-#define        TRxCXT  0       /* TRxC = Xtal output */
-#define        TRxCTC  1       /* TRxC = Transmit clock */
-#define        TRxCBR  2       /* TRxC = BR Generator Output */
-#define        TRxCDP  3       /* TRxC = DPLL output */
-#define        TRxCOI  4       /* TRxC O/I */
-#define        TCRTxCP 0       /* Transmit clock = RTxC pin */
-#define        TCTRxCP 8       /* Transmit clock = TRxC pin */
-#define        TCBR    0x10    /* Transmit clock = BR Generator output */
-#define        TCDPLL  0x18    /* Transmit clock = DPLL output */
-#define        RCRTxCP 0       /* Receive clock = RTxC pin */
-#define        RCTRxCP 0x20    /* Receive clock = TRxC pin */
-#define        RCBR    0x40    /* Receive clock = BR Generator output */
-#define        RCDPLL  0x60    /* Receive clock = DPLL output */
-#define        RTxCX   0x80    /* RTxC Xtal/No Xtal */
-
-/* Write Register 12 (lower byte of baud rate generator time constant) */
-
-/* Write Register 13 (upper byte of baud rate generator time constant) */
-
-/* Write Register 14 (Misc control bits) */
-#define        BRENAB  1       /* Baud rate generator enable */
-#define        BRSRC   2       /* Baud rate generator source */
-#define        DTRREQ  4       /* DTR/Request function */
-#define        AUTOECHO 8      /* Auto Echo */
-#define        LOOPBAK 0x10    /* Local loopback */
-#define        SEARCH  0x20    /* Enter search mode */
-#define        RMC     0x40    /* Reset missing clock */
-#define        DISDPLL 0x60    /* Disable DPLL */
-#define        SSBR    0x80    /* Set DPLL source = BR generator */
-#define        SSRTxC  0xa0    /* Set DPLL source = RTxC */
-#define        SFMM    0xc0    /* Set FM mode */
-#define        SNRZI   0xe0    /* Set NRZI mode */
-
-/* Write Register 15 (external/status interrupt control) */
-#define        EN85C30 1       /* Enable some 85c30-enhanced registers */
-#define        ZCIE    2       /* Zero count IE */
-#define        ENSTFIFO 4      /* Enable status FIFO (SDLC) */
-#define        DCDIE   8       /* DCD IE */
-#define        SYNCIE  0x10    /* Sync/hunt IE */
-#define        CTSIE   0x20    /* CTS IE */
-#define        TxUIE   0x40    /* Tx Underrun/EOM IE */
-#define        BRKIE   0x80    /* Break/Abort IE */
-
-
-/* Read Register 0 */
-#define        Rx_CH_AV        0x1     /* Rx Character Available */
-#define        ZCOUNT          0x2     /* Zero count */
-#define        Tx_BUF_EMP      0x4     /* Tx Buffer empty */
-#define        DCD             0x8     /* DCD */
-#define        SYNC_HUNT       0x10    /* Sync/hunt */
-#define        CTS             0x20    /* CTS */
-#define        TxEOM           0x40    /* Tx underrun */
-#define        BRK_ABRT        0x80    /* Break/Abort */
-
-/* Read Register 1 */
-#define        ALL_SNT         0x1     /* All sent */
-/* Residue Data for 8 Rx bits/char programmed */
-#define        RES3            0x8     /* 0/3 */
-#define        RES4            0x4     /* 0/4 */
-#define        RES5            0xc     /* 0/5 */
-#define        RES6            0x2     /* 0/6 */
-#define        RES7            0xa     /* 0/7 */
-#define        RES8            0x6     /* 0/8 */
-#define        RES18           0xe     /* 1/8 */
-#define        RES28           0x0     /* 2/8 */
-/* Special Rx Condition Interrupts */
-#define        PAR_ERR         0x10    /* Parity error */
-#define        Rx_OVR          0x20    /* Rx Overrun Error */
-#define        CRC_ERR         0x40    /* CRC/Framing Error */
-#define        END_FR          0x80    /* End of Frame (SDLC) */
-
-/* Read Register 2 (channel b only) - Interrupt vector */
-#define        CHB_Tx_EMPTY    0x00
-#define        CHB_EXT_STAT    0x02
-#define        CHB_Rx_AVAIL    0x04
-#define        CHB_SPECIAL     0x06
-#define        CHA_Tx_EMPTY    0x08
-#define        CHA_EXT_STAT    0x0a
-#define        CHA_Rx_AVAIL    0x0c
-#define        CHA_SPECIAL     0x0e
-#define        STATUS_MASK     0x06
-
-/* Read Register 3 (interrupt pending register) ch a only */
-#define        CHBEXT  0x1             /* Channel B Ext/Stat IP */
-#define        CHBTxIP 0x2             /* Channel B Tx IP */
-#define        CHBRxIP 0x4             /* Channel B Rx IP */
-#define        CHAEXT  0x8             /* Channel A Ext/Stat IP */
-#define        CHATxIP 0x10            /* Channel A Tx IP */
-#define        CHARxIP 0x20            /* Channel A Rx IP */
-
-/* Read Register 8 (receive data register) */
-
-/* Read Register 10  (misc status bits) */
-#define        ONLOOP  2               /* On loop */
-#define        LOOPSEND 0x10           /* Loop sending */
-#define        CLK2MIS 0x40            /* Two clocks missing */
-#define        CLK1MIS 0x80            /* One clock missing */
-
-/* Read Register 12 (lower byte of baud rate generator constant) */
-
-/* Read Register 13 (upper byte of baud rate generator constant) */
-
-/* Read Register 15 (value of WR 15) */
-
-/* Misc macros */
-#define ZS_CLEARERR(port)    (write_zsreg(port, 0, ERR_RES))
-#define ZS_CLEARFIFO(port)   do { volatile unsigned char garbage; \
-                                    garbage = read_zsdata(port); \
-                                    garbage = read_zsdata(port); \
-                                    garbage = read_zsdata(port); \
-                               } while(0)
-
-#define ZS_IS_CONS(UP)                 ((UP)->flags & PMACZILOG_FLAG_IS_CONS)
-#define ZS_IS_KGDB(UP)                 ((UP)->flags & PMACZILOG_FLAG_IS_KGDB)
-#define ZS_IS_CHANNEL_A(UP)            ((UP)->flags & PMACZILOG_FLAG_IS_CHANNEL_A)
-#define ZS_REGS_HELD(UP)               ((UP)->flags & PMACZILOG_FLAG_REGS_HELD)
-#define ZS_TX_STOPPED(UP)              ((UP)->flags & PMACZILOG_FLAG_TX_STOPPED)
-#define ZS_TX_ACTIVE(UP)               ((UP)->flags & PMACZILOG_FLAG_TX_ACTIVE)
-#define ZS_WANTS_MODEM_STATUS(UP)      ((UP)->flags & PMACZILOG_FLAG_MODEM_STATUS)
-#define ZS_IS_IRDA(UP)                 ((UP)->flags & PMACZILOG_FLAG_IS_IRDA)
-#define ZS_IS_INTMODEM(UP)             ((UP)->flags & PMACZILOG_FLAG_IS_INTMODEM)
-#define ZS_HAS_DMA(UP)                 ((UP)->flags & PMACZILOG_FLAG_HAS_DMA)
-#define ZS_IS_ASLEEP(UP)               ((UP)->flags & PMACZILOG_FLAG_IS_ASLEEP)
-#define ZS_IS_OPEN(UP)                 ((UP)->flags & PMACZILOG_FLAG_IS_OPEN)
-#define ZS_IS_IRQ_ON(UP)               ((UP)->flags & PMACZILOG_FLAG_IS_IRQ_ON)
-#define ZS_IS_EXTCLK(UP)               ((UP)->flags & PMACZILOG_FLAG_IS_EXTCLK)
-
-#endif /* __PMAC_ZILOG_H__ */
diff --git a/drivers/serial/pnx8xxx_uart.c b/drivers/serial/pnx8xxx_uart.c
deleted file mode 100644 (file)
index 0aa75a9..0000000
+++ /dev/null
@@ -1,854 +0,0 @@
-/*
- * UART driver for PNX8XXX SoCs
- *
- * Author: Per Hallsmark per.hallsmark@mvista.com
- * Ported to 2.6 kernel by EmbeddedAlley
- * Reworked by Vitaly Wool <vitalywool@gmail.com>
- *
- * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- * Copyright (C) 2000 Deep Blue Solutions Ltd.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of
- * any kind, whether express or implied.
- *
- */
-
-#if defined(CONFIG_SERIAL_PNX8XXX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/serial_pnx8xxx.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-/* We'll be using StrongARM sa1100 serial port major/minor */
-#define SERIAL_PNX8XXX_MAJOR   204
-#define MINOR_START            5
-
-#define NR_PORTS               2
-
-#define PNX8XXX_ISR_PASS_LIMIT 256
-
-/*
- * Convert from ignore_status_mask or read_status_mask to FIFO
- * and interrupt status bits
- */
-#define SM_TO_FIFO(x)  ((x) >> 10)
-#define SM_TO_ISTAT(x) ((x) & 0x000001ff)
-#define FIFO_TO_SM(x)  ((x) << 10)
-#define ISTAT_TO_SM(x) ((x) & 0x000001ff)
-
-/*
- * This is the size of our serial port register set.
- */
-#define UART_PORT_SIZE 0x1000
-
-/*
- * This determines how often we check the modem status signals
- * for any change.  They generally aren't connected to an IRQ
- * so we have to poll them.  We also check immediately before
- * filling the TX fifo incase CTS has been dropped.
- */
-#define MCTRL_TIMEOUT  (250*HZ/1000)
-
-extern struct pnx8xxx_port pnx8xxx_ports[];
-
-static inline int serial_in(struct pnx8xxx_port *sport, int offset)
-{
-       return (__raw_readl(sport->port.membase + offset));
-}
-
-static inline void serial_out(struct pnx8xxx_port *sport, int offset, int value)
-{
-       __raw_writel(value, sport->port.membase + offset);
-}
-
-/*
- * Handle any change of modem status signal since we were last called.
- */
-static void pnx8xxx_mctrl_check(struct pnx8xxx_port *sport)
-{
-       unsigned int status, changed;
-
-       status = sport->port.ops->get_mctrl(&sport->port);
-       changed = status ^ sport->old_status;
-
-       if (changed == 0)
-               return;
-
-       sport->old_status = status;
-
-       if (changed & TIOCM_RI)
-               sport->port.icount.rng++;
-       if (changed & TIOCM_DSR)
-               sport->port.icount.dsr++;
-       if (changed & TIOCM_CAR)
-               uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
-       if (changed & TIOCM_CTS)
-               uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
-
-       wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
-}
-
-/*
- * This is our per-port timeout handler, for checking the
- * modem status signals.
- */
-static void pnx8xxx_timeout(unsigned long data)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)data;
-       unsigned long flags;
-
-       if (sport->port.state) {
-               spin_lock_irqsave(&sport->port.lock, flags);
-               pnx8xxx_mctrl_check(sport);
-               spin_unlock_irqrestore(&sport->port.lock, flags);
-
-               mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
-       }
-}
-
-/*
- * interrupts disabled on entry
- */
-static void pnx8xxx_stop_tx(struct uart_port *port)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-       u32 ien;
-
-       /* Disable TX intr */
-       ien = serial_in(sport, PNX8XXX_IEN);
-       serial_out(sport, PNX8XXX_IEN, ien & ~PNX8XXX_UART_INT_ALLTX);
-
-       /* Clear all pending TX intr */
-       serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLTX);
-}
-
-/*
- * interrupts may not be disabled on entry
- */
-static void pnx8xxx_start_tx(struct uart_port *port)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-       u32 ien;
-
-       /* Clear all pending TX intr */
-       serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLTX);
-
-       /* Enable TX intr */
-       ien = serial_in(sport, PNX8XXX_IEN);
-       serial_out(sport, PNX8XXX_IEN, ien | PNX8XXX_UART_INT_ALLTX);
-}
-
-/*
- * Interrupts enabled
- */
-static void pnx8xxx_stop_rx(struct uart_port *port)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-       u32 ien;
-
-       /* Disable RX intr */
-       ien = serial_in(sport, PNX8XXX_IEN);
-       serial_out(sport, PNX8XXX_IEN, ien & ~PNX8XXX_UART_INT_ALLRX);
-
-       /* Clear all pending RX intr */
-       serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX);
-}
-
-/*
- * Set the modem control timer to fire immediately.
- */
-static void pnx8xxx_enable_ms(struct uart_port *port)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-
-       mod_timer(&sport->timer, jiffies);
-}
-
-static void pnx8xxx_rx_chars(struct pnx8xxx_port *sport)
-{
-       struct tty_struct *tty = sport->port.state->port.tty;
-       unsigned int status, ch, flg;
-
-       status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) |
-                ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT));
-       while (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFIFO)) {
-               ch = serial_in(sport, PNX8XXX_FIFO) & 0xff;
-
-               sport->port.icount.rx++;
-
-               flg = TTY_NORMAL;
-
-               /*
-                * note that the error handling code is
-                * out of the main execution path
-                */
-               if (status & (FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE |
-                                       PNX8XXX_UART_FIFO_RXPAR |
-                                       PNX8XXX_UART_FIFO_RXBRK) |
-                             ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN))) {
-                       if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXBRK)) {
-                               status &= ~(FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) |
-                                       FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR));
-                               sport->port.icount.brk++;
-                               if (uart_handle_break(&sport->port))
-                                       goto ignore_char;
-                       } else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR))
-                               sport->port.icount.parity++;
-                       else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE))
-                               sport->port.icount.frame++;
-                       if (status & ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN))
-                               sport->port.icount.overrun++;
-
-                       status &= sport->port.read_status_mask;
-
-                       if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR))
-                               flg = TTY_PARITY;
-                       else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE))
-                               flg = TTY_FRAME;
-
-#ifdef SUPPORT_SYSRQ
-                       sport->port.sysrq = 0;
-#endif
-               }
-
-               if (uart_handle_sysrq_char(&sport->port, ch))
-                       goto ignore_char;
-
-               uart_insert_char(&sport->port, status,
-                               ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN), ch, flg);
-
-       ignore_char:
-               serial_out(sport, PNX8XXX_LCR, serial_in(sport, PNX8XXX_LCR) |
-                               PNX8XXX_UART_LCR_RX_NEXT);
-               status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) |
-                        ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT));
-       }
-       tty_flip_buffer_push(tty);
-}
-
-static void pnx8xxx_tx_chars(struct pnx8xxx_port *sport)
-{
-       struct circ_buf *xmit = &sport->port.state->xmit;
-
-       if (sport->port.x_char) {
-               serial_out(sport, PNX8XXX_FIFO, sport->port.x_char);
-               sport->port.icount.tx++;
-               sport->port.x_char = 0;
-               return;
-       }
-
-       /*
-        * Check the modem control lines before
-        * transmitting anything.
-        */
-       pnx8xxx_mctrl_check(sport);
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
-               pnx8xxx_stop_tx(&sport->port);
-               return;
-       }
-
-       /*
-        * TX while bytes available
-        */
-       while (((serial_in(sport, PNX8XXX_FIFO) &
-                                       PNX8XXX_UART_FIFO_TXFIFO) >> 16) < 16) {
-               serial_out(sport, PNX8XXX_FIFO, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               sport->port.icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&sport->port);
-
-       if (uart_circ_empty(xmit))
-               pnx8xxx_stop_tx(&sport->port);
-}
-
-static irqreturn_t pnx8xxx_int(int irq, void *dev_id)
-{
-       struct pnx8xxx_port *sport = dev_id;
-       unsigned int status;
-
-       spin_lock(&sport->port.lock);
-       /* Get the interrupts */
-       status  = serial_in(sport, PNX8XXX_ISTAT) & serial_in(sport, PNX8XXX_IEN);
-
-       /* Byte or break signal received */
-       if (status & (PNX8XXX_UART_INT_RX | PNX8XXX_UART_INT_BREAK))
-               pnx8xxx_rx_chars(sport);
-
-       /* TX holding register empty - transmit a byte */
-       if (status & PNX8XXX_UART_INT_TX)
-               pnx8xxx_tx_chars(sport);
-
-       /* Clear the ISTAT register */
-       serial_out(sport, PNX8XXX_ICLR, status);
-
-       spin_unlock(&sport->port.lock);
-       return IRQ_HANDLED;
-}
-
-/*
- * Return TIOCSER_TEMT when transmitter is not busy.
- */
-static unsigned int pnx8xxx_tx_empty(struct uart_port *port)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-
-       return serial_in(sport, PNX8XXX_FIFO) & PNX8XXX_UART_FIFO_TXFIFO_STA ? 0 : TIOCSER_TEMT;
-}
-
-static unsigned int pnx8xxx_get_mctrl(struct uart_port *port)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-       unsigned int mctrl = TIOCM_DSR;
-       unsigned int msr;
-
-       /* REVISIT */
-
-       msr = serial_in(sport, PNX8XXX_MCR);
-
-       mctrl |= msr & PNX8XXX_UART_MCR_CTS ? TIOCM_CTS : 0;
-       mctrl |= msr & PNX8XXX_UART_MCR_DCD ? TIOCM_CAR : 0;
-
-       return mctrl;
-}
-
-static void pnx8xxx_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-#if    0       /* FIXME */
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-       unsigned int msr;
-#endif
-}
-
-/*
- * Interrupts always disabled.
- */
-static void pnx8xxx_break_ctl(struct uart_port *port, int break_state)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-       unsigned long flags;
-       unsigned int lcr;
-
-       spin_lock_irqsave(&sport->port.lock, flags);
-       lcr = serial_in(sport, PNX8XXX_LCR);
-       if (break_state == -1)
-               lcr |= PNX8XXX_UART_LCR_TXBREAK;
-       else
-               lcr &= ~PNX8XXX_UART_LCR_TXBREAK;
-       serial_out(sport, PNX8XXX_LCR, lcr);
-       spin_unlock_irqrestore(&sport->port.lock, flags);
-}
-
-static int pnx8xxx_startup(struct uart_port *port)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-       int retval;
-
-       /*
-        * Allocate the IRQ
-        */
-       retval = request_irq(sport->port.irq, pnx8xxx_int, 0,
-                            "pnx8xxx-uart", sport);
-       if (retval)
-               return retval;
-
-       /*
-        * Finally, clear and enable interrupts
-        */
-
-       serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX |
-                            PNX8XXX_UART_INT_ALLTX);
-
-       serial_out(sport, PNX8XXX_IEN, serial_in(sport, PNX8XXX_IEN) |
-                           PNX8XXX_UART_INT_ALLRX |
-                           PNX8XXX_UART_INT_ALLTX);
-
-       /*
-        * Enable modem status interrupts
-        */
-       spin_lock_irq(&sport->port.lock);
-       pnx8xxx_enable_ms(&sport->port);
-       spin_unlock_irq(&sport->port.lock);
-
-       return 0;
-}
-
-static void pnx8xxx_shutdown(struct uart_port *port)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-       int lcr;
-
-       /*
-        * Stop our timer.
-        */
-       del_timer_sync(&sport->timer);
-
-       /*
-        * Disable all interrupts
-        */
-       serial_out(sport, PNX8XXX_IEN, 0);
-
-       /*
-        * Reset the Tx and Rx FIFOS, disable the break condition
-        */
-       lcr = serial_in(sport, PNX8XXX_LCR);
-       lcr &= ~PNX8XXX_UART_LCR_TXBREAK;
-       lcr |= PNX8XXX_UART_LCR_TX_RST | PNX8XXX_UART_LCR_RX_RST;
-       serial_out(sport, PNX8XXX_LCR, lcr);
-
-       /*
-        * Clear all interrupts
-        */
-       serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX |
-                            PNX8XXX_UART_INT_ALLTX);
-
-       /*
-        * Free the interrupt
-        */
-       free_irq(sport->port.irq, sport);
-}
-
-static void
-pnx8xxx_set_termios(struct uart_port *port, struct ktermios *termios,
-                  struct ktermios *old)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-       unsigned long flags;
-       unsigned int lcr_fcr, old_ien, baud, quot;
-       unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
-
-       /*
-        * We only support CS7 and CS8.
-        */
-       while ((termios->c_cflag & CSIZE) != CS7 &&
-              (termios->c_cflag & CSIZE) != CS8) {
-               termios->c_cflag &= ~CSIZE;
-               termios->c_cflag |= old_csize;
-               old_csize = CS8;
-       }
-
-       if ((termios->c_cflag & CSIZE) == CS8)
-               lcr_fcr = PNX8XXX_UART_LCR_8BIT;
-       else
-               lcr_fcr = 0;
-
-       if (termios->c_cflag & CSTOPB)
-               lcr_fcr |= PNX8XXX_UART_LCR_2STOPB;
-       if (termios->c_cflag & PARENB) {
-               lcr_fcr |= PNX8XXX_UART_LCR_PAREN;
-               if (!(termios->c_cflag & PARODD))
-                       lcr_fcr |= PNX8XXX_UART_LCR_PAREVN;
-       }
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
-       quot = uart_get_divisor(port, baud);
-
-       spin_lock_irqsave(&sport->port.lock, flags);
-
-       sport->port.read_status_mask = ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN) |
-                               ISTAT_TO_SM(PNX8XXX_UART_INT_EMPTY) |
-                               ISTAT_TO_SM(PNX8XXX_UART_INT_RX);
-       if (termios->c_iflag & INPCK)
-               sport->port.read_status_mask |=
-                       FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) |
-                       FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR);
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               sport->port.read_status_mask |=
-                       ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK);
-
-       /*
-        * Characters to ignore
-        */
-       sport->port.ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               sport->port.ignore_status_mask |=
-                       FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) |
-                       FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR);
-       if (termios->c_iflag & IGNBRK) {
-               sport->port.ignore_status_mask |=
-                       ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK);
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       sport->port.ignore_status_mask |=
-                               ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN);
-       }
-
-       /*
-        * ignore all characters if CREAD is not set
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               sport->port.ignore_status_mask |=
-                       ISTAT_TO_SM(PNX8XXX_UART_INT_RX);
-
-       del_timer_sync(&sport->timer);
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       /*
-        * disable interrupts and drain transmitter
-        */
-       old_ien = serial_in(sport, PNX8XXX_IEN);
-       serial_out(sport, PNX8XXX_IEN, old_ien & ~(PNX8XXX_UART_INT_ALLTX |
-                                       PNX8XXX_UART_INT_ALLRX));
-
-       while (serial_in(sport, PNX8XXX_FIFO) & PNX8XXX_UART_FIFO_TXFIFO_STA)
-               barrier();
-
-       /* then, disable everything */
-       serial_out(sport, PNX8XXX_IEN, 0);
-
-       /* Reset the Rx and Tx FIFOs too */
-       lcr_fcr |= PNX8XXX_UART_LCR_TX_RST;
-       lcr_fcr |= PNX8XXX_UART_LCR_RX_RST;
-
-       /* set the parity, stop bits and data size */
-       serial_out(sport, PNX8XXX_LCR, lcr_fcr);
-
-       /* set the baud rate */
-       quot -= 1;
-       serial_out(sport, PNX8XXX_BAUD, quot);
-
-       serial_out(sport, PNX8XXX_ICLR, -1);
-
-       serial_out(sport, PNX8XXX_IEN, old_ien);
-
-       if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
-               pnx8xxx_enable_ms(&sport->port);
-
-       spin_unlock_irqrestore(&sport->port.lock, flags);
-}
-
-static const char *pnx8xxx_type(struct uart_port *port)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-
-       return sport->port.type == PORT_PNX8XXX ? "PNX8XXX" : NULL;
-}
-
-/*
- * Release the memory region(s) being used by 'port'.
- */
-static void pnx8xxx_release_port(struct uart_port *port)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-
-       release_mem_region(sport->port.mapbase, UART_PORT_SIZE);
-}
-
-/*
- * Request the memory region(s) being used by 'port'.
- */
-static int pnx8xxx_request_port(struct uart_port *port)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-       return request_mem_region(sport->port.mapbase, UART_PORT_SIZE,
-                       "pnx8xxx-uart") != NULL ? 0 : -EBUSY;
-}
-
-/*
- * Configure/autoconfigure the port.
- */
-static void pnx8xxx_config_port(struct uart_port *port, int flags)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-
-       if (flags & UART_CONFIG_TYPE &&
-           pnx8xxx_request_port(&sport->port) == 0)
-               sport->port.type = PORT_PNX8XXX;
-}
-
-/*
- * Verify the new serial_struct (for TIOCSSERIAL).
- * The only change we allow are to the flags and type, and
- * even then only between PORT_PNX8XXX and PORT_UNKNOWN
- */
-static int
-pnx8xxx_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-       int ret = 0;
-
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_PNX8XXX)
-               ret = -EINVAL;
-       if (sport->port.irq != ser->irq)
-               ret = -EINVAL;
-       if (ser->io_type != SERIAL_IO_MEM)
-               ret = -EINVAL;
-       if (sport->port.uartclk / 16 != ser->baud_base)
-               ret = -EINVAL;
-       if ((void *)sport->port.mapbase != ser->iomem_base)
-               ret = -EINVAL;
-       if (sport->port.iobase != ser->port)
-               ret = -EINVAL;
-       if (ser->hub6 != 0)
-               ret = -EINVAL;
-       return ret;
-}
-
-static struct uart_ops pnx8xxx_pops = {
-       .tx_empty       = pnx8xxx_tx_empty,
-       .set_mctrl      = pnx8xxx_set_mctrl,
-       .get_mctrl      = pnx8xxx_get_mctrl,
-       .stop_tx        = pnx8xxx_stop_tx,
-       .start_tx       = pnx8xxx_start_tx,
-       .stop_rx        = pnx8xxx_stop_rx,
-       .enable_ms      = pnx8xxx_enable_ms,
-       .break_ctl      = pnx8xxx_break_ctl,
-       .startup        = pnx8xxx_startup,
-       .shutdown       = pnx8xxx_shutdown,
-       .set_termios    = pnx8xxx_set_termios,
-       .type           = pnx8xxx_type,
-       .release_port   = pnx8xxx_release_port,
-       .request_port   = pnx8xxx_request_port,
-       .config_port    = pnx8xxx_config_port,
-       .verify_port    = pnx8xxx_verify_port,
-};
-
-
-/*
- * Setup the PNX8XXX serial ports.
- *
- * Note also that we support "console=ttySx" where "x" is either 0 or 1.
- */
-static void __init pnx8xxx_init_ports(void)
-{
-       static int first = 1;
-       int i;
-
-       if (!first)
-               return;
-       first = 0;
-
-       for (i = 0; i < NR_PORTS; i++) {
-               init_timer(&pnx8xxx_ports[i].timer);
-               pnx8xxx_ports[i].timer.function = pnx8xxx_timeout;
-               pnx8xxx_ports[i].timer.data     = (unsigned long)&pnx8xxx_ports[i];
-               pnx8xxx_ports[i].port.ops = &pnx8xxx_pops;
-       }
-}
-
-#ifdef CONFIG_SERIAL_PNX8XXX_CONSOLE
-
-static void pnx8xxx_console_putchar(struct uart_port *port, int ch)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-       int status;
-
-       do {
-               /* Wait for UART_TX register to empty */
-               status = serial_in(sport, PNX8XXX_FIFO);
-       } while (status & PNX8XXX_UART_FIFO_TXFIFO);
-       serial_out(sport, PNX8XXX_FIFO, ch);
-}
-
-/*
- * Interrupts are disabled on entering
- */static void
-pnx8xxx_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct pnx8xxx_port *sport = &pnx8xxx_ports[co->index];
-       unsigned int old_ien, status;
-
-       /*
-        *      First, save IEN and then disable interrupts
-        */
-       old_ien = serial_in(sport, PNX8XXX_IEN);
-       serial_out(sport, PNX8XXX_IEN, old_ien & ~(PNX8XXX_UART_INT_ALLTX |
-                                       PNX8XXX_UART_INT_ALLRX));
-
-       uart_console_write(&sport->port, s, count, pnx8xxx_console_putchar);
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore IEN
-        */
-       do {
-               /* Wait for UART_TX register to empty */
-               status = serial_in(sport, PNX8XXX_FIFO);
-       } while (status & PNX8XXX_UART_FIFO_TXFIFO);
-
-       /* Clear TX and EMPTY interrupt */
-       serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_TX |
-                            PNX8XXX_UART_INT_EMPTY);
-
-       serial_out(sport, PNX8XXX_IEN, old_ien);
-}
-
-static int __init
-pnx8xxx_console_setup(struct console *co, char *options)
-{
-       struct pnx8xxx_port *sport;
-       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.
-        */
-       if (co->index == -1 || co->index >= NR_PORTS)
-               co->index = 0;
-       sport = &pnx8xxx_ports[co->index];
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(&sport->port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver pnx8xxx_reg;
-static struct console pnx8xxx_console = {
-       .name           = "ttyS",
-       .write          = pnx8xxx_console_write,
-       .device         = uart_console_device,
-       .setup          = pnx8xxx_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &pnx8xxx_reg,
-};
-
-static int __init pnx8xxx_rs_console_init(void)
-{
-       pnx8xxx_init_ports();
-       register_console(&pnx8xxx_console);
-       return 0;
-}
-console_initcall(pnx8xxx_rs_console_init);
-
-#define PNX8XXX_CONSOLE        &pnx8xxx_console
-#else
-#define PNX8XXX_CONSOLE        NULL
-#endif
-
-static struct uart_driver pnx8xxx_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "ttyS",
-       .dev_name               = "ttyS",
-       .major                  = SERIAL_PNX8XXX_MAJOR,
-       .minor                  = MINOR_START,
-       .nr                     = NR_PORTS,
-       .cons                   = PNX8XXX_CONSOLE,
-};
-
-static int pnx8xxx_serial_suspend(struct platform_device *pdev, pm_message_t state)
-{
-       struct pnx8xxx_port *sport = platform_get_drvdata(pdev);
-
-       return uart_suspend_port(&pnx8xxx_reg, &sport->port);
-}
-
-static int pnx8xxx_serial_resume(struct platform_device *pdev)
-{
-       struct pnx8xxx_port *sport = platform_get_drvdata(pdev);
-
-       return uart_resume_port(&pnx8xxx_reg, &sport->port);
-}
-
-static int pnx8xxx_serial_probe(struct platform_device *pdev)
-{
-       struct resource *res = pdev->resource;
-       int i;
-
-       for (i = 0; i < pdev->num_resources; i++, res++) {
-               if (!(res->flags & IORESOURCE_MEM))
-                       continue;
-
-               for (i = 0; i < NR_PORTS; i++) {
-                       if (pnx8xxx_ports[i].port.mapbase != res->start)
-                               continue;
-
-                       pnx8xxx_ports[i].port.dev = &pdev->dev;
-                       uart_add_one_port(&pnx8xxx_reg, &pnx8xxx_ports[i].port);
-                       platform_set_drvdata(pdev, &pnx8xxx_ports[i]);
-                       break;
-               }
-       }
-
-       return 0;
-}
-
-static int pnx8xxx_serial_remove(struct platform_device *pdev)
-{
-       struct pnx8xxx_port *sport = platform_get_drvdata(pdev);
-
-       platform_set_drvdata(pdev, NULL);
-
-       if (sport)
-               uart_remove_one_port(&pnx8xxx_reg, &sport->port);
-
-       return 0;
-}
-
-static struct platform_driver pnx8xxx_serial_driver = {
-       .driver         = {
-               .name   = "pnx8xxx-uart",
-               .owner  = THIS_MODULE,
-       },
-       .probe          = pnx8xxx_serial_probe,
-       .remove         = pnx8xxx_serial_remove,
-       .suspend        = pnx8xxx_serial_suspend,
-       .resume         = pnx8xxx_serial_resume,
-};
-
-static int __init pnx8xxx_serial_init(void)
-{
-       int ret;
-
-       printk(KERN_INFO "Serial: PNX8XXX driver\n");
-
-       pnx8xxx_init_ports();
-
-       ret = uart_register_driver(&pnx8xxx_reg);
-       if (ret == 0) {
-               ret = platform_driver_register(&pnx8xxx_serial_driver);
-               if (ret)
-                       uart_unregister_driver(&pnx8xxx_reg);
-       }
-       return ret;
-}
-
-static void __exit pnx8xxx_serial_exit(void)
-{
-       platform_driver_unregister(&pnx8xxx_serial_driver);
-       uart_unregister_driver(&pnx8xxx_reg);
-}
-
-module_init(pnx8xxx_serial_init);
-module_exit(pnx8xxx_serial_exit);
-
-MODULE_AUTHOR("Embedded Alley Solutions, Inc.");
-MODULE_DESCRIPTION("PNX8XXX SoCs serial port driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_PNX8XXX_MAJOR);
-MODULE_ALIAS("platform:pnx8xxx-uart");
diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c
deleted file mode 100644 (file)
index 1102a39..0000000
+++ /dev/null
@@ -1,879 +0,0 @@
-/*
- *  linux/drivers/serial/pxa.c
- *
- *  Based on drivers/serial/8250.c by Russell King.
- *
- *  Author:    Nicolas Pitre
- *  Created:   Feb 20, 2003
- *  Copyright: (C) 2003 Monta Vista Software, Inc.
- *
- * 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.
- *
- * Note 1: This driver is made separate from the already too overloaded
- * 8250.c because it needs some kirks of its own and that'll make it
- * easier to add DMA support.
- *
- * Note 2: I'm too sick of device allocation policies for serial ports.
- * If someone else wants to request an "official" allocation of major/minor
- * for this driver please be my guest.  And don't forget that new hardware
- * to come from Intel might have more than 3 or 4 of those UARTs.  Let's
- * hope for a better port registration and dynamic device allocation scheme
- * with the serial core maintainer satisfaction to appear soon.
- */
-
-
-#if defined(CONFIG_SERIAL_PXA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/serial_reg.h>
-#include <linux/circ_buf.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-
-struct uart_pxa_port {
-       struct uart_port        port;
-       unsigned char           ier;
-       unsigned char           lcr;
-       unsigned char           mcr;
-       unsigned int            lsr_break_flag;
-       struct clk              *clk;
-       char                    *name;
-};
-
-static inline unsigned int serial_in(struct uart_pxa_port *up, int offset)
-{
-       offset <<= 2;
-       return readl(up->port.membase + offset);
-}
-
-static inline void serial_out(struct uart_pxa_port *up, int offset, int value)
-{
-       offset <<= 2;
-       writel(value, up->port.membase + offset);
-}
-
-static void serial_pxa_enable_ms(struct uart_port *port)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-
-       up->ier |= UART_IER_MSI;
-       serial_out(up, UART_IER, up->ier);
-}
-
-static void serial_pxa_stop_tx(struct uart_port *port)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-
-       if (up->ier & UART_IER_THRI) {
-               up->ier &= ~UART_IER_THRI;
-               serial_out(up, UART_IER, up->ier);
-       }
-}
-
-static void serial_pxa_stop_rx(struct uart_port *port)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-
-       up->ier &= ~UART_IER_RLSI;
-       up->port.read_status_mask &= ~UART_LSR_DR;
-       serial_out(up, UART_IER, up->ier);
-}
-
-static inline void receive_chars(struct uart_pxa_port *up, int *status)
-{
-       struct tty_struct *tty = up->port.state->port.tty;
-       unsigned int ch, flag;
-       int max_count = 256;
-
-       do {
-               ch = serial_in(up, UART_RX);
-               flag = TTY_NORMAL;
-               up->port.icount.rx++;
-
-               if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
-                                      UART_LSR_FE | UART_LSR_OE))) {
-                       /*
-                        * For statistics only
-                        */
-                       if (*status & UART_LSR_BI) {
-                               *status &= ~(UART_LSR_FE | UART_LSR_PE);
-                               up->port.icount.brk++;
-                               /*
-                                * We do the SysRQ and SAK checking
-                                * here because otherwise the break
-                                * may get masked by ignore_status_mask
-                                * or read_status_mask.
-                                */
-                               if (uart_handle_break(&up->port))
-                                       goto ignore_char;
-                       } else if (*status & UART_LSR_PE)
-                               up->port.icount.parity++;
-                       else if (*status & UART_LSR_FE)
-                               up->port.icount.frame++;
-                       if (*status & UART_LSR_OE)
-                               up->port.icount.overrun++;
-
-                       /*
-                        * Mask off conditions which should be ignored.
-                        */
-                       *status &= up->port.read_status_mask;
-
-#ifdef CONFIG_SERIAL_PXA_CONSOLE
-                       if (up->port.line == up->port.cons->index) {
-                               /* Recover the break flag from console xmit */
-                               *status |= up->lsr_break_flag;
-                               up->lsr_break_flag = 0;
-                       }
-#endif
-                       if (*status & UART_LSR_BI) {
-                               flag = TTY_BREAK;
-                       } else if (*status & UART_LSR_PE)
-                               flag = TTY_PARITY;
-                       else if (*status & UART_LSR_FE)
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(&up->port, ch))
-                       goto ignore_char;
-
-               uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag);
-
-       ignore_char:
-               *status = serial_in(up, UART_LSR);
-       } while ((*status & UART_LSR_DR) && (max_count-- > 0));
-       tty_flip_buffer_push(tty);
-}
-
-static void transmit_chars(struct uart_pxa_port *up)
-{
-       struct circ_buf *xmit = &up->port.state->xmit;
-       int count;
-
-       if (up->port.x_char) {
-               serial_out(up, UART_TX, up->port.x_char);
-               up->port.icount.tx++;
-               up->port.x_char = 0;
-               return;
-       }
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
-               serial_pxa_stop_tx(&up->port);
-               return;
-       }
-
-       count = up->port.fifosize / 2;
-       do {
-               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               up->port.icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (--count > 0);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&up->port);
-
-
-       if (uart_circ_empty(xmit))
-               serial_pxa_stop_tx(&up->port);
-}
-
-static void serial_pxa_start_tx(struct uart_port *port)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-
-       if (!(up->ier & UART_IER_THRI)) {
-               up->ier |= UART_IER_THRI;
-               serial_out(up, UART_IER, up->ier);
-       }
-}
-
-static inline void check_modem_status(struct uart_pxa_port *up)
-{
-       int status;
-
-       status = serial_in(up, UART_MSR);
-
-       if ((status & UART_MSR_ANY_DELTA) == 0)
-               return;
-
-       if (status & UART_MSR_TERI)
-               up->port.icount.rng++;
-       if (status & UART_MSR_DDSR)
-               up->port.icount.dsr++;
-       if (status & UART_MSR_DDCD)
-               uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
-       if (status & UART_MSR_DCTS)
-               uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
-
-       wake_up_interruptible(&up->port.state->port.delta_msr_wait);
-}
-
-/*
- * This handles the interrupt from one port.
- */
-static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id)
-{
-       struct uart_pxa_port *up = dev_id;
-       unsigned int iir, lsr;
-
-       iir = serial_in(up, UART_IIR);
-       if (iir & UART_IIR_NO_INT)
-               return IRQ_NONE;
-       lsr = serial_in(up, UART_LSR);
-       if (lsr & UART_LSR_DR)
-               receive_chars(up, &lsr);
-       check_modem_status(up);
-       if (lsr & UART_LSR_THRE)
-               transmit_chars(up);
-       return IRQ_HANDLED;
-}
-
-static unsigned int serial_pxa_tx_empty(struct uart_port *port)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-       unsigned long flags;
-       unsigned int ret;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       return ret;
-}
-
-static unsigned int serial_pxa_get_mctrl(struct uart_port *port)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-       unsigned char status;
-       unsigned int ret;
-
-       status = serial_in(up, UART_MSR);
-
-       ret = 0;
-       if (status & UART_MSR_DCD)
-               ret |= TIOCM_CAR;
-       if (status & UART_MSR_RI)
-               ret |= TIOCM_RNG;
-       if (status & UART_MSR_DSR)
-               ret |= TIOCM_DSR;
-       if (status & UART_MSR_CTS)
-               ret |= TIOCM_CTS;
-       return ret;
-}
-
-static void serial_pxa_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-       unsigned char mcr = 0;
-
-       if (mctrl & TIOCM_RTS)
-               mcr |= UART_MCR_RTS;
-       if (mctrl & TIOCM_DTR)
-               mcr |= UART_MCR_DTR;
-       if (mctrl & TIOCM_OUT1)
-               mcr |= UART_MCR_OUT1;
-       if (mctrl & TIOCM_OUT2)
-               mcr |= UART_MCR_OUT2;
-       if (mctrl & TIOCM_LOOP)
-               mcr |= UART_MCR_LOOP;
-
-       mcr |= up->mcr;
-
-       serial_out(up, UART_MCR, mcr);
-}
-
-static void serial_pxa_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-       unsigned long flags;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       if (break_state == -1)
-               up->lcr |= UART_LCR_SBC;
-       else
-               up->lcr &= ~UART_LCR_SBC;
-       serial_out(up, UART_LCR, up->lcr);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-#if 0
-static void serial_pxa_dma_init(struct pxa_uart *up)
-{
-       up->rxdma =
-               pxa_request_dma(up->name, DMA_PRIO_LOW, pxa_receive_dma, up);
-       if (up->rxdma < 0)
-               goto out;
-       up->txdma =
-               pxa_request_dma(up->name, DMA_PRIO_LOW, pxa_transmit_dma, up);
-       if (up->txdma < 0)
-               goto err_txdma;
-       up->dmadesc = kmalloc(4 * sizeof(pxa_dma_desc), GFP_KERNEL);
-       if (!up->dmadesc)
-               goto err_alloc;
-
-       /* ... */
-err_alloc:
-       pxa_free_dma(up->txdma);
-err_rxdma:
-       pxa_free_dma(up->rxdma);
-out:
-       return;
-}
-#endif
-
-static int serial_pxa_startup(struct uart_port *port)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-       unsigned long flags;
-       int retval;
-
-       if (port->line == 3) /* HWUART */
-               up->mcr |= UART_MCR_AFE;
-       else
-               up->mcr = 0;
-
-       up->port.uartclk = clk_get_rate(up->clk);
-
-       /*
-        * Allocate the IRQ
-        */
-       retval = request_irq(up->port.irq, serial_pxa_irq, 0, up->name, up);
-       if (retval)
-               return retval;
-
-       /*
-        * Clear the FIFO buffers and disable them.
-        * (they will be reenabled in set_termios())
-        */
-       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
-                       UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
-       serial_out(up, UART_FCR, 0);
-
-       /*
-        * Clear the interrupt registers.
-        */
-       (void) serial_in(up, UART_LSR);
-       (void) serial_in(up, UART_RX);
-       (void) serial_in(up, UART_IIR);
-       (void) serial_in(up, UART_MSR);
-
-       /*
-        * Now, initialize the UART
-        */
-       serial_out(up, UART_LCR, UART_LCR_WLEN8);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       up->port.mctrl |= TIOCM_OUT2;
-       serial_pxa_set_mctrl(&up->port, up->port.mctrl);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       /*
-        * Finally, enable interrupts.  Note: Modem status interrupts
-        * are set via set_termios(), which will be occurring imminently
-        * anyway, so we don't enable them here.
-        */
-       up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE;
-       serial_out(up, UART_IER, up->ier);
-
-       /*
-        * And clear the interrupt registers again for luck.
-        */
-       (void) serial_in(up, UART_LSR);
-       (void) serial_in(up, UART_RX);
-       (void) serial_in(up, UART_IIR);
-       (void) serial_in(up, UART_MSR);
-
-       return 0;
-}
-
-static void serial_pxa_shutdown(struct uart_port *port)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-       unsigned long flags;
-
-       free_irq(up->port.irq, up);
-
-       /*
-        * Disable interrupts from this port
-        */
-       up->ier = 0;
-       serial_out(up, UART_IER, 0);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       up->port.mctrl &= ~TIOCM_OUT2;
-       serial_pxa_set_mctrl(&up->port, up->port.mctrl);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       /*
-        * Disable break condition and FIFOs
-        */
-       serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
-       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
-                                 UART_FCR_CLEAR_RCVR |
-                                 UART_FCR_CLEAR_XMIT);
-       serial_out(up, UART_FCR, 0);
-}
-
-static void
-serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,
-                      struct ktermios *old)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-       unsigned char cval, fcr = 0;
-       unsigned long flags;
-       unsigned int baud, quot;
-       unsigned int dll;
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               cval = UART_LCR_WLEN5;
-               break;
-       case CS6:
-               cval = UART_LCR_WLEN6;
-               break;
-       case CS7:
-               cval = UART_LCR_WLEN7;
-               break;
-       default:
-       case CS8:
-               cval = UART_LCR_WLEN8;
-               break;
-       }
-
-       if (termios->c_cflag & CSTOPB)
-               cval |= UART_LCR_STOP;
-       if (termios->c_cflag & PARENB)
-               cval |= UART_LCR_PARITY;
-       if (!(termios->c_cflag & PARODD))
-               cval |= UART_LCR_EPAR;
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
-       quot = uart_get_divisor(port, baud);
-
-       if ((up->port.uartclk / quot) < (2400 * 16))
-               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR1;
-       else if ((up->port.uartclk / quot) < (230400 * 16))
-               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR8;
-       else
-               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR32;
-
-       /*
-        * Ok, we're now changing the port state.  Do it with
-        * interrupts disabled.
-        */
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       /*
-        * Ensure the port will be enabled.
-        * This is required especially for serial console.
-        */
-       up->ier |= UART_IER_UUE;
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
-       if (termios->c_iflag & INPCK)
-               up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               up->port.read_status_mask |= UART_LSR_BI;
-
-       /*
-        * Characters to ignore
-        */
-       up->port.ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
-       if (termios->c_iflag & IGNBRK) {
-               up->port.ignore_status_mask |= UART_LSR_BI;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       up->port.ignore_status_mask |= UART_LSR_OE;
-       }
-
-       /*
-        * ignore all characters if CREAD is not set
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               up->port.ignore_status_mask |= UART_LSR_DR;
-
-       /*
-        * CTS flow control flag and modem status interrupts
-        */
-       up->ier &= ~UART_IER_MSI;
-       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
-               up->ier |= UART_IER_MSI;
-
-       serial_out(up, UART_IER, up->ier);
-
-       if (termios->c_cflag & CRTSCTS)
-               up->mcr |= UART_MCR_AFE;
-       else
-               up->mcr &= ~UART_MCR_AFE;
-
-       serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
-       serial_out(up, UART_DLL, quot & 0xff);          /* LS of divisor */
-
-       /*
-        * work around Errata #75 according to Intel(R) PXA27x Processor Family
-        * Specification Update (Nov 2005)
-        */
-       dll = serial_in(up, UART_DLL);
-       WARN_ON(dll != (quot & 0xff));
-
-       serial_out(up, UART_DLM, quot >> 8);            /* MS of divisor */
-       serial_out(up, UART_LCR, cval);                 /* reset DLAB */
-       up->lcr = cval;                                 /* Save LCR */
-       serial_pxa_set_mctrl(&up->port, up->port.mctrl);
-       serial_out(up, UART_FCR, fcr);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static void
-serial_pxa_pm(struct uart_port *port, unsigned int state,
-             unsigned int oldstate)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-
-       if (!state)
-               clk_enable(up->clk);
-       else
-               clk_disable(up->clk);
-}
-
-static void serial_pxa_release_port(struct uart_port *port)
-{
-}
-
-static int serial_pxa_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-static void serial_pxa_config_port(struct uart_port *port, int flags)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-       up->port.type = PORT_PXA;
-}
-
-static int
-serial_pxa_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       /* we don't want the core code to modify any port params */
-       return -EINVAL;
-}
-
-static const char *
-serial_pxa_type(struct uart_port *port)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-       return up->name;
-}
-
-static struct uart_pxa_port *serial_pxa_ports[4];
-static struct uart_driver serial_pxa_reg;
-
-#ifdef CONFIG_SERIAL_PXA_CONSOLE
-
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-
-/*
- *     Wait for transmitter & holding register to empty
- */
-static inline void wait_for_xmitr(struct uart_pxa_port *up)
-{
-       unsigned int status, tmout = 10000;
-
-       /* Wait up to 10ms for the character(s) to be sent. */
-       do {
-               status = serial_in(up, UART_LSR);
-
-               if (status & UART_LSR_BI)
-                       up->lsr_break_flag = UART_LSR_BI;
-
-               if (--tmout == 0)
-                       break;
-               udelay(1);
-       } while ((status & BOTH_EMPTY) != BOTH_EMPTY);
-
-       /* Wait up to 1s for flow control if necessary */
-       if (up->port.flags & UPF_CONS_FLOW) {
-               tmout = 1000000;
-               while (--tmout &&
-                      ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
-                       udelay(1);
-       }
-}
-
-static void serial_pxa_console_putchar(struct uart_port *port, int ch)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-
-       wait_for_xmitr(up);
-       serial_out(up, UART_TX, ch);
-}
-
-/*
- * 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.
- */
-static void
-serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct uart_pxa_port *up = serial_pxa_ports[co->index];
-       unsigned int ier;
-
-       clk_enable(up->clk);
-
-       /*
-        *      First save the IER then disable the interrupts
-        */
-       ier = serial_in(up, UART_IER);
-       serial_out(up, UART_IER, UART_IER_UUE);
-
-       uart_console_write(&up->port, s, count, serial_pxa_console_putchar);
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore the IER
-        */
-       wait_for_xmitr(up);
-       serial_out(up, UART_IER, ier);
-
-       clk_disable(up->clk);
-}
-
-static int __init
-serial_pxa_console_setup(struct console *co, char *options)
-{
-       struct uart_pxa_port *up;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       if (co->index == -1 || co->index >= serial_pxa_reg.nr)
-               co->index = 0;
-       up = serial_pxa_ports[co->index];
-       if (!up)
-               return -ENODEV;
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(&up->port, co, baud, parity, bits, flow);
-}
-
-static struct console serial_pxa_console = {
-       .name           = "ttyS",
-       .write          = serial_pxa_console_write,
-       .device         = uart_console_device,
-       .setup          = serial_pxa_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &serial_pxa_reg,
-};
-
-#define PXA_CONSOLE    &serial_pxa_console
-#else
-#define PXA_CONSOLE    NULL
-#endif
-
-struct uart_ops serial_pxa_pops = {
-       .tx_empty       = serial_pxa_tx_empty,
-       .set_mctrl      = serial_pxa_set_mctrl,
-       .get_mctrl      = serial_pxa_get_mctrl,
-       .stop_tx        = serial_pxa_stop_tx,
-       .start_tx       = serial_pxa_start_tx,
-       .stop_rx        = serial_pxa_stop_rx,
-       .enable_ms      = serial_pxa_enable_ms,
-       .break_ctl      = serial_pxa_break_ctl,
-       .startup        = serial_pxa_startup,
-       .shutdown       = serial_pxa_shutdown,
-       .set_termios    = serial_pxa_set_termios,
-       .pm             = serial_pxa_pm,
-       .type           = serial_pxa_type,
-       .release_port   = serial_pxa_release_port,
-       .request_port   = serial_pxa_request_port,
-       .config_port    = serial_pxa_config_port,
-       .verify_port    = serial_pxa_verify_port,
-};
-
-static struct uart_driver serial_pxa_reg = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "PXA serial",
-       .dev_name       = "ttyS",
-       .major          = TTY_MAJOR,
-       .minor          = 64,
-       .nr             = 4,
-       .cons           = PXA_CONSOLE,
-};
-
-#ifdef CONFIG_PM
-static int serial_pxa_suspend(struct device *dev)
-{
-        struct uart_pxa_port *sport = dev_get_drvdata(dev);
-
-        if (sport)
-                uart_suspend_port(&serial_pxa_reg, &sport->port);
-
-        return 0;
-}
-
-static int serial_pxa_resume(struct device *dev)
-{
-        struct uart_pxa_port *sport = dev_get_drvdata(dev);
-
-        if (sport)
-                uart_resume_port(&serial_pxa_reg, &sport->port);
-
-        return 0;
-}
-
-static const struct dev_pm_ops serial_pxa_pm_ops = {
-       .suspend        = serial_pxa_suspend,
-       .resume         = serial_pxa_resume,
-};
-#endif
-
-static int serial_pxa_probe(struct platform_device *dev)
-{
-       struct uart_pxa_port *sport;
-       struct resource *mmres, *irqres;
-       int ret;
-
-       mmres = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       irqres = platform_get_resource(dev, IORESOURCE_IRQ, 0);
-       if (!mmres || !irqres)
-               return -ENODEV;
-
-       sport = kzalloc(sizeof(struct uart_pxa_port), GFP_KERNEL);
-       if (!sport)
-               return -ENOMEM;
-
-       sport->clk = clk_get(&dev->dev, NULL);
-       if (IS_ERR(sport->clk)) {
-               ret = PTR_ERR(sport->clk);
-               goto err_free;
-       }
-
-       sport->port.type = PORT_PXA;
-       sport->port.iotype = UPIO_MEM;
-       sport->port.mapbase = mmres->start;
-       sport->port.irq = irqres->start;
-       sport->port.fifosize = 64;
-       sport->port.ops = &serial_pxa_pops;
-       sport->port.line = dev->id;
-       sport->port.dev = &dev->dev;
-       sport->port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
-       sport->port.uartclk = clk_get_rate(sport->clk);
-
-       switch (dev->id) {
-       case 0: sport->name = "FFUART"; break;
-       case 1: sport->name = "BTUART"; break;
-       case 2: sport->name = "STUART"; break;
-       case 3: sport->name = "HWUART"; break;
-       default:
-               sport->name = "???";
-               break;
-       }
-
-       sport->port.membase = ioremap(mmres->start, mmres->end - mmres->start + 1);
-       if (!sport->port.membase) {
-               ret = -ENOMEM;
-               goto err_clk;
-       }
-
-       serial_pxa_ports[dev->id] = sport;
-
-       uart_add_one_port(&serial_pxa_reg, &sport->port);
-       platform_set_drvdata(dev, sport);
-
-       return 0;
-
- err_clk:
-       clk_put(sport->clk);
- err_free:
-       kfree(sport);
-       return ret;
-}
-
-static int serial_pxa_remove(struct platform_device *dev)
-{
-       struct uart_pxa_port *sport = platform_get_drvdata(dev);
-
-       platform_set_drvdata(dev, NULL);
-
-       uart_remove_one_port(&serial_pxa_reg, &sport->port);
-       clk_put(sport->clk);
-       kfree(sport);
-
-       return 0;
-}
-
-static struct platform_driver serial_pxa_driver = {
-        .probe          = serial_pxa_probe,
-        .remove         = serial_pxa_remove,
-
-       .driver         = {
-               .name   = "pxa2xx-uart",
-               .owner  = THIS_MODULE,
-#ifdef CONFIG_PM
-               .pm     = &serial_pxa_pm_ops,
-#endif
-       },
-};
-
-int __init serial_pxa_init(void)
-{
-       int ret;
-
-       ret = uart_register_driver(&serial_pxa_reg);
-       if (ret != 0)
-               return ret;
-
-       ret = platform_driver_register(&serial_pxa_driver);
-       if (ret != 0)
-               uart_unregister_driver(&serial_pxa_reg);
-
-       return ret;
-}
-
-void __exit serial_pxa_exit(void)
-{
-       platform_driver_unregister(&serial_pxa_driver);
-       uart_unregister_driver(&serial_pxa_reg);
-}
-
-module_init(serial_pxa_init);
-module_exit(serial_pxa_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:pxa2xx-uart");
diff --git a/drivers/serial/s3c2400.c b/drivers/serial/s3c2400.c
deleted file mode 100644 (file)
index fed1a9a..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/* linux/drivers/serial/s3c240.c
- *
- * Driver for Samsung SoC onboard UARTs.
- *
- * Ben Dooks, Copyright (c) 2003-2005 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-
-#include <asm/irq.h>
-
-#include <mach/hardware.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-
-#include "samsung.h"
-
-static int s3c2400_serial_getsource(struct uart_port *port,
-                                   struct s3c24xx_uart_clksrc *clk)
-{
-       clk->divisor = 1;
-       clk->name = "pclk";
-
-       return 0;
-}
-
-static int s3c2400_serial_setsource(struct uart_port *port,
-                                   struct s3c24xx_uart_clksrc *clk)
-{
-       return 0;
-}
-
-static int s3c2400_serial_resetport(struct uart_port *port,
-                                   struct s3c2410_uartcfg *cfg)
-{
-       dbg("s3c2400_serial_resetport: port=%p (%08lx), cfg=%p\n",
-           port, port->mapbase, cfg);
-
-       wr_regl(port, S3C2410_UCON,  cfg->ucon);
-       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
-
-       /* reset both fifos */
-
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
-
-       return 0;
-}
-
-static struct s3c24xx_uart_info s3c2400_uart_inf = {
-       .name           = "Samsung S3C2400 UART",
-       .type           = PORT_S3C2400,
-       .fifosize       = 16,
-       .rx_fifomask    = S3C2410_UFSTAT_RXMASK,
-       .rx_fifoshift   = S3C2410_UFSTAT_RXSHIFT,
-       .rx_fifofull    = S3C2410_UFSTAT_RXFULL,
-       .tx_fifofull    = S3C2410_UFSTAT_TXFULL,
-       .tx_fifomask    = S3C2410_UFSTAT_TXMASK,
-       .tx_fifoshift   = S3C2410_UFSTAT_TXSHIFT,
-       .get_clksrc     = s3c2400_serial_getsource,
-       .set_clksrc     = s3c2400_serial_setsource,
-       .reset_port     = s3c2400_serial_resetport,
-};
-
-static int s3c2400_serial_probe(struct platform_device *dev)
-{
-       return s3c24xx_serial_probe(dev, &s3c2400_uart_inf);
-}
-
-static struct platform_driver s3c2400_serial_driver = {
-       .probe          = s3c2400_serial_probe,
-       .remove         = __devexit_p(s3c24xx_serial_remove),
-       .driver         = {
-               .name   = "s3c2400-uart",
-               .owner  = THIS_MODULE,
-       },
-};
-
-s3c24xx_console_init(&s3c2400_serial_driver, &s3c2400_uart_inf);
-
-static inline int s3c2400_serial_init(void)
-{
-       return s3c24xx_serial_init(&s3c2400_serial_driver, &s3c2400_uart_inf);
-}
-
-static inline void s3c2400_serial_exit(void)
-{
-       platform_driver_unregister(&s3c2400_serial_driver);
-}
-
-module_init(s3c2400_serial_init);
-module_exit(s3c2400_serial_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-MODULE_DESCRIPTION("Samsung S3C2400 SoC Serial port driver");
-MODULE_ALIAS("platform:s3c2400-uart");
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
deleted file mode 100644 (file)
index 73f089d..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/* linux/drivers/serial/s3c2410.c
- *
- * Driver for Samsung S3C2410 SoC onboard UARTs.
- *
- * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-
-#include <asm/irq.h>
-#include <mach/hardware.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-
-#include "samsung.h"
-
-static int s3c2410_serial_setsource(struct uart_port *port,
-                                   struct s3c24xx_uart_clksrc *clk)
-{
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-
-       if (strcmp(clk->name, "uclk") == 0)
-               ucon |= S3C2410_UCON_UCLK;
-       else
-               ucon &= ~S3C2410_UCON_UCLK;
-
-       wr_regl(port, S3C2410_UCON, ucon);
-       return 0;
-}
-
-static int s3c2410_serial_getsource(struct uart_port *port,
-                                   struct s3c24xx_uart_clksrc *clk)
-{
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-
-       clk->divisor = 1;
-       clk->name = (ucon & S3C2410_UCON_UCLK) ? "uclk" : "pclk";
-
-       return 0;
-}
-
-static int s3c2410_serial_resetport(struct uart_port *port,
-                                   struct s3c2410_uartcfg *cfg)
-{
-       dbg("s3c2410_serial_resetport: port=%p (%08lx), cfg=%p\n",
-           port, port->mapbase, cfg);
-
-       wr_regl(port, S3C2410_UCON,  cfg->ucon);
-       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
-
-       /* reset both fifos */
-
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
-
-       return 0;
-}
-
-static struct s3c24xx_uart_info s3c2410_uart_inf = {
-       .name           = "Samsung S3C2410 UART",
-       .type           = PORT_S3C2410,
-       .fifosize       = 16,
-       .rx_fifomask    = S3C2410_UFSTAT_RXMASK,
-       .rx_fifoshift   = S3C2410_UFSTAT_RXSHIFT,
-       .rx_fifofull    = S3C2410_UFSTAT_RXFULL,
-       .tx_fifofull    = S3C2410_UFSTAT_TXFULL,
-       .tx_fifomask    = S3C2410_UFSTAT_TXMASK,
-       .tx_fifoshift   = S3C2410_UFSTAT_TXSHIFT,
-       .get_clksrc     = s3c2410_serial_getsource,
-       .set_clksrc     = s3c2410_serial_setsource,
-       .reset_port     = s3c2410_serial_resetport,
-};
-
-static int s3c2410_serial_probe(struct platform_device *dev)
-{
-       return s3c24xx_serial_probe(dev, &s3c2410_uart_inf);
-}
-
-static struct platform_driver s3c2410_serial_driver = {
-       .probe          = s3c2410_serial_probe,
-       .remove         = __devexit_p(s3c24xx_serial_remove),
-       .driver         = {
-               .name   = "s3c2410-uart",
-               .owner  = THIS_MODULE,
-       },
-};
-
-s3c24xx_console_init(&s3c2410_serial_driver, &s3c2410_uart_inf);
-
-static int __init s3c2410_serial_init(void)
-{
-       return s3c24xx_serial_init(&s3c2410_serial_driver, &s3c2410_uart_inf);
-}
-
-static void __exit s3c2410_serial_exit(void)
-{
-       platform_driver_unregister(&s3c2410_serial_driver);
-}
-
-module_init(s3c2410_serial_init);
-module_exit(s3c2410_serial_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-MODULE_DESCRIPTION("Samsung S3C2410 SoC Serial port driver");
-MODULE_ALIAS("platform:s3c2410-uart");
diff --git a/drivers/serial/s3c2412.c b/drivers/serial/s3c2412.c
deleted file mode 100644 (file)
index 1700b1a..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/* linux/drivers/serial/s3c2412.c
- *
- * Driver for Samsung S3C2412 and S3C2413 SoC onboard UARTs.
- *
- * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-
-#include <asm/irq.h>
-#include <mach/hardware.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-
-#include "samsung.h"
-
-static int s3c2412_serial_setsource(struct uart_port *port,
-                                    struct s3c24xx_uart_clksrc *clk)
-{
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-
-       ucon &= ~S3C2412_UCON_CLKMASK;
-
-       if (strcmp(clk->name, "uclk") == 0)
-               ucon |= S3C2440_UCON_UCLK;
-       else if (strcmp(clk->name, "pclk") == 0)
-               ucon |= S3C2440_UCON_PCLK;
-       else if (strcmp(clk->name, "usysclk") == 0)
-               ucon |= S3C2412_UCON_USYSCLK;
-       else {
-               printk(KERN_ERR "unknown clock source %s\n", clk->name);
-               return -EINVAL;
-       }
-
-       wr_regl(port, S3C2410_UCON, ucon);
-       return 0;
-}
-
-
-static int s3c2412_serial_getsource(struct uart_port *port,
-                                   struct s3c24xx_uart_clksrc *clk)
-{
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-
-       switch (ucon & S3C2412_UCON_CLKMASK) {
-       case S3C2412_UCON_UCLK:
-               clk->divisor = 1;
-               clk->name = "uclk";
-               break;
-
-       case S3C2412_UCON_PCLK:
-       case S3C2412_UCON_PCLK2:
-               clk->divisor = 1;
-               clk->name = "pclk";
-               break;
-
-       case S3C2412_UCON_USYSCLK:
-               clk->divisor = 1;
-               clk->name = "usysclk";
-               break;
-       }
-
-       return 0;
-}
-
-static int s3c2412_serial_resetport(struct uart_port *port,
-                                   struct s3c2410_uartcfg *cfg)
-{
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-
-       dbg("%s: port=%p (%08lx), cfg=%p\n",
-           __func__, port, port->mapbase, cfg);
-
-       /* ensure we don't change the clock settings... */
-
-       ucon &= S3C2412_UCON_CLKMASK;
-
-       wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);
-       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
-
-       /* reset both fifos */
-
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
-
-       return 0;
-}
-
-static struct s3c24xx_uart_info s3c2412_uart_inf = {
-       .name           = "Samsung S3C2412 UART",
-       .type           = PORT_S3C2412,
-       .fifosize       = 64,
-       .has_divslot    = 1,
-       .rx_fifomask    = S3C2440_UFSTAT_RXMASK,
-       .rx_fifoshift   = S3C2440_UFSTAT_RXSHIFT,
-       .rx_fifofull    = S3C2440_UFSTAT_RXFULL,
-       .tx_fifofull    = S3C2440_UFSTAT_TXFULL,
-       .tx_fifomask    = S3C2440_UFSTAT_TXMASK,
-       .tx_fifoshift   = S3C2440_UFSTAT_TXSHIFT,
-       .get_clksrc     = s3c2412_serial_getsource,
-       .set_clksrc     = s3c2412_serial_setsource,
-       .reset_port     = s3c2412_serial_resetport,
-};
-
-/* device management */
-
-static int s3c2412_serial_probe(struct platform_device *dev)
-{
-       dbg("s3c2440_serial_probe: dev=%p\n", dev);
-       return s3c24xx_serial_probe(dev, &s3c2412_uart_inf);
-}
-
-static struct platform_driver s3c2412_serial_driver = {
-       .probe          = s3c2412_serial_probe,
-       .remove         = __devexit_p(s3c24xx_serial_remove),
-       .driver         = {
-               .name   = "s3c2412-uart",
-               .owner  = THIS_MODULE,
-       },
-};
-
-s3c24xx_console_init(&s3c2412_serial_driver, &s3c2412_uart_inf);
-
-static inline int s3c2412_serial_init(void)
-{
-       return s3c24xx_serial_init(&s3c2412_serial_driver, &s3c2412_uart_inf);
-}
-
-static inline void s3c2412_serial_exit(void)
-{
-       platform_driver_unregister(&s3c2412_serial_driver);
-}
-
-module_init(s3c2412_serial_init);
-module_exit(s3c2412_serial_exit);
-
-MODULE_DESCRIPTION("Samsung S3C2412,S3C2413 SoC Serial port driver");
-MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:s3c2412-uart");
diff --git a/drivers/serial/s3c2440.c b/drivers/serial/s3c2440.c
deleted file mode 100644 (file)
index 094cc39..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-/* linux/drivers/serial/s3c2440.c
- *
- * Driver for Samsung S3C2440 and S3C2442 SoC onboard UARTs.
- *
- * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-
-#include <asm/irq.h>
-#include <mach/hardware.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-
-#include "samsung.h"
-
-
-static int s3c2440_serial_setsource(struct uart_port *port,
-                                    struct s3c24xx_uart_clksrc *clk)
-{
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-
-       /* todo - proper fclk<>nonfclk switch. */
-
-       ucon &= ~S3C2440_UCON_CLKMASK;
-
-       if (strcmp(clk->name, "uclk") == 0)
-               ucon |= S3C2440_UCON_UCLK;
-       else if (strcmp(clk->name, "pclk") == 0)
-               ucon |= S3C2440_UCON_PCLK;
-       else if (strcmp(clk->name, "fclk") == 0)
-               ucon |= S3C2440_UCON_FCLK;
-       else {
-               printk(KERN_ERR "unknown clock source %s\n", clk->name);
-               return -EINVAL;
-       }
-
-       wr_regl(port, S3C2410_UCON, ucon);
-       return 0;
-}
-
-
-static int s3c2440_serial_getsource(struct uart_port *port,
-                                   struct s3c24xx_uart_clksrc *clk)
-{
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-       unsigned long ucon0, ucon1, ucon2;
-
-       switch (ucon & S3C2440_UCON_CLKMASK) {
-       case S3C2440_UCON_UCLK:
-               clk->divisor = 1;
-               clk->name = "uclk";
-               break;
-
-       case S3C2440_UCON_PCLK:
-       case S3C2440_UCON_PCLK2:
-               clk->divisor = 1;
-               clk->name = "pclk";
-               break;
-
-       case S3C2440_UCON_FCLK:
-               /* the fun of calculating the uart divisors on
-                * the s3c2440 */
-
-               ucon0 = __raw_readl(S3C24XX_VA_UART0 + S3C2410_UCON);
-               ucon1 = __raw_readl(S3C24XX_VA_UART1 + S3C2410_UCON);
-               ucon2 = __raw_readl(S3C24XX_VA_UART2 + S3C2410_UCON);
-
-               printk("ucons: %08lx, %08lx, %08lx\n", ucon0, ucon1, ucon2);
-
-               ucon0 &= S3C2440_UCON0_DIVMASK;
-               ucon1 &= S3C2440_UCON1_DIVMASK;
-               ucon2 &= S3C2440_UCON2_DIVMASK;
-
-               if (ucon0 != 0) {
-                       clk->divisor = ucon0 >> S3C2440_UCON_DIVSHIFT;
-                       clk->divisor += 6;
-               } else if (ucon1 != 0) {
-                       clk->divisor = ucon1 >> S3C2440_UCON_DIVSHIFT;
-                       clk->divisor += 21;
-               } else if (ucon2 != 0) {
-                       clk->divisor = ucon2 >> S3C2440_UCON_DIVSHIFT;
-                       clk->divisor += 36;
-               } else {
-                       /* manual calims 44, seems to be 9 */
-                       clk->divisor = 9;
-               }
-
-               clk->name = "fclk";
-               break;
-       }
-
-       return 0;
-}
-
-static int s3c2440_serial_resetport(struct uart_port *port,
-                                   struct s3c2410_uartcfg *cfg)
-{
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-
-       dbg("s3c2440_serial_resetport: port=%p (%08lx), cfg=%p\n",
-           port, port->mapbase, cfg);
-
-       /* ensure we don't change the clock settings... */
-
-       ucon &= (S3C2440_UCON0_DIVMASK | (3<<10));
-
-       wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);
-       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
-
-       /* reset both fifos */
-
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
-
-       return 0;
-}
-
-static struct s3c24xx_uart_info s3c2440_uart_inf = {
-       .name           = "Samsung S3C2440 UART",
-       .type           = PORT_S3C2440,
-       .fifosize       = 64,
-       .rx_fifomask    = S3C2440_UFSTAT_RXMASK,
-       .rx_fifoshift   = S3C2440_UFSTAT_RXSHIFT,
-       .rx_fifofull    = S3C2440_UFSTAT_RXFULL,
-       .tx_fifofull    = S3C2440_UFSTAT_TXFULL,
-       .tx_fifomask    = S3C2440_UFSTAT_TXMASK,
-       .tx_fifoshift   = S3C2440_UFSTAT_TXSHIFT,
-       .get_clksrc     = s3c2440_serial_getsource,
-       .set_clksrc     = s3c2440_serial_setsource,
-       .reset_port     = s3c2440_serial_resetport,
-};
-
-/* device management */
-
-static int s3c2440_serial_probe(struct platform_device *dev)
-{
-       dbg("s3c2440_serial_probe: dev=%p\n", dev);
-       return s3c24xx_serial_probe(dev, &s3c2440_uart_inf);
-}
-
-static struct platform_driver s3c2440_serial_driver = {
-       .probe          = s3c2440_serial_probe,
-       .remove         = __devexit_p(s3c24xx_serial_remove),
-       .driver         = {
-               .name   = "s3c2440-uart",
-               .owner  = THIS_MODULE,
-       },
-};
-
-s3c24xx_console_init(&s3c2440_serial_driver, &s3c2440_uart_inf);
-
-static int __init s3c2440_serial_init(void)
-{
-       return s3c24xx_serial_init(&s3c2440_serial_driver, &s3c2440_uart_inf);
-}
-
-static void __exit s3c2440_serial_exit(void)
-{
-       platform_driver_unregister(&s3c2440_serial_driver);
-}
-
-module_init(s3c2440_serial_init);
-module_exit(s3c2440_serial_exit);
-
-MODULE_DESCRIPTION("Samsung S3C2440,S3C2442 SoC Serial port driver");
-MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:s3c2440-uart");
diff --git a/drivers/serial/s3c24a0.c b/drivers/serial/s3c24a0.c
deleted file mode 100644 (file)
index fad6083..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/* linux/drivers/serial/s3c24a0.c
- *
- * Driver for Samsung S3C24A0 SoC onboard UARTs.
- *
- * Based on drivers/serial/s3c2410.c
- *
- * Author: Sandeep Patil <sandeep.patil@azingo.com>
- *
- * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-
-#include <mach/hardware.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-
-#include "samsung.h"
-
-static int s3c24a0_serial_setsource(struct uart_port *port,
-                                   struct s3c24xx_uart_clksrc *clk)
-{
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-
-       if (strcmp(clk->name, "uclk") == 0)
-               ucon |= S3C2410_UCON_UCLK;
-       else
-               ucon &= ~S3C2410_UCON_UCLK;
-
-       wr_regl(port, S3C2410_UCON, ucon);
-       return 0;
-}
-
-static int s3c24a0_serial_getsource(struct uart_port *port,
-                                   struct s3c24xx_uart_clksrc *clk)
-{
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-
-       clk->divisor = 1;
-       clk->name = (ucon & S3C2410_UCON_UCLK) ? "uclk" : "pclk";
-
-       return 0;
-}
-
-static int s3c24a0_serial_resetport(struct uart_port *port,
-                                   struct s3c2410_uartcfg *cfg)
-{
-       dbg("s3c24a0_serial_resetport: port=%p (%08lx), cfg=%p\n",
-           port, port->mapbase, cfg);
-
-       wr_regl(port, S3C2410_UCON,  cfg->ucon);
-       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
-
-       /* reset both fifos */
-
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
-
-       return 0;
-}
-
-static struct s3c24xx_uart_info s3c24a0_uart_inf = {
-       .name           = "Samsung S3C24A0 UART",
-       .type           = PORT_S3C2410,
-       .fifosize       = 16,
-       .rx_fifomask    = S3C24A0_UFSTAT_RXMASK,
-       .rx_fifoshift   = S3C24A0_UFSTAT_RXSHIFT,
-       .rx_fifofull    = S3C24A0_UFSTAT_RXFULL,
-       .tx_fifofull    = S3C24A0_UFSTAT_TXFULL,
-       .tx_fifomask    = S3C24A0_UFSTAT_TXMASK,
-       .tx_fifoshift   = S3C24A0_UFSTAT_TXSHIFT,
-       .get_clksrc     = s3c24a0_serial_getsource,
-       .set_clksrc     = s3c24a0_serial_setsource,
-       .reset_port     = s3c24a0_serial_resetport,
-};
-
-static int s3c24a0_serial_probe(struct platform_device *dev)
-{
-       return s3c24xx_serial_probe(dev, &s3c24a0_uart_inf);
-}
-
-static struct platform_driver s3c24a0_serial_driver = {
-       .probe          = s3c24a0_serial_probe,
-       .remove         = __devexit_p(s3c24xx_serial_remove),
-       .driver         = {
-               .name   = "s3c24a0-uart",
-               .owner  = THIS_MODULE,
-       },
-};
-
-s3c24xx_console_init(&s3c24a0_serial_driver, &s3c24a0_uart_inf);
-
-static int __init s3c24a0_serial_init(void)
-{
-       return s3c24xx_serial_init(&s3c24a0_serial_driver, &s3c24a0_uart_inf);
-}
-
-static void __exit s3c24a0_serial_exit(void)
-{
-       platform_driver_unregister(&s3c24a0_serial_driver);
-}
-
-module_init(s3c24a0_serial_init);
-module_exit(s3c24a0_serial_exit);
-
diff --git a/drivers/serial/s3c6400.c b/drivers/serial/s3c6400.c
deleted file mode 100644 (file)
index 4be92ab..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/* linux/drivers/serial/s3c6400.c
- *
- * Driver for Samsung S3C6400 and S3C6410 SoC onboard UARTs.
- *
- * Copyright 2008 Openmoko,  Inc.
- * Copyright 2008 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *     http://armlinux.simtec.co.uk/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-
-#include <asm/irq.h>
-#include <mach/hardware.h>
-
-#include <plat/regs-serial.h>
-
-#include "samsung.h"
-
-static int s3c6400_serial_setsource(struct uart_port *port,
-                                   struct s3c24xx_uart_clksrc *clk)
-{
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-
-       if (strcmp(clk->name, "uclk0") == 0) {
-               ucon &= ~S3C6400_UCON_CLKMASK;
-               ucon |= S3C6400_UCON_UCLK0;
-       } else if (strcmp(clk->name, "uclk1") == 0)
-               ucon |= S3C6400_UCON_UCLK1;
-       else if (strcmp(clk->name, "pclk") == 0) {
-               /* See notes about transitioning from UCLK to PCLK */
-               ucon &= ~S3C6400_UCON_UCLK0;
-       } else {
-               printk(KERN_ERR "unknown clock source %s\n", clk->name);
-               return -EINVAL;
-       }
-
-       wr_regl(port, S3C2410_UCON, ucon);
-       return 0;
-}
-
-
-static int s3c6400_serial_getsource(struct uart_port *port,
-                                   struct s3c24xx_uart_clksrc *clk)
-{
-       u32 ucon = rd_regl(port, S3C2410_UCON);
-
-       clk->divisor = 1;
-
-       switch (ucon & S3C6400_UCON_CLKMASK) {
-       case S3C6400_UCON_UCLK0:
-               clk->name = "uclk0";
-               break;
-
-       case S3C6400_UCON_UCLK1:
-               clk->name = "uclk1";
-               break;
-
-       case S3C6400_UCON_PCLK:
-       case S3C6400_UCON_PCLK2:
-               clk->name = "pclk";
-               break;
-       }
-
-       return 0;
-}
-
-static int s3c6400_serial_resetport(struct uart_port *port,
-                                   struct s3c2410_uartcfg *cfg)
-{
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-
-       dbg("s3c6400_serial_resetport: port=%p (%08lx), cfg=%p\n",
-           port, port->mapbase, cfg);
-
-       /* ensure we don't change the clock settings... */
-
-       ucon &= S3C6400_UCON_CLKMASK;
-
-       wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);
-       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
-
-       /* reset both fifos */
-
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
-
-       return 0;
-}
-
-static struct s3c24xx_uart_info s3c6400_uart_inf = {
-       .name           = "Samsung S3C6400 UART",
-       .type           = PORT_S3C6400,
-       .fifosize       = 64,
-       .has_divslot    = 1,
-       .rx_fifomask    = S3C2440_UFSTAT_RXMASK,
-       .rx_fifoshift   = S3C2440_UFSTAT_RXSHIFT,
-       .rx_fifofull    = S3C2440_UFSTAT_RXFULL,
-       .tx_fifofull    = S3C2440_UFSTAT_TXFULL,
-       .tx_fifomask    = S3C2440_UFSTAT_TXMASK,
-       .tx_fifoshift   = S3C2440_UFSTAT_TXSHIFT,
-       .get_clksrc     = s3c6400_serial_getsource,
-       .set_clksrc     = s3c6400_serial_setsource,
-       .reset_port     = s3c6400_serial_resetport,
-};
-
-/* device management */
-
-static int s3c6400_serial_probe(struct platform_device *dev)
-{
-       dbg("s3c6400_serial_probe: dev=%p\n", dev);
-       return s3c24xx_serial_probe(dev, &s3c6400_uart_inf);
-}
-
-static struct platform_driver s3c6400_serial_driver = {
-       .probe          = s3c6400_serial_probe,
-       .remove         = __devexit_p(s3c24xx_serial_remove),
-       .driver         = {
-               .name   = "s3c6400-uart",
-               .owner  = THIS_MODULE,
-       },
-};
-
-s3c24xx_console_init(&s3c6400_serial_driver, &s3c6400_uart_inf);
-
-static int __init s3c6400_serial_init(void)
-{
-       return s3c24xx_serial_init(&s3c6400_serial_driver, &s3c6400_uart_inf);
-}
-
-static void __exit s3c6400_serial_exit(void)
-{
-       platform_driver_unregister(&s3c6400_serial_driver);
-}
-
-module_init(s3c6400_serial_init);
-module_exit(s3c6400_serial_exit);
-
-MODULE_DESCRIPTION("Samsung S3C6400,S3C6410 SoC Serial port driver");
-MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:s3c6400-uart");
diff --git a/drivers/serial/s5pv210.c b/drivers/serial/s5pv210.c
deleted file mode 100644 (file)
index 6ebccd7..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/* linux/drivers/serial/s5pv210.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * Based on drivers/serial/s3c6400.c
- *
- * Driver for Samsung S5PV210 SoC UARTs.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-
-#include <asm/irq.h>
-#include <mach/hardware.h>
-#include <plat/regs-serial.h>
-#include "samsung.h"
-
-static int s5pv210_serial_setsource(struct uart_port *port,
-                                       struct s3c24xx_uart_clksrc *clk)
-{
-       struct s3c2410_uartcfg *cfg = port->dev->platform_data;
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-
-       if ((cfg->clocks_size) == 1)
-               return 0;
-
-       if (strcmp(clk->name, "pclk") == 0)
-               ucon &= ~S5PV210_UCON_CLKMASK;
-       else if (strcmp(clk->name, "uclk1") == 0)
-               ucon |= S5PV210_UCON_CLKMASK;
-       else {
-               printk(KERN_ERR "unknown clock source %s\n", clk->name);
-               return -EINVAL;
-       }
-
-       wr_regl(port, S3C2410_UCON, ucon);
-       return 0;
-}
-
-
-static int s5pv210_serial_getsource(struct uart_port *port,
-                                       struct s3c24xx_uart_clksrc *clk)
-{
-       struct s3c2410_uartcfg *cfg = port->dev->platform_data;
-       u32 ucon = rd_regl(port, S3C2410_UCON);
-
-       clk->divisor = 1;
-
-       if ((cfg->clocks_size) == 1)
-               return 0;
-
-       switch (ucon & S5PV210_UCON_CLKMASK) {
-       case S5PV210_UCON_PCLK:
-               clk->name = "pclk";
-               break;
-       case S5PV210_UCON_UCLK:
-               clk->name = "uclk1";
-               break;
-       }
-
-       return 0;
-}
-
-static int s5pv210_serial_resetport(struct uart_port *port,
-                                       struct s3c2410_uartcfg *cfg)
-{
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-
-       ucon &= S5PV210_UCON_CLKMASK;
-       wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);
-       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
-
-       /* reset both fifos */
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
-
-       return 0;
-}
-
-#define S5PV210_UART_DEFAULT_INFO(fifo_size)                   \
-               .name           = "Samsung S5PV210 UART0",      \
-               .type           = PORT_S3C6400,                 \
-               .fifosize       = fifo_size,                    \
-               .has_divslot    = 1,                            \
-               .rx_fifomask    = S5PV210_UFSTAT_RXMASK,        \
-               .rx_fifoshift   = S5PV210_UFSTAT_RXSHIFT,       \
-               .rx_fifofull    = S5PV210_UFSTAT_RXFULL,        \
-               .tx_fifofull    = S5PV210_UFSTAT_TXFULL,        \
-               .tx_fifomask    = S5PV210_UFSTAT_TXMASK,        \
-               .tx_fifoshift   = S5PV210_UFSTAT_TXSHIFT,       \
-               .get_clksrc     = s5pv210_serial_getsource,     \
-               .set_clksrc     = s5pv210_serial_setsource,     \
-               .reset_port     = s5pv210_serial_resetport
-
-static struct s3c24xx_uart_info s5p_port_fifo256 = {
-       S5PV210_UART_DEFAULT_INFO(256),
-};
-
-static struct s3c24xx_uart_info s5p_port_fifo64 = {
-       S5PV210_UART_DEFAULT_INFO(64),
-};
-
-static struct s3c24xx_uart_info s5p_port_fifo16 = {
-       S5PV210_UART_DEFAULT_INFO(16),
-};
-
-static struct s3c24xx_uart_info *s5p_uart_inf[] = {
-       [0] = &s5p_port_fifo256,
-       [1] = &s5p_port_fifo64,
-       [2] = &s5p_port_fifo16,
-       [3] = &s5p_port_fifo16,
-};
-
-/* device management */
-static int s5p_serial_probe(struct platform_device *pdev)
-{
-       return s3c24xx_serial_probe(pdev, s5p_uart_inf[pdev->id]);
-}
-
-static struct platform_driver s5p_serial_driver = {
-       .probe          = s5p_serial_probe,
-       .remove         = __devexit_p(s3c24xx_serial_remove),
-       .driver         = {
-               .name   = "s5pv210-uart",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init s5pv210_serial_console_init(void)
-{
-       return s3c24xx_serial_initconsole(&s5p_serial_driver, s5p_uart_inf);
-}
-
-console_initcall(s5pv210_serial_console_init);
-
-static int __init s5p_serial_init(void)
-{
-       return s3c24xx_serial_init(&s5p_serial_driver, *s5p_uart_inf);
-}
-
-static void __exit s5p_serial_exit(void)
-{
-       platform_driver_unregister(&s5p_serial_driver);
-}
-
-module_init(s5p_serial_init);
-module_exit(s5p_serial_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:s5pv210-uart");
-MODULE_DESCRIPTION("Samsung S5PV210 UART Driver support");
-MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com>");
diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c
deleted file mode 100644 (file)
index 2199d81..0000000
+++ /dev/null
@@ -1,918 +0,0 @@
-/*
- *  linux/drivers/char/sa1100.c
- *
- *  Driver for SA11x0 serial ports
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *
- *  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
- */
-
-#if defined(CONFIG_SERIAL_SA1100_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/platform_device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <mach/hardware.h>
-#include <asm/mach/serial_sa1100.h>
-
-/* We've been assigned a range on the "Low-density serial ports" major */
-#define SERIAL_SA1100_MAJOR    204
-#define MINOR_START            5
-
-#define NR_PORTS               3
-
-#define SA1100_ISR_PASS_LIMIT  256
-
-/*
- * Convert from ignore_status_mask or read_status_mask to UTSR[01]
- */
-#define SM_TO_UTSR0(x) ((x) & 0xff)
-#define SM_TO_UTSR1(x) ((x) >> 8)
-#define UTSR0_TO_SM(x) ((x))
-#define UTSR1_TO_SM(x) ((x) << 8)
-
-#define UART_GET_UTCR0(sport)  __raw_readl((sport)->port.membase + UTCR0)
-#define UART_GET_UTCR1(sport)  __raw_readl((sport)->port.membase + UTCR1)
-#define UART_GET_UTCR2(sport)  __raw_readl((sport)->port.membase + UTCR2)
-#define UART_GET_UTCR3(sport)  __raw_readl((sport)->port.membase + UTCR3)
-#define UART_GET_UTSR0(sport)  __raw_readl((sport)->port.membase + UTSR0)
-#define UART_GET_UTSR1(sport)  __raw_readl((sport)->port.membase + UTSR1)
-#define UART_GET_CHAR(sport)   __raw_readl((sport)->port.membase + UTDR)
-
-#define UART_PUT_UTCR0(sport,v)        __raw_writel((v),(sport)->port.membase + UTCR0)
-#define UART_PUT_UTCR1(sport,v)        __raw_writel((v),(sport)->port.membase + UTCR1)
-#define UART_PUT_UTCR2(sport,v)        __raw_writel((v),(sport)->port.membase + UTCR2)
-#define UART_PUT_UTCR3(sport,v)        __raw_writel((v),(sport)->port.membase + UTCR3)
-#define UART_PUT_UTSR0(sport,v)        __raw_writel((v),(sport)->port.membase + UTSR0)
-#define UART_PUT_UTSR1(sport,v)        __raw_writel((v),(sport)->port.membase + UTSR1)
-#define UART_PUT_CHAR(sport,v) __raw_writel((v),(sport)->port.membase + UTDR)
-
-/*
- * This is the size of our serial port register set.
- */
-#define UART_PORT_SIZE 0x24
-
-/*
- * This determines how often we check the modem status signals
- * for any change.  They generally aren't connected to an IRQ
- * so we have to poll them.  We also check immediately before
- * filling the TX fifo incase CTS has been dropped.
- */
-#define MCTRL_TIMEOUT  (250*HZ/1000)
-
-struct sa1100_port {
-       struct uart_port        port;
-       struct timer_list       timer;
-       unsigned int            old_status;
-};
-
-/*
- * Handle any change of modem status signal since we were last called.
- */
-static void sa1100_mctrl_check(struct sa1100_port *sport)
-{
-       unsigned int status, changed;
-
-       status = sport->port.ops->get_mctrl(&sport->port);
-       changed = status ^ sport->old_status;
-
-       if (changed == 0)
-               return;
-
-       sport->old_status = status;
-
-       if (changed & TIOCM_RI)
-               sport->port.icount.rng++;
-       if (changed & TIOCM_DSR)
-               sport->port.icount.dsr++;
-       if (changed & TIOCM_CAR)
-               uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
-       if (changed & TIOCM_CTS)
-               uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
-
-       wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
-}
-
-/*
- * This is our per-port timeout handler, for checking the
- * modem status signals.
- */
-static void sa1100_timeout(unsigned long data)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)data;
-       unsigned long flags;
-
-       if (sport->port.state) {
-               spin_lock_irqsave(&sport->port.lock, flags);
-               sa1100_mctrl_check(sport);
-               spin_unlock_irqrestore(&sport->port.lock, flags);
-
-               mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
-       }
-}
-
-/*
- * interrupts disabled on entry
- */
-static void sa1100_stop_tx(struct uart_port *port)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-       u32 utcr3;
-
-       utcr3 = UART_GET_UTCR3(sport);
-       UART_PUT_UTCR3(sport, utcr3 & ~UTCR3_TIE);
-       sport->port.read_status_mask &= ~UTSR0_TO_SM(UTSR0_TFS);
-}
-
-/*
- * port locked and interrupts disabled
- */
-static void sa1100_start_tx(struct uart_port *port)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-       u32 utcr3;
-
-       utcr3 = UART_GET_UTCR3(sport);
-       sport->port.read_status_mask |= UTSR0_TO_SM(UTSR0_TFS);
-       UART_PUT_UTCR3(sport, utcr3 | UTCR3_TIE);
-}
-
-/*
- * Interrupts enabled
- */
-static void sa1100_stop_rx(struct uart_port *port)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-       u32 utcr3;
-
-       utcr3 = UART_GET_UTCR3(sport);
-       UART_PUT_UTCR3(sport, utcr3 & ~UTCR3_RIE);
-}
-
-/*
- * Set the modem control timer to fire immediately.
- */
-static void sa1100_enable_ms(struct uart_port *port)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-
-       mod_timer(&sport->timer, jiffies);
-}
-
-static void
-sa1100_rx_chars(struct sa1100_port *sport)
-{
-       struct tty_struct *tty = sport->port.state->port.tty;
-       unsigned int status, ch, flg;
-
-       status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) |
-                UTSR0_TO_SM(UART_GET_UTSR0(sport));
-       while (status & UTSR1_TO_SM(UTSR1_RNE)) {
-               ch = UART_GET_CHAR(sport);
-
-               sport->port.icount.rx++;
-
-               flg = TTY_NORMAL;
-
-               /*
-                * note that the error handling code is
-                * out of the main execution path
-                */
-               if (status & UTSR1_TO_SM(UTSR1_PRE | UTSR1_FRE | UTSR1_ROR)) {
-                       if (status & UTSR1_TO_SM(UTSR1_PRE))
-                               sport->port.icount.parity++;
-                       else if (status & UTSR1_TO_SM(UTSR1_FRE))
-                               sport->port.icount.frame++;
-                       if (status & UTSR1_TO_SM(UTSR1_ROR))
-                               sport->port.icount.overrun++;
-
-                       status &= sport->port.read_status_mask;
-
-                       if (status & UTSR1_TO_SM(UTSR1_PRE))
-                               flg = TTY_PARITY;
-                       else if (status & UTSR1_TO_SM(UTSR1_FRE))
-                               flg = TTY_FRAME;
-
-#ifdef SUPPORT_SYSRQ
-                       sport->port.sysrq = 0;
-#endif
-               }
-
-               if (uart_handle_sysrq_char(&sport->port, ch))
-                       goto ignore_char;
-
-               uart_insert_char(&sport->port, status, UTSR1_TO_SM(UTSR1_ROR), ch, flg);
-
-       ignore_char:
-               status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) |
-                        UTSR0_TO_SM(UART_GET_UTSR0(sport));
-       }
-       tty_flip_buffer_push(tty);
-}
-
-static void sa1100_tx_chars(struct sa1100_port *sport)
-{
-       struct circ_buf *xmit = &sport->port.state->xmit;
-
-       if (sport->port.x_char) {
-               UART_PUT_CHAR(sport, sport->port.x_char);
-               sport->port.icount.tx++;
-               sport->port.x_char = 0;
-               return;
-       }
-
-       /*
-        * Check the modem control lines before
-        * transmitting anything.
-        */
-       sa1100_mctrl_check(sport);
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
-               sa1100_stop_tx(&sport->port);
-               return;
-       }
-
-       /*
-        * Tried using FIFO (not checking TNF) for fifo fill:
-        * still had the '4 bytes repeated' problem.
-        */
-       while (UART_GET_UTSR1(sport) & UTSR1_TNF) {
-               UART_PUT_CHAR(sport, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               sport->port.icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&sport->port);
-
-       if (uart_circ_empty(xmit))
-               sa1100_stop_tx(&sport->port);
-}
-
-static irqreturn_t sa1100_int(int irq, void *dev_id)
-{
-       struct sa1100_port *sport = dev_id;
-       unsigned int status, pass_counter = 0;
-
-       spin_lock(&sport->port.lock);
-       status = UART_GET_UTSR0(sport);
-       status &= SM_TO_UTSR0(sport->port.read_status_mask) | ~UTSR0_TFS;
-       do {
-               if (status & (UTSR0_RFS | UTSR0_RID)) {
-                       /* Clear the receiver idle bit, if set */
-                       if (status & UTSR0_RID)
-                               UART_PUT_UTSR0(sport, UTSR0_RID);
-                       sa1100_rx_chars(sport);
-               }
-
-               /* Clear the relevant break bits */
-               if (status & (UTSR0_RBB | UTSR0_REB))
-                       UART_PUT_UTSR0(sport, status & (UTSR0_RBB | UTSR0_REB));
-
-               if (status & UTSR0_RBB)
-                       sport->port.icount.brk++;
-
-               if (status & UTSR0_REB)
-                       uart_handle_break(&sport->port);
-
-               if (status & UTSR0_TFS)
-                       sa1100_tx_chars(sport);
-               if (pass_counter++ > SA1100_ISR_PASS_LIMIT)
-                       break;
-               status = UART_GET_UTSR0(sport);
-               status &= SM_TO_UTSR0(sport->port.read_status_mask) |
-                         ~UTSR0_TFS;
-       } while (status & (UTSR0_TFS | UTSR0_RFS | UTSR0_RID));
-       spin_unlock(&sport->port.lock);
-
-       return IRQ_HANDLED;
-}
-
-/*
- * Return TIOCSER_TEMT when transmitter is not busy.
- */
-static unsigned int sa1100_tx_empty(struct uart_port *port)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-
-       return UART_GET_UTSR1(sport) & UTSR1_TBY ? 0 : TIOCSER_TEMT;
-}
-
-static unsigned int sa1100_get_mctrl(struct uart_port *port)
-{
-       return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
-}
-
-static void sa1100_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-}
-
-/*
- * Interrupts always disabled.
- */
-static void sa1100_break_ctl(struct uart_port *port, int break_state)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-       unsigned long flags;
-       unsigned int utcr3;
-
-       spin_lock_irqsave(&sport->port.lock, flags);
-       utcr3 = UART_GET_UTCR3(sport);
-       if (break_state == -1)
-               utcr3 |= UTCR3_BRK;
-       else
-               utcr3 &= ~UTCR3_BRK;
-       UART_PUT_UTCR3(sport, utcr3);
-       spin_unlock_irqrestore(&sport->port.lock, flags);
-}
-
-static int sa1100_startup(struct uart_port *port)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-       int retval;
-
-       /*
-        * Allocate the IRQ
-        */
-       retval = request_irq(sport->port.irq, sa1100_int, 0,
-                            "sa11x0-uart", sport);
-       if (retval)
-               return retval;
-
-       /*
-        * Finally, clear and enable interrupts
-        */
-       UART_PUT_UTSR0(sport, -1);
-       UART_PUT_UTCR3(sport, UTCR3_RXE | UTCR3_TXE | UTCR3_RIE);
-
-       /*
-        * Enable modem status interrupts
-        */
-       spin_lock_irq(&sport->port.lock);
-       sa1100_enable_ms(&sport->port);
-       spin_unlock_irq(&sport->port.lock);
-
-       return 0;
-}
-
-static void sa1100_shutdown(struct uart_port *port)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-
-       /*
-        * Stop our timer.
-        */
-       del_timer_sync(&sport->timer);
-
-       /*
-        * Free the interrupt
-        */
-       free_irq(sport->port.irq, sport);
-
-       /*
-        * Disable all interrupts, port and break condition.
-        */
-       UART_PUT_UTCR3(sport, 0);
-}
-
-static void
-sa1100_set_termios(struct uart_port *port, struct ktermios *termios,
-                  struct ktermios *old)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-       unsigned long flags;
-       unsigned int utcr0, old_utcr3, baud, quot;
-       unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
-
-       /*
-        * We only support CS7 and CS8.
-        */
-       while ((termios->c_cflag & CSIZE) != CS7 &&
-              (termios->c_cflag & CSIZE) != CS8) {
-               termios->c_cflag &= ~CSIZE;
-               termios->c_cflag |= old_csize;
-               old_csize = CS8;
-       }
-
-       if ((termios->c_cflag & CSIZE) == CS8)
-               utcr0 = UTCR0_DSS;
-       else
-               utcr0 = 0;
-
-       if (termios->c_cflag & CSTOPB)
-               utcr0 |= UTCR0_SBS;
-       if (termios->c_cflag & PARENB) {
-               utcr0 |= UTCR0_PE;
-               if (!(termios->c_cflag & PARODD))
-                       utcr0 |= UTCR0_OES;
-       }
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
-       quot = uart_get_divisor(port, baud);
-
-       spin_lock_irqsave(&sport->port.lock, flags);
-
-       sport->port.read_status_mask &= UTSR0_TO_SM(UTSR0_TFS);
-       sport->port.read_status_mask |= UTSR1_TO_SM(UTSR1_ROR);
-       if (termios->c_iflag & INPCK)
-               sport->port.read_status_mask |=
-                               UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE);
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               sport->port.read_status_mask |=
-                               UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB);
-
-       /*
-        * Characters to ignore
-        */
-       sport->port.ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               sport->port.ignore_status_mask |=
-                               UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE);
-       if (termios->c_iflag & IGNBRK) {
-               sport->port.ignore_status_mask |=
-                               UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB);
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       sport->port.ignore_status_mask |=
-                               UTSR1_TO_SM(UTSR1_ROR);
-       }
-
-       del_timer_sync(&sport->timer);
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       /*
-        * disable interrupts and drain transmitter
-        */
-       old_utcr3 = UART_GET_UTCR3(sport);
-       UART_PUT_UTCR3(sport, old_utcr3 & ~(UTCR3_RIE | UTCR3_TIE));
-
-       while (UART_GET_UTSR1(sport) & UTSR1_TBY)
-               barrier();
-
-       /* then, disable everything */
-       UART_PUT_UTCR3(sport, 0);
-
-       /* set the parity, stop bits and data size */
-       UART_PUT_UTCR0(sport, utcr0);
-
-       /* set the baud rate */
-       quot -= 1;
-       UART_PUT_UTCR1(sport, ((quot & 0xf00) >> 8));
-       UART_PUT_UTCR2(sport, (quot & 0xff));
-
-       UART_PUT_UTSR0(sport, -1);
-
-       UART_PUT_UTCR3(sport, old_utcr3);
-
-       if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
-               sa1100_enable_ms(&sport->port);
-
-       spin_unlock_irqrestore(&sport->port.lock, flags);
-}
-
-static const char *sa1100_type(struct uart_port *port)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-
-       return sport->port.type == PORT_SA1100 ? "SA1100" : NULL;
-}
-
-/*
- * Release the memory region(s) being used by 'port'.
- */
-static void sa1100_release_port(struct uart_port *port)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-
-       release_mem_region(sport->port.mapbase, UART_PORT_SIZE);
-}
-
-/*
- * Request the memory region(s) being used by 'port'.
- */
-static int sa1100_request_port(struct uart_port *port)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-
-       return request_mem_region(sport->port.mapbase, UART_PORT_SIZE,
-                       "sa11x0-uart") != NULL ? 0 : -EBUSY;
-}
-
-/*
- * Configure/autoconfigure the port.
- */
-static void sa1100_config_port(struct uart_port *port, int flags)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-
-       if (flags & UART_CONFIG_TYPE &&
-           sa1100_request_port(&sport->port) == 0)
-               sport->port.type = PORT_SA1100;
-}
-
-/*
- * Verify the new serial_struct (for TIOCSSERIAL).
- * The only change we allow are to the flags and type, and
- * even then only between PORT_SA1100 and PORT_UNKNOWN
- */
-static int
-sa1100_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-       int ret = 0;
-
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_SA1100)
-               ret = -EINVAL;
-       if (sport->port.irq != ser->irq)
-               ret = -EINVAL;
-       if (ser->io_type != SERIAL_IO_MEM)
-               ret = -EINVAL;
-       if (sport->port.uartclk / 16 != ser->baud_base)
-               ret = -EINVAL;
-       if ((void *)sport->port.mapbase != ser->iomem_base)
-               ret = -EINVAL;
-       if (sport->port.iobase != ser->port)
-               ret = -EINVAL;
-       if (ser->hub6 != 0)
-               ret = -EINVAL;
-       return ret;
-}
-
-static struct uart_ops sa1100_pops = {
-       .tx_empty       = sa1100_tx_empty,
-       .set_mctrl      = sa1100_set_mctrl,
-       .get_mctrl      = sa1100_get_mctrl,
-       .stop_tx        = sa1100_stop_tx,
-       .start_tx       = sa1100_start_tx,
-       .stop_rx        = sa1100_stop_rx,
-       .enable_ms      = sa1100_enable_ms,
-       .break_ctl      = sa1100_break_ctl,
-       .startup        = sa1100_startup,
-       .shutdown       = sa1100_shutdown,
-       .set_termios    = sa1100_set_termios,
-       .type           = sa1100_type,
-       .release_port   = sa1100_release_port,
-       .request_port   = sa1100_request_port,
-       .config_port    = sa1100_config_port,
-       .verify_port    = sa1100_verify_port,
-};
-
-static struct sa1100_port sa1100_ports[NR_PORTS];
-
-/*
- * Setup the SA1100 serial ports.  Note that we don't include the IrDA
- * port here since we have our own SIR/FIR driver (see drivers/net/irda)
- *
- * Note also that we support "console=ttySAx" where "x" is either 0 or 1.
- * Which serial port this ends up being depends on the machine you're
- * running this kernel on.  I'm not convinced that this is a good idea,
- * but that's the way it traditionally works.
- *
- * Note that NanoEngine UART3 becomes UART2, and UART2 is no longer
- * used here.
- */
-static void __init sa1100_init_ports(void)
-{
-       static int first = 1;
-       int i;
-
-       if (!first)
-               return;
-       first = 0;
-
-       for (i = 0; i < NR_PORTS; i++) {
-               sa1100_ports[i].port.uartclk   = 3686400;
-               sa1100_ports[i].port.ops       = &sa1100_pops;
-               sa1100_ports[i].port.fifosize  = 8;
-               sa1100_ports[i].port.line      = i;
-               sa1100_ports[i].port.iotype    = UPIO_MEM;
-               init_timer(&sa1100_ports[i].timer);
-               sa1100_ports[i].timer.function = sa1100_timeout;
-               sa1100_ports[i].timer.data     = (unsigned long)&sa1100_ports[i];
-       }
-
-       /*
-        * make transmit lines outputs, so that when the port
-        * is closed, the output is in the MARK state.
-        */
-       PPDR |= PPC_TXD1 | PPC_TXD3;
-       PPSR |= PPC_TXD1 | PPC_TXD3;
-}
-
-void __devinit sa1100_register_uart_fns(struct sa1100_port_fns *fns)
-{
-       if (fns->get_mctrl)
-               sa1100_pops.get_mctrl = fns->get_mctrl;
-       if (fns->set_mctrl)
-               sa1100_pops.set_mctrl = fns->set_mctrl;
-
-       sa1100_pops.pm       = fns->pm;
-       sa1100_pops.set_wake = fns->set_wake;
-}
-
-void __init sa1100_register_uart(int idx, int port)
-{
-       if (idx >= NR_PORTS) {
-               printk(KERN_ERR "%s: bad index number %d\n", __func__, idx);
-               return;
-       }
-
-       switch (port) {
-       case 1:
-               sa1100_ports[idx].port.membase = (void __iomem *)&Ser1UTCR0;
-               sa1100_ports[idx].port.mapbase = _Ser1UTCR0;
-               sa1100_ports[idx].port.irq     = IRQ_Ser1UART;
-               sa1100_ports[idx].port.flags   = UPF_BOOT_AUTOCONF;
-               break;
-
-       case 2:
-               sa1100_ports[idx].port.membase = (void __iomem *)&Ser2UTCR0;
-               sa1100_ports[idx].port.mapbase = _Ser2UTCR0;
-               sa1100_ports[idx].port.irq     = IRQ_Ser2ICP;
-               sa1100_ports[idx].port.flags   = UPF_BOOT_AUTOCONF;
-               break;
-
-       case 3:
-               sa1100_ports[idx].port.membase = (void __iomem *)&Ser3UTCR0;
-               sa1100_ports[idx].port.mapbase = _Ser3UTCR0;
-               sa1100_ports[idx].port.irq     = IRQ_Ser3UART;
-               sa1100_ports[idx].port.flags   = UPF_BOOT_AUTOCONF;
-               break;
-
-       default:
-               printk(KERN_ERR "%s: bad port number %d\n", __func__, port);
-       }
-}
-
-
-#ifdef CONFIG_SERIAL_SA1100_CONSOLE
-static void sa1100_console_putchar(struct uart_port *port, int ch)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-
-       while (!(UART_GET_UTSR1(sport) & UTSR1_TNF))
-               barrier();
-       UART_PUT_CHAR(sport, ch);
-}
-
-/*
- * Interrupts are disabled on entering
- */
-static void
-sa1100_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct sa1100_port *sport = &sa1100_ports[co->index];
-       unsigned int old_utcr3, status;
-
-       /*
-        *      First, save UTCR3 and then disable interrupts
-        */
-       old_utcr3 = UART_GET_UTCR3(sport);
-       UART_PUT_UTCR3(sport, (old_utcr3 & ~(UTCR3_RIE | UTCR3_TIE)) |
-                               UTCR3_TXE);
-
-       uart_console_write(&sport->port, s, count, sa1100_console_putchar);
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore UTCR3
-        */
-       do {
-               status = UART_GET_UTSR1(sport);
-       } while (status & UTSR1_TBY);
-       UART_PUT_UTCR3(sport, old_utcr3);
-}
-
-/*
- * If the port was already initialised (eg, by a boot loader),
- * try to determine the current setup.
- */
-static void __init
-sa1100_console_get_options(struct sa1100_port *sport, int *baud,
-                          int *parity, int *bits)
-{
-       unsigned int utcr3;
-
-       utcr3 = UART_GET_UTCR3(sport) & (UTCR3_RXE | UTCR3_TXE);
-       if (utcr3 == (UTCR3_RXE | UTCR3_TXE)) {
-               /* ok, the port was enabled */
-               unsigned int utcr0, quot;
-
-               utcr0 = UART_GET_UTCR0(sport);
-
-               *parity = 'n';
-               if (utcr0 & UTCR0_PE) {
-                       if (utcr0 & UTCR0_OES)
-                               *parity = 'e';
-                       else
-                               *parity = 'o';
-               }
-
-               if (utcr0 & UTCR0_DSS)
-                       *bits = 8;
-               else
-                       *bits = 7;
-
-               quot = UART_GET_UTCR2(sport) | UART_GET_UTCR1(sport) << 8;
-               quot &= 0xfff;
-               *baud = sport->port.uartclk / (16 * (quot + 1));
-       }
-}
-
-static int __init
-sa1100_console_setup(struct console *co, char *options)
-{
-       struct sa1100_port *sport;
-       int baud = 9600;
-       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.
-        */
-       if (co->index == -1 || co->index >= NR_PORTS)
-               co->index = 0;
-       sport = &sa1100_ports[co->index];
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               sa1100_console_get_options(sport, &baud, &parity, &bits);
-
-       return uart_set_options(&sport->port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver sa1100_reg;
-static struct console sa1100_console = {
-       .name           = "ttySA",
-       .write          = sa1100_console_write,
-       .device         = uart_console_device,
-       .setup          = sa1100_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &sa1100_reg,
-};
-
-static int __init sa1100_rs_console_init(void)
-{
-       sa1100_init_ports();
-       register_console(&sa1100_console);
-       return 0;
-}
-console_initcall(sa1100_rs_console_init);
-
-#define SA1100_CONSOLE &sa1100_console
-#else
-#define SA1100_CONSOLE NULL
-#endif
-
-static struct uart_driver sa1100_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "ttySA",
-       .dev_name               = "ttySA",
-       .major                  = SERIAL_SA1100_MAJOR,
-       .minor                  = MINOR_START,
-       .nr                     = NR_PORTS,
-       .cons                   = SA1100_CONSOLE,
-};
-
-static int sa1100_serial_suspend(struct platform_device *dev, pm_message_t state)
-{
-       struct sa1100_port *sport = platform_get_drvdata(dev);
-
-       if (sport)
-               uart_suspend_port(&sa1100_reg, &sport->port);
-
-       return 0;
-}
-
-static int sa1100_serial_resume(struct platform_device *dev)
-{
-       struct sa1100_port *sport = platform_get_drvdata(dev);
-
-       if (sport)
-               uart_resume_port(&sa1100_reg, &sport->port);
-
-       return 0;
-}
-
-static int sa1100_serial_probe(struct platform_device *dev)
-{
-       struct resource *res = dev->resource;
-       int i;
-
-       for (i = 0; i < dev->num_resources; i++, res++)
-               if (res->flags & IORESOURCE_MEM)
-                       break;
-
-       if (i < dev->num_resources) {
-               for (i = 0; i < NR_PORTS; i++) {
-                       if (sa1100_ports[i].port.mapbase != res->start)
-                               continue;
-
-                       sa1100_ports[i].port.dev = &dev->dev;
-                       uart_add_one_port(&sa1100_reg, &sa1100_ports[i].port);
-                       platform_set_drvdata(dev, &sa1100_ports[i]);
-                       break;
-               }
-       }
-
-       return 0;
-}
-
-static int sa1100_serial_remove(struct platform_device *pdev)
-{
-       struct sa1100_port *sport = platform_get_drvdata(pdev);
-
-       platform_set_drvdata(pdev, NULL);
-
-       if (sport)
-               uart_remove_one_port(&sa1100_reg, &sport->port);
-
-       return 0;
-}
-
-static struct platform_driver sa11x0_serial_driver = {
-       .probe          = sa1100_serial_probe,
-       .remove         = sa1100_serial_remove,
-       .suspend        = sa1100_serial_suspend,
-       .resume         = sa1100_serial_resume,
-       .driver         = {
-               .name   = "sa11x0-uart",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init sa1100_serial_init(void)
-{
-       int ret;
-
-       printk(KERN_INFO "Serial: SA11x0 driver\n");
-
-       sa1100_init_ports();
-
-       ret = uart_register_driver(&sa1100_reg);
-       if (ret == 0) {
-               ret = platform_driver_register(&sa11x0_serial_driver);
-               if (ret)
-                       uart_unregister_driver(&sa1100_reg);
-       }
-       return ret;
-}
-
-static void __exit sa1100_serial_exit(void)
-{
-       platform_driver_unregister(&sa11x0_serial_driver);
-       uart_unregister_driver(&sa1100_reg);
-}
-
-module_init(sa1100_serial_init);
-module_exit(sa1100_serial_exit);
-
-MODULE_AUTHOR("Deep Blue Solutions Ltd");
-MODULE_DESCRIPTION("SA1100 generic serial port driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_SA1100_MAJOR);
-MODULE_ALIAS("platform:sa11x0-uart");
diff --git a/drivers/serial/samsung.c b/drivers/serial/samsung.c
deleted file mode 100644 (file)
index 7ac2bf5..0000000
+++ /dev/null
@@ -1,1487 +0,0 @@
-/* linux/drivers/serial/samsuing.c
- *
- * Driver core for Samsung SoC onboard UARTs.
- *
- * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-/* Hote on 2410 error handling
- *
- * The s3c2410 manual has a love/hate affair with the contents of the
- * UERSTAT register in the UART blocks, and keeps marking some of the
- * error bits as reserved. Having checked with the s3c2410x01,
- * it copes with BREAKs properly, so I am happy to ignore the RESERVED
- * feature from the latter versions of the manual.
- *
- * If it becomes aparrent that latter versions of the 2410 remove these
- * bits, then action will have to be taken to differentiate the versions
- * and change the policy on BREAK
- *
- * BJD, 04-Nov-2004
-*/
-
-#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/sysrq.h>
-#include <linux/console.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/cpufreq.h>
-
-#include <asm/irq.h>
-
-#include <mach/hardware.h>
-#include <mach/map.h>
-
-#include <plat/regs-serial.h>
-
-#include "samsung.h"
-
-/* UART name and device definitions */
-
-#define S3C24XX_SERIAL_NAME    "ttySAC"
-#define S3C24XX_SERIAL_MAJOR   204
-#define S3C24XX_SERIAL_MINOR   64
-
-/* macros to change one thing to another */
-
-#define tx_enabled(port) ((port)->unused[0])
-#define rx_enabled(port) ((port)->unused[1])
-
-/* flag to ignore all characters comming in */
-#define RXSTAT_DUMMY_READ (0x10000000)
-
-static inline struct s3c24xx_uart_port *to_ourport(struct uart_port *port)
-{
-       return container_of(port, struct s3c24xx_uart_port, port);
-}
-
-/* translate a port to the device name */
-
-static inline const char *s3c24xx_serial_portname(struct uart_port *port)
-{
-       return to_platform_device(port->dev)->name;
-}
-
-static int s3c24xx_serial_txempty_nofifo(struct uart_port *port)
-{
-       return (rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE);
-}
-
-static void s3c24xx_serial_rx_enable(struct uart_port *port)
-{
-       unsigned long flags;
-       unsigned int ucon, ufcon;
-       int count = 10000;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       while (--count && !s3c24xx_serial_txempty_nofifo(port))
-               udelay(100);
-
-       ufcon = rd_regl(port, S3C2410_UFCON);
-       ufcon |= S3C2410_UFCON_RESETRX;
-       wr_regl(port, S3C2410_UFCON, ufcon);
-
-       ucon = rd_regl(port, S3C2410_UCON);
-       ucon |= S3C2410_UCON_RXIRQMODE;
-       wr_regl(port, S3C2410_UCON, ucon);
-
-       rx_enabled(port) = 1;
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void s3c24xx_serial_rx_disable(struct uart_port *port)
-{
-       unsigned long flags;
-       unsigned int ucon;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       ucon = rd_regl(port, S3C2410_UCON);
-       ucon &= ~S3C2410_UCON_RXIRQMODE;
-       wr_regl(port, S3C2410_UCON, ucon);
-
-       rx_enabled(port) = 0;
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void s3c24xx_serial_stop_tx(struct uart_port *port)
-{
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-
-       if (tx_enabled(port)) {
-               disable_irq_nosync(ourport->tx_irq);
-               tx_enabled(port) = 0;
-               if (port->flags & UPF_CONS_FLOW)
-                       s3c24xx_serial_rx_enable(port);
-       }
-}
-
-static void s3c24xx_serial_start_tx(struct uart_port *port)
-{
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-
-       if (!tx_enabled(port)) {
-               if (port->flags & UPF_CONS_FLOW)
-                       s3c24xx_serial_rx_disable(port);
-
-               enable_irq(ourport->tx_irq);
-               tx_enabled(port) = 1;
-       }
-}
-
-
-static void s3c24xx_serial_stop_rx(struct uart_port *port)
-{
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-
-       if (rx_enabled(port)) {
-               dbg("s3c24xx_serial_stop_rx: port=%p\n", port);
-               disable_irq_nosync(ourport->rx_irq);
-               rx_enabled(port) = 0;
-       }
-}
-
-static void s3c24xx_serial_enable_ms(struct uart_port *port)
-{
-}
-
-static inline struct s3c24xx_uart_info *s3c24xx_port_to_info(struct uart_port *port)
-{
-       return to_ourport(port)->info;
-}
-
-static inline struct s3c2410_uartcfg *s3c24xx_port_to_cfg(struct uart_port *port)
-{
-       if (port->dev == NULL)
-               return NULL;
-
-       return (struct s3c2410_uartcfg *)port->dev->platform_data;
-}
-
-static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
-                                    unsigned long ufstat)
-{
-       struct s3c24xx_uart_info *info = ourport->info;
-
-       if (ufstat & info->rx_fifofull)
-               return info->fifosize;
-
-       return (ufstat & info->rx_fifomask) >> info->rx_fifoshift;
-}
-
-
-/* ? - where has parity gone?? */
-#define S3C2410_UERSTAT_PARITY (0x1000)
-
-static irqreturn_t
-s3c24xx_serial_rx_chars(int irq, void *dev_id)
-{
-       struct s3c24xx_uart_port *ourport = dev_id;
-       struct uart_port *port = &ourport->port;
-       struct tty_struct *tty = port->state->port.tty;
-       unsigned int ufcon, ch, flag, ufstat, uerstat;
-       int max_count = 64;
-
-       while (max_count-- > 0) {
-               ufcon = rd_regl(port, S3C2410_UFCON);
-               ufstat = rd_regl(port, S3C2410_UFSTAT);
-
-               if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)
-                       break;
-
-               uerstat = rd_regl(port, S3C2410_UERSTAT);
-               ch = rd_regb(port, S3C2410_URXH);
-
-               if (port->flags & UPF_CONS_FLOW) {
-                       int txe = s3c24xx_serial_txempty_nofifo(port);
-
-                       if (rx_enabled(port)) {
-                               if (!txe) {
-                                       rx_enabled(port) = 0;
-                                       continue;
-                               }
-                       } else {
-                               if (txe) {
-                                       ufcon |= S3C2410_UFCON_RESETRX;
-                                       wr_regl(port, S3C2410_UFCON, ufcon);
-                                       rx_enabled(port) = 1;
-                                       goto out;
-                               }
-                               continue;
-                       }
-               }
-
-               /* insert the character into the buffer */
-
-               flag = TTY_NORMAL;
-               port->icount.rx++;
-
-               if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) {
-                       dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n",
-                           ch, uerstat);
-
-                       /* check for break */
-                       if (uerstat & S3C2410_UERSTAT_BREAK) {
-                               dbg("break!\n");
-                               port->icount.brk++;
-                               if (uart_handle_break(port))
-                                   goto ignore_char;
-                       }
-
-                       if (uerstat & S3C2410_UERSTAT_FRAME)
-                               port->icount.frame++;
-                       if (uerstat & S3C2410_UERSTAT_OVERRUN)
-                               port->icount.overrun++;
-
-                       uerstat &= port->read_status_mask;
-
-                       if (uerstat & S3C2410_UERSTAT_BREAK)
-                               flag = TTY_BREAK;
-                       else if (uerstat & S3C2410_UERSTAT_PARITY)
-                               flag = TTY_PARITY;
-                       else if (uerstat & (S3C2410_UERSTAT_FRAME |
-                                           S3C2410_UERSTAT_OVERRUN))
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(port, ch))
-                       goto ignore_char;
-
-               uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN,
-                                ch, flag);
-
- ignore_char:
-               continue;
-       }
-       tty_flip_buffer_push(tty);
-
- out:
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
-{
-       struct s3c24xx_uart_port *ourport = id;
-       struct uart_port *port = &ourport->port;
-       struct circ_buf *xmit = &port->state->xmit;
-       int count = 256;
-
-       if (port->x_char) {
-               wr_regb(port, S3C2410_UTXH, port->x_char);
-               port->icount.tx++;
-               port->x_char = 0;
-               goto out;
-       }
-
-       /* if there isnt anything more to transmit, or the uart is now
-        * stopped, disable the uart and exit
-       */
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               s3c24xx_serial_stop_tx(port);
-               goto out;
-       }
-
-       /* try and drain the buffer... */
-
-       while (!uart_circ_empty(xmit) && count-- > 0) {
-               if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
-                       break;
-
-               wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (uart_circ_empty(xmit))
-               s3c24xx_serial_stop_tx(port);
-
- out:
-       return IRQ_HANDLED;
-}
-
-static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port)
-{
-       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-       unsigned long ufstat = rd_regl(port, S3C2410_UFSTAT);
-       unsigned long ufcon = rd_regl(port, S3C2410_UFCON);
-
-       if (ufcon & S3C2410_UFCON_FIFOMODE) {
-               if ((ufstat & info->tx_fifomask) != 0 ||
-                   (ufstat & info->tx_fifofull))
-                       return 0;
-
-               return 1;
-       }
-
-       return s3c24xx_serial_txempty_nofifo(port);
-}
-
-/* no modem control lines */
-static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port)
-{
-       unsigned int umstat = rd_regb(port, S3C2410_UMSTAT);
-
-       if (umstat & S3C2410_UMSTAT_CTS)
-               return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
-       else
-               return TIOCM_CAR | TIOCM_DSR;
-}
-
-static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       /* todo - possibly remove AFC and do manual CTS */
-}
-
-static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
-{
-       unsigned long flags;
-       unsigned int ucon;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       ucon = rd_regl(port, S3C2410_UCON);
-
-       if (break_state)
-               ucon |= S3C2410_UCON_SBREAK;
-       else
-               ucon &= ~S3C2410_UCON_SBREAK;
-
-       wr_regl(port, S3C2410_UCON, ucon);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void s3c24xx_serial_shutdown(struct uart_port *port)
-{
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-
-       if (ourport->tx_claimed) {
-               free_irq(ourport->tx_irq, ourport);
-               tx_enabled(port) = 0;
-               ourport->tx_claimed = 0;
-       }
-
-       if (ourport->rx_claimed) {
-               free_irq(ourport->rx_irq, ourport);
-               ourport->rx_claimed = 0;
-               rx_enabled(port) = 0;
-       }
-}
-
-
-static int s3c24xx_serial_startup(struct uart_port *port)
-{
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-       int ret;
-
-       dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n",
-           port->mapbase, port->membase);
-
-       rx_enabled(port) = 1;
-
-       ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0,
-                         s3c24xx_serial_portname(port), ourport);
-
-       if (ret != 0) {
-               printk(KERN_ERR "cannot get irq %d\n", ourport->rx_irq);
-               return ret;
-       }
-
-       ourport->rx_claimed = 1;
-
-       dbg("requesting tx irq...\n");
-
-       tx_enabled(port) = 1;
-
-       ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0,
-                         s3c24xx_serial_portname(port), ourport);
-
-       if (ret) {
-               printk(KERN_ERR "cannot get irq %d\n", ourport->tx_irq);
-               goto err;
-       }
-
-       ourport->tx_claimed = 1;
-
-       dbg("s3c24xx_serial_startup ok\n");
-
-       /* the port reset code should have done the correct
-        * register setup for the port controls */
-
-       return ret;
-
- err:
-       s3c24xx_serial_shutdown(port);
-       return ret;
-}
-
-/* power power management control */
-
-static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
-                             unsigned int old)
-{
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-
-       ourport->pm_level = level;
-
-       switch (level) {
-       case 3:
-               if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
-                       clk_disable(ourport->baudclk);
-
-               clk_disable(ourport->clk);
-               break;
-
-       case 0:
-               clk_enable(ourport->clk);
-
-               if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
-                       clk_enable(ourport->baudclk);
-
-               break;
-       default:
-               printk(KERN_ERR "s3c24xx_serial: unknown pm %d\n", level);
-       }
-}
-
-/* baud rate calculation
- *
- * The UARTs on the S3C2410/S3C2440 can take their clocks from a number
- * of different sources, including the peripheral clock ("pclk") and an
- * external clock ("uclk"). The S3C2440 also adds the core clock ("fclk")
- * with a programmable extra divisor.
- *
- * The following code goes through the clock sources, and calculates the
- * baud clocks (and the resultant actual baud rates) and then tries to
- * pick the closest one and select that.
- *
-*/
-
-
-#define MAX_CLKS (8)
-
-static struct s3c24xx_uart_clksrc tmp_clksrc = {
-       .name           = "pclk",
-       .min_baud       = 0,
-       .max_baud       = 0,
-       .divisor        = 1,
-};
-
-static inline int
-s3c24xx_serial_getsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
-{
-       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-
-       return (info->get_clksrc)(port, c);
-}
-
-static inline int
-s3c24xx_serial_setsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
-{
-       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-
-       return (info->set_clksrc)(port, c);
-}
-
-struct baud_calc {
-       struct s3c24xx_uart_clksrc      *clksrc;
-       unsigned int                     calc;
-       unsigned int                     divslot;
-       unsigned int                     quot;
-       struct clk                      *src;
-};
-
-static int s3c24xx_serial_calcbaud(struct baud_calc *calc,
-                                  struct uart_port *port,
-                                  struct s3c24xx_uart_clksrc *clksrc,
-                                  unsigned int baud)
-{
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-       unsigned long rate;
-
-       calc->src = clk_get(port->dev, clksrc->name);
-       if (calc->src == NULL || IS_ERR(calc->src))
-               return 0;
-
-       rate = clk_get_rate(calc->src);
-       rate /= clksrc->divisor;
-
-       calc->clksrc = clksrc;
-
-       if (ourport->info->has_divslot) {
-               unsigned long div = rate / baud;
-
-               /* The UDIVSLOT register on the newer UARTs allows us to
-                * get a divisor adjustment of 1/16th on the baud clock.
-                *
-                * We don't keep the UDIVSLOT value (the 16ths we calculated
-                * by not multiplying the baud by 16) as it is easy enough
-                * to recalculate.
-                */
-
-               calc->quot = div / 16;
-               calc->calc = rate / div;
-       } else {
-               calc->quot = (rate + (8 * baud)) / (16 * baud);
-               calc->calc = (rate / (calc->quot * 16));
-       }
-
-       calc->quot--;
-       return 1;
-}
-
-static unsigned int s3c24xx_serial_getclk(struct uart_port *port,
-                                         struct s3c24xx_uart_clksrc **clksrc,
-                                         struct clk **clk,
-                                         unsigned int baud)
-{
-       struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
-       struct s3c24xx_uart_clksrc *clkp;
-       struct baud_calc res[MAX_CLKS];
-       struct baud_calc *resptr, *best, *sptr;
-       int i;
-
-       clkp = cfg->clocks;
-       best = NULL;
-
-       if (cfg->clocks_size < 2) {
-               if (cfg->clocks_size == 0)
-                       clkp = &tmp_clksrc;
-
-               /* check to see if we're sourcing fclk, and if so we're
-                * going to have to update the clock source
-                */
-
-               if (strcmp(clkp->name, "fclk") == 0) {
-                       struct s3c24xx_uart_clksrc src;
-
-                       s3c24xx_serial_getsource(port, &src);
-
-                       /* check that the port already using fclk, and if
-                        * not, then re-select fclk
-                        */
-
-                       if (strcmp(src.name, clkp->name) == 0) {
-                               s3c24xx_serial_setsource(port, clkp);
-                               s3c24xx_serial_getsource(port, &src);
-                       }
-
-                       clkp->divisor = src.divisor;
-               }
-
-               s3c24xx_serial_calcbaud(res, port, clkp, baud);
-               best = res;
-               resptr = best + 1;
-       } else {
-               resptr = res;
-
-               for (i = 0; i < cfg->clocks_size; i++, clkp++) {
-                       if (s3c24xx_serial_calcbaud(resptr, port, clkp, baud))
-                               resptr++;
-               }
-       }
-
-       /* ok, we now need to select the best clock we found */
-
-       if (!best) {
-               unsigned int deviation = (1<<30)|((1<<30)-1);
-               int calc_deviation;
-
-               for (sptr = res; sptr < resptr; sptr++) {
-                       calc_deviation = baud - sptr->calc;
-                       if (calc_deviation < 0)
-                               calc_deviation = -calc_deviation;
-
-                       if (calc_deviation < deviation) {
-                               best = sptr;
-                               deviation = calc_deviation;
-                       }
-               }
-       }
-
-       /* store results to pass back */
-
-       *clksrc = best->clksrc;
-       *clk    = best->src;
-
-       return best->quot;
-}
-
-/* udivslot_table[]
- *
- * This table takes the fractional value of the baud divisor and gives
- * the recommended setting for the UDIVSLOT register.
- */
-static u16 udivslot_table[16] = {
-       [0] = 0x0000,
-       [1] = 0x0080,
-       [2] = 0x0808,
-       [3] = 0x0888,
-       [4] = 0x2222,
-       [5] = 0x4924,
-       [6] = 0x4A52,
-       [7] = 0x54AA,
-       [8] = 0x5555,
-       [9] = 0xD555,
-       [10] = 0xD5D5,
-       [11] = 0xDDD5,
-       [12] = 0xDDDD,
-       [13] = 0xDFDD,
-       [14] = 0xDFDF,
-       [15] = 0xFFDF,
-};
-
-static void s3c24xx_serial_set_termios(struct uart_port *port,
-                                      struct ktermios *termios,
-                                      struct ktermios *old)
-{
-       struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-       struct s3c24xx_uart_clksrc *clksrc = NULL;
-       struct clk *clk = NULL;
-       unsigned long flags;
-       unsigned int baud, quot;
-       unsigned int ulcon;
-       unsigned int umcon;
-       unsigned int udivslot = 0;
-
-       /*
-        * We don't support modem control lines.
-        */
-       termios->c_cflag &= ~(HUPCL | CMSPAR);
-       termios->c_cflag |= CLOCAL;
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-
-       baud = uart_get_baud_rate(port, termios, old, 0, 115200*8);
-
-       if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
-               quot = port->custom_divisor;
-       else
-               quot = s3c24xx_serial_getclk(port, &clksrc, &clk, baud);
-
-       /* check to see if we need  to change clock source */
-
-       if (ourport->clksrc != clksrc || ourport->baudclk != clk) {
-               dbg("selecting clock %p\n", clk);
-               s3c24xx_serial_setsource(port, clksrc);
-
-               if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) {
-                       clk_disable(ourport->baudclk);
-                       ourport->baudclk  = NULL;
-               }
-
-               clk_enable(clk);
-
-               ourport->clksrc = clksrc;
-               ourport->baudclk = clk;
-               ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;
-       }
-
-       if (ourport->info->has_divslot) {
-               unsigned int div = ourport->baudclk_rate / baud;
-
-               if (cfg->has_fracval) {
-                       udivslot = (div & 15);
-                       dbg("fracval = %04x\n", udivslot);
-               } else {
-                       udivslot = udivslot_table[div & 15];
-                       dbg("udivslot = %04x (div %d)\n", udivslot, div & 15);
-               }
-       }
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               dbg("config: 5bits/char\n");
-               ulcon = S3C2410_LCON_CS5;
-               break;
-       case CS6:
-               dbg("config: 6bits/char\n");
-               ulcon = S3C2410_LCON_CS6;
-               break;
-       case CS7:
-               dbg("config: 7bits/char\n");
-               ulcon = S3C2410_LCON_CS7;
-               break;
-       case CS8:
-       default:
-               dbg("config: 8bits/char\n");
-               ulcon = S3C2410_LCON_CS8;
-               break;
-       }
-
-       /* preserve original lcon IR settings */
-       ulcon |= (cfg->ulcon & S3C2410_LCON_IRM);
-
-       if (termios->c_cflag & CSTOPB)
-               ulcon |= S3C2410_LCON_STOPB;
-
-       umcon = (termios->c_cflag & CRTSCTS) ? S3C2410_UMCOM_AFC : 0;
-
-       if (termios->c_cflag & PARENB) {
-               if (termios->c_cflag & PARODD)
-                       ulcon |= S3C2410_LCON_PODD;
-               else
-                       ulcon |= S3C2410_LCON_PEVEN;
-       } else {
-               ulcon |= S3C2410_LCON_PNONE;
-       }
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       dbg("setting ulcon to %08x, brddiv to %d, udivslot %08x\n",
-           ulcon, quot, udivslot);
-
-       wr_regl(port, S3C2410_ULCON, ulcon);
-       wr_regl(port, S3C2410_UBRDIV, quot);
-       wr_regl(port, S3C2410_UMCON, umcon);
-
-       if (ourport->info->has_divslot)
-               wr_regl(port, S3C2443_DIVSLOT, udivslot);
-
-       dbg("uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n",
-           rd_regl(port, S3C2410_ULCON),
-           rd_regl(port, S3C2410_UCON),
-           rd_regl(port, S3C2410_UFCON));
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       /*
-        * Which character status flags are we interested in?
-        */
-       port->read_status_mask = S3C2410_UERSTAT_OVERRUN;
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_PARITY;
-
-       /*
-        * Which character status flags should we ignore?
-        */
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= S3C2410_UERSTAT_OVERRUN;
-       if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= S3C2410_UERSTAT_FRAME;
-
-       /*
-        * Ignore all characters if CREAD is not set.
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               port->ignore_status_mask |= RXSTAT_DUMMY_READ;
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *s3c24xx_serial_type(struct uart_port *port)
-{
-       switch (port->type) {
-       case PORT_S3C2410:
-               return "S3C2410";
-       case PORT_S3C2440:
-               return "S3C2440";
-       case PORT_S3C2412:
-               return "S3C2412";
-       case PORT_S3C6400:
-               return "S3C6400/10";
-       default:
-               return NULL;
-       }
-}
-
-#define MAP_SIZE (0x100)
-
-static void s3c24xx_serial_release_port(struct uart_port *port)
-{
-       release_mem_region(port->mapbase, MAP_SIZE);
-}
-
-static int s3c24xx_serial_request_port(struct uart_port *port)
-{
-       const char *name = s3c24xx_serial_portname(port);
-       return request_mem_region(port->mapbase, MAP_SIZE, name) ? 0 : -EBUSY;
-}
-
-static void s3c24xx_serial_config_port(struct uart_port *port, int flags)
-{
-       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-
-       if (flags & UART_CONFIG_TYPE &&
-           s3c24xx_serial_request_port(port) == 0)
-               port->type = info->type;
-}
-
-/*
- * verify the new serial_struct (for TIOCSSERIAL).
- */
-static int
-s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-
-       if (ser->type != PORT_UNKNOWN && ser->type != info->type)
-               return -EINVAL;
-
-       return 0;
-}
-
-
-#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
-
-static struct console s3c24xx_serial_console;
-
-#define S3C24XX_SERIAL_CONSOLE &s3c24xx_serial_console
-#else
-#define S3C24XX_SERIAL_CONSOLE NULL
-#endif
-
-static struct uart_ops s3c24xx_serial_ops = {
-       .pm             = s3c24xx_serial_pm,
-       .tx_empty       = s3c24xx_serial_tx_empty,
-       .get_mctrl      = s3c24xx_serial_get_mctrl,
-       .set_mctrl      = s3c24xx_serial_set_mctrl,
-       .stop_tx        = s3c24xx_serial_stop_tx,
-       .start_tx       = s3c24xx_serial_start_tx,
-       .stop_rx        = s3c24xx_serial_stop_rx,
-       .enable_ms      = s3c24xx_serial_enable_ms,
-       .break_ctl      = s3c24xx_serial_break_ctl,
-       .startup        = s3c24xx_serial_startup,
-       .shutdown       = s3c24xx_serial_shutdown,
-       .set_termios    = s3c24xx_serial_set_termios,
-       .type           = s3c24xx_serial_type,
-       .release_port   = s3c24xx_serial_release_port,
-       .request_port   = s3c24xx_serial_request_port,
-       .config_port    = s3c24xx_serial_config_port,
-       .verify_port    = s3c24xx_serial_verify_port,
-};
-
-
-static struct uart_driver s3c24xx_uart_drv = {
-       .owner          = THIS_MODULE,
-       .dev_name       = "s3c2410_serial",
-       .nr             = CONFIG_SERIAL_SAMSUNG_UARTS,
-       .cons           = S3C24XX_SERIAL_CONSOLE,
-       .driver_name    = S3C24XX_SERIAL_NAME,
-       .major          = S3C24XX_SERIAL_MAJOR,
-       .minor          = S3C24XX_SERIAL_MINOR,
-};
-
-static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
-       [0] = {
-               .port = {
-                       .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),
-                       .iotype         = UPIO_MEM,
-                       .irq            = IRQ_S3CUART_RX0,
-                       .uartclk        = 0,
-                       .fifosize       = 16,
-                       .ops            = &s3c24xx_serial_ops,
-                       .flags          = UPF_BOOT_AUTOCONF,
-                       .line           = 0,
-               }
-       },
-       [1] = {
-               .port = {
-                       .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock),
-                       .iotype         = UPIO_MEM,
-                       .irq            = IRQ_S3CUART_RX1,
-                       .uartclk        = 0,
-                       .fifosize       = 16,
-                       .ops            = &s3c24xx_serial_ops,
-                       .flags          = UPF_BOOT_AUTOCONF,
-                       .line           = 1,
-               }
-       },
-#if CONFIG_SERIAL_SAMSUNG_UARTS > 2
-
-       [2] = {
-               .port = {
-                       .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock),
-                       .iotype         = UPIO_MEM,
-                       .irq            = IRQ_S3CUART_RX2,
-                       .uartclk        = 0,
-                       .fifosize       = 16,
-                       .ops            = &s3c24xx_serial_ops,
-                       .flags          = UPF_BOOT_AUTOCONF,
-                       .line           = 2,
-               }
-       },
-#endif
-#if CONFIG_SERIAL_SAMSUNG_UARTS > 3
-       [3] = {
-               .port = {
-                       .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock),
-                       .iotype         = UPIO_MEM,
-                       .irq            = IRQ_S3CUART_RX3,
-                       .uartclk        = 0,
-                       .fifosize       = 16,
-                       .ops            = &s3c24xx_serial_ops,
-                       .flags          = UPF_BOOT_AUTOCONF,
-                       .line           = 3,
-               }
-       }
-#endif
-};
-
-/* s3c24xx_serial_resetport
- *
- * wrapper to call the specific reset for this port (reset the fifos
- * and the settings)
-*/
-
-static inline int s3c24xx_serial_resetport(struct uart_port *port,
-                                          struct s3c2410_uartcfg *cfg)
-{
-       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-
-       return (info->reset_port)(port, cfg);
-}
-
-
-#ifdef CONFIG_CPU_FREQ
-
-static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb,
-                                            unsigned long val, void *data)
-{
-       struct s3c24xx_uart_port *port;
-       struct uart_port *uport;
-
-       port = container_of(nb, struct s3c24xx_uart_port, freq_transition);
-       uport = &port->port;
-
-       /* check to see if port is enabled */
-
-       if (port->pm_level != 0)
-               return 0;
-
-       /* try and work out if the baudrate is changing, we can detect
-        * a change in rate, but we do not have support for detecting
-        * a disturbance in the clock-rate over the change.
-        */
-
-       if (IS_ERR(port->clk))
-               goto exit;
-
-       if (port->baudclk_rate == clk_get_rate(port->clk))
-               goto exit;
-
-       if (val == CPUFREQ_PRECHANGE) {
-               /* we should really shut the port down whilst the
-                * frequency change is in progress. */
-
-       } else if (val == CPUFREQ_POSTCHANGE) {
-               struct ktermios *termios;
-               struct tty_struct *tty;
-
-               if (uport->state == NULL)
-                       goto exit;
-
-               tty = uport->state->port.tty;
-
-               if (tty == NULL)
-                       goto exit;
-
-               termios = tty->termios;
-
-               if (termios == NULL) {
-                       printk(KERN_WARNING "%s: no termios?\n", __func__);
-                       goto exit;
-               }
-
-               s3c24xx_serial_set_termios(uport, termios, NULL);
-       }
-
- exit:
-       return 0;
-}
-
-static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
-{
-       port->freq_transition.notifier_call = s3c24xx_serial_cpufreq_transition;
-
-       return cpufreq_register_notifier(&port->freq_transition,
-                                        CPUFREQ_TRANSITION_NOTIFIER);
-}
-
-static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
-{
-       cpufreq_unregister_notifier(&port->freq_transition,
-                                   CPUFREQ_TRANSITION_NOTIFIER);
-}
-
-#else
-static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
-{
-       return 0;
-}
-
-static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
-{
-}
-#endif
-
-/* s3c24xx_serial_init_port
- *
- * initialise a single serial port from the platform device given
- */
-
-static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
-                                   struct s3c24xx_uart_info *info,
-                                   struct platform_device *platdev)
-{
-       struct uart_port *port = &ourport->port;
-       struct s3c2410_uartcfg *cfg;
-       struct resource *res;
-       int ret;
-
-       dbg("s3c24xx_serial_init_port: port=%p, platdev=%p\n", port, platdev);
-
-       if (platdev == NULL)
-               return -ENODEV;
-
-       cfg = s3c24xx_dev_to_cfg(&platdev->dev);
-
-       if (port->mapbase != 0)
-               return 0;
-
-       if (cfg->hwport > CONFIG_SERIAL_SAMSUNG_UARTS) {
-               printk(KERN_ERR "%s: port %d bigger than %d\n", __func__,
-                      cfg->hwport, CONFIG_SERIAL_SAMSUNG_UARTS);
-               return -ERANGE;
-       }
-
-       /* setup info for port */
-       port->dev       = &platdev->dev;
-       ourport->info   = info;
-
-       /* copy the info in from provided structure */
-       ourport->port.fifosize = info->fifosize;
-
-       dbg("s3c24xx_serial_init_port: %p (hw %d)...\n", port, cfg->hwport);
-
-       port->uartclk = 1;
-
-       if (cfg->uart_flags & UPF_CONS_FLOW) {
-               dbg("s3c24xx_serial_init_port: enabling flow control\n");
-               port->flags |= UPF_CONS_FLOW;
-       }
-
-       /* sort our the physical and virtual addresses for each UART */
-
-       res = platform_get_resource(platdev, IORESOURCE_MEM, 0);
-       if (res == NULL) {
-               printk(KERN_ERR "failed to find memory resource for uart\n");
-               return -EINVAL;
-       }
-
-       dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);
-
-       port->mapbase = res->start;
-       port->membase = S3C_VA_UART + (res->start & 0xfffff);
-       ret = platform_get_irq(platdev, 0);
-       if (ret < 0)
-               port->irq = 0;
-       else {
-               port->irq = ret;
-               ourport->rx_irq = ret;
-               ourport->tx_irq = ret + 1;
-       }
-       
-       ret = platform_get_irq(platdev, 1);
-       if (ret > 0)
-               ourport->tx_irq = ret;
-
-       ourport->clk    = clk_get(&platdev->dev, "uart");
-
-       dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n",
-           port->mapbase, port->membase, port->irq,
-           ourport->rx_irq, ourport->tx_irq, port->uartclk);
-
-       /* reset the fifos (and setup the uart) */
-       s3c24xx_serial_resetport(port, cfg);
-       return 0;
-}
-
-static ssize_t s3c24xx_serial_show_clksrc(struct device *dev,
-                                         struct device_attribute *attr,
-                                         char *buf)
-{
-       struct uart_port *port = s3c24xx_dev_to_port(dev);
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-
-       return snprintf(buf, PAGE_SIZE, "* %s\n", ourport->clksrc->name);
-}
-
-static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL);
-
-/* Device driver serial port probe */
-
-static int probe_index;
-
-int s3c24xx_serial_probe(struct platform_device *dev,
-                        struct s3c24xx_uart_info *info)
-{
-       struct s3c24xx_uart_port *ourport;
-       int ret;
-
-       dbg("s3c24xx_serial_probe(%p, %p) %d\n", dev, info, probe_index);
-
-       ourport = &s3c24xx_serial_ports[probe_index];
-       probe_index++;
-
-       dbg("%s: initialising port %p...\n", __func__, ourport);
-
-       ret = s3c24xx_serial_init_port(ourport, info, dev);
-       if (ret < 0)
-               goto probe_err;
-
-       dbg("%s: adding port\n", __func__);
-       uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
-       platform_set_drvdata(dev, &ourport->port);
-
-       ret = device_create_file(&dev->dev, &dev_attr_clock_source);
-       if (ret < 0)
-               printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__);
-
-       ret = s3c24xx_serial_cpufreq_register(ourport);
-       if (ret < 0)
-               dev_err(&dev->dev, "failed to add cpufreq notifier\n");
-
-       return 0;
-
- probe_err:
-       return ret;
-}
-
-EXPORT_SYMBOL_GPL(s3c24xx_serial_probe);
-
-int __devexit s3c24xx_serial_remove(struct platform_device *dev)
-{
-       struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
-
-       if (port) {
-               s3c24xx_serial_cpufreq_deregister(to_ourport(port));
-               device_remove_file(&dev->dev, &dev_attr_clock_source);
-               uart_remove_one_port(&s3c24xx_uart_drv, port);
-       }
-
-       return 0;
-}
-
-EXPORT_SYMBOL_GPL(s3c24xx_serial_remove);
-
-/* UART power management code */
-
-#ifdef CONFIG_PM
-
-static int s3c24xx_serial_suspend(struct platform_device *dev, pm_message_t state)
-{
-       struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
-
-       if (port)
-               uart_suspend_port(&s3c24xx_uart_drv, port);
-
-       return 0;
-}
-
-static int s3c24xx_serial_resume(struct platform_device *dev)
-{
-       struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-
-       if (port) {
-               clk_enable(ourport->clk);
-               s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port));
-               clk_disable(ourport->clk);
-
-               uart_resume_port(&s3c24xx_uart_drv, port);
-       }
-
-       return 0;
-}
-#endif
-
-int s3c24xx_serial_init(struct platform_driver *drv,
-                       struct s3c24xx_uart_info *info)
-{
-       dbg("s3c24xx_serial_init(%p,%p)\n", drv, info);
-
-#ifdef CONFIG_PM
-       drv->suspend = s3c24xx_serial_suspend;
-       drv->resume = s3c24xx_serial_resume;
-#endif
-
-       return platform_driver_register(drv);
-}
-
-EXPORT_SYMBOL_GPL(s3c24xx_serial_init);
-
-/* module initialisation code */
-
-static int __init s3c24xx_serial_modinit(void)
-{
-       int ret;
-
-       ret = uart_register_driver(&s3c24xx_uart_drv);
-       if (ret < 0) {
-               printk(KERN_ERR "failed to register UART driver\n");
-               return -1;
-       }
-
-       return 0;
-}
-
-static void __exit s3c24xx_serial_modexit(void)
-{
-       uart_unregister_driver(&s3c24xx_uart_drv);
-}
-
-module_init(s3c24xx_serial_modinit);
-module_exit(s3c24xx_serial_modexit);
-
-/* Console code */
-
-#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
-
-static struct uart_port *cons_uart;
-
-static int
-s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon)
-{
-       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-       unsigned long ufstat, utrstat;
-
-       if (ufcon & S3C2410_UFCON_FIFOMODE) {
-               /* fifo mode - check amount of data in fifo registers... */
-
-               ufstat = rd_regl(port, S3C2410_UFSTAT);
-               return (ufstat & info->tx_fifofull) ? 0 : 1;
-       }
-
-       /* in non-fifo mode, we go and use the tx buffer empty */
-
-       utrstat = rd_regl(port, S3C2410_UTRSTAT);
-       return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0;
-}
-
-static void
-s3c24xx_serial_console_putchar(struct uart_port *port, int ch)
-{
-       unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
-       while (!s3c24xx_serial_console_txrdy(port, ufcon))
-               barrier();
-       wr_regb(cons_uart, S3C2410_UTXH, ch);
-}
-
-static void
-s3c24xx_serial_console_write(struct console *co, const char *s,
-                            unsigned int count)
-{
-       uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar);
-}
-
-static void __init
-s3c24xx_serial_get_options(struct uart_port *port, int *baud,
-                          int *parity, int *bits)
-{
-       struct s3c24xx_uart_clksrc clksrc;
-       struct clk *clk;
-       unsigned int ulcon;
-       unsigned int ucon;
-       unsigned int ubrdiv;
-       unsigned long rate;
-
-       ulcon  = rd_regl(port, S3C2410_ULCON);
-       ucon   = rd_regl(port, S3C2410_UCON);
-       ubrdiv = rd_regl(port, S3C2410_UBRDIV);
-
-       dbg("s3c24xx_serial_get_options: port=%p\n"
-           "registers: ulcon=%08x, ucon=%08x, ubdriv=%08x\n",
-           port, ulcon, ucon, ubrdiv);
-
-       if ((ucon & 0xf) != 0) {
-               /* consider the serial port configured if the tx/rx mode set */
-
-               switch (ulcon & S3C2410_LCON_CSMASK) {
-               case S3C2410_LCON_CS5:
-                       *bits = 5;
-                       break;
-               case S3C2410_LCON_CS6:
-                       *bits = 6;
-                       break;
-               case S3C2410_LCON_CS7:
-                       *bits = 7;
-                       break;
-               default:
-               case S3C2410_LCON_CS8:
-                       *bits = 8;
-                       break;
-               }
-
-               switch (ulcon & S3C2410_LCON_PMASK) {
-               case S3C2410_LCON_PEVEN:
-                       *parity = 'e';
-                       break;
-
-               case S3C2410_LCON_PODD:
-                       *parity = 'o';
-                       break;
-
-               case S3C2410_LCON_PNONE:
-               default:
-                       *parity = 'n';
-               }
-
-               /* now calculate the baud rate */
-
-               s3c24xx_serial_getsource(port, &clksrc);
-
-               clk = clk_get(port->dev, clksrc.name);
-               if (!IS_ERR(clk) && clk != NULL)
-                       rate = clk_get_rate(clk) / clksrc.divisor;
-               else
-                       rate = 1;
-
-
-               *baud = rate / (16 * (ubrdiv + 1));
-               dbg("calculated baud %d\n", *baud);
-       }
-
-}
-
-/* s3c24xx_serial_init_ports
- *
- * initialise the serial ports from the machine provided initialisation
- * data.
-*/
-
-static int s3c24xx_serial_init_ports(struct s3c24xx_uart_info **info)
-{
-       struct s3c24xx_uart_port *ptr = s3c24xx_serial_ports;
-       struct platform_device **platdev_ptr;
-       int i;
-
-       dbg("s3c24xx_serial_init_ports: initialising ports...\n");
-
-       platdev_ptr = s3c24xx_uart_devs;
-
-       for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++, ptr++, platdev_ptr++) {
-               s3c24xx_serial_init_port(ptr, info[i], *platdev_ptr);
-       }
-
-       return 0;
-}
-
-static int __init
-s3c24xx_serial_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       dbg("s3c24xx_serial_console_setup: co=%p (%d), %s\n",
-           co, co->index, options);
-
-       /* is this a valid port */
-
-       if (co->index == -1 || co->index >= CONFIG_SERIAL_SAMSUNG_UARTS)
-               co->index = 0;
-
-       port = &s3c24xx_serial_ports[co->index].port;
-
-       /* is the port configured? */
-
-       if (port->mapbase == 0x0) {
-               co->index = 0;
-               port = &s3c24xx_serial_ports[co->index].port;
-       }
-
-       cons_uart = port;
-
-       dbg("s3c24xx_serial_console_setup: port=%p (%d)\n", port, co->index);
-
-       /*
-        * Check whether an invalid uart number has been specified, and
-        * if so, search for the first available port that does have
-        * console support.
-        */
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               s3c24xx_serial_get_options(port, &baud, &parity, &bits);
-
-       dbg("s3c24xx_serial_console_setup: baud %d\n", baud);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-/* s3c24xx_serial_initconsole
- *
- * initialise the console from one of the uart drivers
-*/
-
-static struct console s3c24xx_serial_console = {
-       .name           = S3C24XX_SERIAL_NAME,
-       .device         = uart_console_device,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .write          = s3c24xx_serial_console_write,
-       .setup          = s3c24xx_serial_console_setup
-};
-
-int s3c24xx_serial_initconsole(struct platform_driver *drv,
-                              struct s3c24xx_uart_info **info)
-
-{
-       struct platform_device *dev = s3c24xx_uart_devs[0];
-
-       dbg("s3c24xx_serial_initconsole\n");
-
-       /* select driver based on the cpu */
-
-       if (dev == NULL) {
-               printk(KERN_ERR "s3c24xx: no devices for console init\n");
-               return 0;
-       }
-
-       if (strcmp(dev->name, drv->driver.name) != 0)
-               return 0;
-
-       s3c24xx_serial_console.data = &s3c24xx_uart_drv;
-       s3c24xx_serial_init_ports(info);
-
-       register_console(&s3c24xx_serial_console);
-       return 0;
-}
-
-#endif /* CONFIG_SERIAL_SAMSUNG_CONSOLE */
-
-MODULE_DESCRIPTION("Samsung SoC Serial port driver");
-MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/serial/samsung.h b/drivers/serial/samsung.h
deleted file mode 100644 (file)
index 0ac06a0..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/* linux/drivers/serial/samsung.h
- *
- * Driver for Samsung SoC onboard UARTs.
- *
- * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-struct s3c24xx_uart_info {
-       char                    *name;
-       unsigned int            type;
-       unsigned int            fifosize;
-       unsigned long           rx_fifomask;
-       unsigned long           rx_fifoshift;
-       unsigned long           rx_fifofull;
-       unsigned long           tx_fifomask;
-       unsigned long           tx_fifoshift;
-       unsigned long           tx_fifofull;
-
-       /* uart port features */
-
-       unsigned int            has_divslot:1;
-
-       /* clock source control */
-
-       int (*get_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk);
-       int (*set_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk);
-
-       /* uart controls */
-       int (*reset_port)(struct uart_port *, struct s3c2410_uartcfg *);
-};
-
-struct s3c24xx_uart_port {
-       unsigned char                   rx_claimed;
-       unsigned char                   tx_claimed;
-       unsigned int                    pm_level;
-       unsigned long                   baudclk_rate;
-
-       unsigned int                    rx_irq;
-       unsigned int                    tx_irq;
-
-       struct s3c24xx_uart_info        *info;
-       struct s3c24xx_uart_clksrc      *clksrc;
-       struct clk                      *clk;
-       struct clk                      *baudclk;
-       struct uart_port                port;
-
-#ifdef CONFIG_CPU_FREQ
-       struct notifier_block           freq_transition;
-#endif
-};
-
-/* conversion functions */
-
-#define s3c24xx_dev_to_port(__dev) (struct uart_port *)dev_get_drvdata(__dev)
-#define s3c24xx_dev_to_cfg(__dev) (struct s3c2410_uartcfg *)((__dev)->platform_data)
-
-/* register access controls */
-
-#define portaddr(port, reg) ((port)->membase + (reg))
-
-#define rd_regb(port, reg) (__raw_readb(portaddr(port, reg)))
-#define rd_regl(port, reg) (__raw_readl(portaddr(port, reg)))
-
-#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg))
-#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg))
-
-extern int s3c24xx_serial_probe(struct platform_device *dev,
-                               struct s3c24xx_uart_info *uart);
-
-extern int __devexit s3c24xx_serial_remove(struct platform_device *dev);
-
-extern int s3c24xx_serial_initconsole(struct platform_driver *drv,
-                                     struct s3c24xx_uart_info **uart);
-
-extern int s3c24xx_serial_init(struct platform_driver *drv,
-                              struct s3c24xx_uart_info *info);
-
-#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
-
-#define s3c24xx_console_init(__drv, __inf)                             \
-static int __init s3c_serial_console_init(void)                                \
-{                                                                      \
-       struct s3c24xx_uart_info *uinfo[CONFIG_SERIAL_SAMSUNG_UARTS];   \
-       int i;                                                          \
-                                                                       \
-       for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++)               \
-               uinfo[i] = __inf;                                       \
-       return s3c24xx_serial_initconsole(__drv, uinfo);                \
-}                                                                      \
-                                                                       \
-console_initcall(s3c_serial_console_init)
-
-#else
-#define s3c24xx_console_init(drv, inf) extern void no_console(void)
-#endif
-
-#ifdef CONFIG_SERIAL_SAMSUNG_DEBUG
-
-extern void printascii(const char *);
-
-static void dbg(const char *fmt, ...)
-{
-       va_list va;
-       char buff[256];
-
-       va_start(va, fmt);
-       vsprintf(buff, fmt, va);
-       va_end(va);
-
-       printascii(buff);
-}
-
-#else
-#define dbg(x...) do { } while (0)
-#endif
diff --git a/drivers/serial/sb1250-duart.c b/drivers/serial/sb1250-duart.c
deleted file mode 100644 (file)
index a2f2b32..0000000
+++ /dev/null
@@ -1,976 +0,0 @@
-/*
- *     drivers/serial/sb1250-duart.c
- *
- *     Support for the asynchronous serial interface (DUART) included
- *     in the BCM1250 and derived System-On-a-Chip (SOC) devices.
- *
- *     Copyright (c) 2007  Maciej W. Rozycki
- *
- *     Derived from drivers/char/sb1250_duart.c for which the following
- *     copyright applies:
- *
- *     Copyright (c) 2000, 2001, 2002, 2003, 2004  Broadcom Corporation
- *
- *     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.
- *
- *     References:
- *
- *     "BCM1250/BCM1125/BCM1125H User Manual", Broadcom Corporation
- */
-
-#if defined(CONFIG_SERIAL_SB1250_DUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/compiler.h>
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <linux/spinlock.h>
-#include <linux/sysrq.h>
-#include <linux/tty.h>
-#include <linux/types.h>
-
-#include <asm/atomic.h>
-#include <asm/io.h>
-#include <asm/war.h>
-
-#include <asm/sibyte/sb1250.h>
-#include <asm/sibyte/sb1250_uart.h>
-#include <asm/sibyte/swarm.h>
-
-
-#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
-#include <asm/sibyte/bcm1480_regs.h>
-#include <asm/sibyte/bcm1480_int.h>
-
-#define SBD_CHANREGS(line)     A_BCM1480_DUART_CHANREG((line), 0)
-#define SBD_CTRLREGS(line)     A_BCM1480_DUART_CTRLREG((line), 0)
-#define SBD_INT(line)          (K_BCM1480_INT_UART_0 + (line))
-
-#define DUART_CHANREG_SPACING  BCM1480_DUART_CHANREG_SPACING
-
-#define R_DUART_IMRREG(line)   R_BCM1480_DUART_IMRREG(line)
-#define R_DUART_INCHREG(line)  R_BCM1480_DUART_INCHREG(line)
-#define R_DUART_ISRREG(line)   R_BCM1480_DUART_ISRREG(line)
-
-#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
-#include <asm/sibyte/sb1250_regs.h>
-#include <asm/sibyte/sb1250_int.h>
-
-#define SBD_CHANREGS(line)     A_DUART_CHANREG((line), 0)
-#define SBD_CTRLREGS(line)     A_DUART_CTRLREG(0)
-#define SBD_INT(line)          (K_INT_UART_0 + (line))
-
-#else
-#error invalid SB1250 UART configuration
-
-#endif
-
-
-MODULE_AUTHOR("Maciej W. Rozycki <macro@linux-mips.org>");
-MODULE_DESCRIPTION("BCM1xxx on-chip DUART serial driver");
-MODULE_LICENSE("GPL");
-
-
-#define DUART_MAX_CHIP 2
-#define DUART_MAX_SIDE 2
-
-/*
- * Per-port state.
- */
-struct sbd_port {
-       struct sbd_duart        *duart;
-       struct uart_port        port;
-       unsigned char __iomem   *memctrl;
-       int                     tx_stopped;
-       int                     initialised;
-};
-
-/*
- * Per-DUART state for the shared register space.
- */
-struct sbd_duart {
-       struct sbd_port         sport[2];
-       unsigned long           mapctrl;
-       atomic_t                map_guard;
-};
-
-#define to_sport(uport) container_of(uport, struct sbd_port, port)
-
-static struct sbd_duart sbd_duarts[DUART_MAX_CHIP];
-
-
-/*
- * Reading and writing SB1250 DUART registers.
- *
- * There are three register spaces: two per-channel ones and
- * a shared one.  We have to define accessors appropriately.
- * All registers are 64-bit and all but the Baud Rate Clock
- * registers only define 8 least significant bits.  There is
- * also a workaround to take into account.  Raw accessors use
- * the full register width, but cooked ones truncate it
- * intentionally so that the rest of the driver does not care.
- */
-static u64 __read_sbdchn(struct sbd_port *sport, int reg)
-{
-       void __iomem *csr = sport->port.membase + reg;
-
-       return __raw_readq(csr);
-}
-
-static u64 __read_sbdshr(struct sbd_port *sport, int reg)
-{
-       void __iomem *csr = sport->memctrl + reg;
-
-       return __raw_readq(csr);
-}
-
-static void __write_sbdchn(struct sbd_port *sport, int reg, u64 value)
-{
-       void __iomem *csr = sport->port.membase + reg;
-
-       __raw_writeq(value, csr);
-}
-
-static void __write_sbdshr(struct sbd_port *sport, int reg, u64 value)
-{
-       void __iomem *csr = sport->memctrl + reg;
-
-       __raw_writeq(value, csr);
-}
-
-/*
- * In bug 1956, we get glitches that can mess up uart registers.  This
- * "read-mode-reg after any register access" is an accepted workaround.
- */
-static void __war_sbd1956(struct sbd_port *sport)
-{
-       __read_sbdchn(sport, R_DUART_MODE_REG_1);
-       __read_sbdchn(sport, R_DUART_MODE_REG_2);
-}
-
-static unsigned char read_sbdchn(struct sbd_port *sport, int reg)
-{
-       unsigned char retval;
-
-       retval = __read_sbdchn(sport, reg);
-       if (SIBYTE_1956_WAR)
-               __war_sbd1956(sport);
-       return retval;
-}
-
-static unsigned char read_sbdshr(struct sbd_port *sport, int reg)
-{
-       unsigned char retval;
-
-       retval = __read_sbdshr(sport, reg);
-       if (SIBYTE_1956_WAR)
-               __war_sbd1956(sport);
-       return retval;
-}
-
-static void write_sbdchn(struct sbd_port *sport, int reg, unsigned int value)
-{
-       __write_sbdchn(sport, reg, value);
-       if (SIBYTE_1956_WAR)
-               __war_sbd1956(sport);
-}
-
-static void write_sbdshr(struct sbd_port *sport, int reg, unsigned int value)
-{
-       __write_sbdshr(sport, reg, value);
-       if (SIBYTE_1956_WAR)
-               __war_sbd1956(sport);
-}
-
-
-static int sbd_receive_ready(struct sbd_port *sport)
-{
-       return read_sbdchn(sport, R_DUART_STATUS) & M_DUART_RX_RDY;
-}
-
-static int sbd_receive_drain(struct sbd_port *sport)
-{
-       int loops = 10000;
-
-       while (sbd_receive_ready(sport) && --loops)
-               read_sbdchn(sport, R_DUART_RX_HOLD);
-       return loops;
-}
-
-static int __maybe_unused sbd_transmit_ready(struct sbd_port *sport)
-{
-       return read_sbdchn(sport, R_DUART_STATUS) & M_DUART_TX_RDY;
-}
-
-static int __maybe_unused sbd_transmit_drain(struct sbd_port *sport)
-{
-       int loops = 10000;
-
-       while (!sbd_transmit_ready(sport) && --loops)
-               udelay(2);
-       return loops;
-}
-
-static int sbd_transmit_empty(struct sbd_port *sport)
-{
-       return read_sbdchn(sport, R_DUART_STATUS) & M_DUART_TX_EMT;
-}
-
-static int sbd_line_drain(struct sbd_port *sport)
-{
-       int loops = 10000;
-
-       while (!sbd_transmit_empty(sport) && --loops)
-               udelay(2);
-       return loops;
-}
-
-
-static unsigned int sbd_tx_empty(struct uart_port *uport)
-{
-       struct sbd_port *sport = to_sport(uport);
-
-       return sbd_transmit_empty(sport) ? TIOCSER_TEMT : 0;
-}
-
-static unsigned int sbd_get_mctrl(struct uart_port *uport)
-{
-       struct sbd_port *sport = to_sport(uport);
-       unsigned int mctrl, status;
-
-       status = read_sbdshr(sport, R_DUART_IN_PORT);
-       status >>= (uport->line) % 2;
-       mctrl = (!(status & M_DUART_IN_PIN0_VAL) ? TIOCM_CTS : 0) |
-               (!(status & M_DUART_IN_PIN4_VAL) ? TIOCM_CAR : 0) |
-               (!(status & M_DUART_RIN0_PIN) ? TIOCM_RNG : 0) |
-               (!(status & M_DUART_IN_PIN2_VAL) ? TIOCM_DSR : 0);
-       return mctrl;
-}
-
-static void sbd_set_mctrl(struct uart_port *uport, unsigned int mctrl)
-{
-       struct sbd_port *sport = to_sport(uport);
-       unsigned int clr = 0, set = 0, mode2;
-
-       if (mctrl & TIOCM_DTR)
-               set |= M_DUART_SET_OPR2;
-       else
-               clr |= M_DUART_CLR_OPR2;
-       if (mctrl & TIOCM_RTS)
-               set |= M_DUART_SET_OPR0;
-       else
-               clr |= M_DUART_CLR_OPR0;
-       clr <<= (uport->line) % 2;
-       set <<= (uport->line) % 2;
-
-       mode2 = read_sbdchn(sport, R_DUART_MODE_REG_2);
-       mode2 &= ~M_DUART_CHAN_MODE;
-       if (mctrl & TIOCM_LOOP)
-               mode2 |= V_DUART_CHAN_MODE_LCL_LOOP;
-       else
-               mode2 |= V_DUART_CHAN_MODE_NORMAL;
-
-       write_sbdshr(sport, R_DUART_CLEAR_OPR, clr);
-       write_sbdshr(sport, R_DUART_SET_OPR, set);
-       write_sbdchn(sport, R_DUART_MODE_REG_2, mode2);
-}
-
-static void sbd_stop_tx(struct uart_port *uport)
-{
-       struct sbd_port *sport = to_sport(uport);
-
-       write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS);
-       sport->tx_stopped = 1;
-};
-
-static void sbd_start_tx(struct uart_port *uport)
-{
-       struct sbd_port *sport = to_sport(uport);
-       unsigned int mask;
-
-       /* Enable tx interrupts.  */
-       mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2));
-       mask |= M_DUART_IMR_TX;
-       write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), mask);
-
-       /* Go!, go!, go!...  */
-       write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_EN);
-       sport->tx_stopped = 0;
-};
-
-static void sbd_stop_rx(struct uart_port *uport)
-{
-       struct sbd_port *sport = to_sport(uport);
-
-       write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), 0);
-};
-
-static void sbd_enable_ms(struct uart_port *uport)
-{
-       struct sbd_port *sport = to_sport(uport);
-
-       write_sbdchn(sport, R_DUART_AUXCTL_X,
-                    M_DUART_CIN_CHNG_ENA | M_DUART_CTS_CHNG_ENA);
-}
-
-static void sbd_break_ctl(struct uart_port *uport, int break_state)
-{
-       struct sbd_port *sport = to_sport(uport);
-
-       if (break_state == -1)
-               write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_START_BREAK);
-       else
-               write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_STOP_BREAK);
-}
-
-
-static void sbd_receive_chars(struct sbd_port *sport)
-{
-       struct uart_port *uport = &sport->port;
-       struct uart_icount *icount;
-       unsigned int status, ch, flag;
-       int count;
-
-       for (count = 16; count; count--) {
-               status = read_sbdchn(sport, R_DUART_STATUS);
-               if (!(status & M_DUART_RX_RDY))
-                       break;
-
-               ch = read_sbdchn(sport, R_DUART_RX_HOLD);
-
-               flag = TTY_NORMAL;
-
-               icount = &uport->icount;
-               icount->rx++;
-
-               if (unlikely(status &
-                            (M_DUART_RCVD_BRK | M_DUART_FRM_ERR |
-                             M_DUART_PARITY_ERR | M_DUART_OVRUN_ERR))) {
-                       if (status & M_DUART_RCVD_BRK) {
-                               icount->brk++;
-                               if (uart_handle_break(uport))
-                                       continue;
-                       } else if (status & M_DUART_FRM_ERR)
-                               icount->frame++;
-                       else if (status & M_DUART_PARITY_ERR)
-                               icount->parity++;
-                       if (status & M_DUART_OVRUN_ERR)
-                               icount->overrun++;
-
-                       status &= uport->read_status_mask;
-                       if (status & M_DUART_RCVD_BRK)
-                               flag = TTY_BREAK;
-                       else if (status & M_DUART_FRM_ERR)
-                               flag = TTY_FRAME;
-                       else if (status & M_DUART_PARITY_ERR)
-                               flag = TTY_PARITY;
-               }
-
-               if (uart_handle_sysrq_char(uport, ch))
-                       continue;
-
-               uart_insert_char(uport, status, M_DUART_OVRUN_ERR, ch, flag);
-       }
-
-       tty_flip_buffer_push(uport->state->port.tty);
-}
-
-static void sbd_transmit_chars(struct sbd_port *sport)
-{
-       struct uart_port *uport = &sport->port;
-       struct circ_buf *xmit = &sport->port.state->xmit;
-       unsigned int mask;
-       int stop_tx;
-
-       /* XON/XOFF chars.  */
-       if (sport->port.x_char) {
-               write_sbdchn(sport, R_DUART_TX_HOLD, sport->port.x_char);
-               sport->port.icount.tx++;
-               sport->port.x_char = 0;
-               return;
-       }
-
-       /* If nothing to do or stopped or hardware stopped.  */
-       stop_tx = (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port));
-
-       /* Send char.  */
-       if (!stop_tx) {
-               write_sbdchn(sport, R_DUART_TX_HOLD, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               sport->port.icount.tx++;
-
-               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-                       uart_write_wakeup(&sport->port);
-       }
-
-       /* Are we are done?  */
-       if (stop_tx || uart_circ_empty(xmit)) {
-               /* Disable tx interrupts.  */
-               mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2));
-               mask &= ~M_DUART_IMR_TX;
-               write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), mask);
-       }
-}
-
-static void sbd_status_handle(struct sbd_port *sport)
-{
-       struct uart_port *uport = &sport->port;
-       unsigned int delta;
-
-       delta = read_sbdshr(sport, R_DUART_INCHREG((uport->line) % 2));
-       delta >>= (uport->line) % 2;
-
-       if (delta & (M_DUART_IN_PIN0_VAL << S_DUART_IN_PIN_CHNG))
-               uart_handle_cts_change(uport, !(delta & M_DUART_IN_PIN0_VAL));
-
-       if (delta & (M_DUART_IN_PIN2_VAL << S_DUART_IN_PIN_CHNG))
-               uport->icount.dsr++;
-
-       if (delta & ((M_DUART_IN_PIN2_VAL | M_DUART_IN_PIN0_VAL) <<
-                    S_DUART_IN_PIN_CHNG))
-               wake_up_interruptible(&uport->state->port.delta_msr_wait);
-}
-
-static irqreturn_t sbd_interrupt(int irq, void *dev_id)
-{
-       struct sbd_port *sport = dev_id;
-       struct uart_port *uport = &sport->port;
-       irqreturn_t status = IRQ_NONE;
-       unsigned int intstat;
-       int count;
-
-       for (count = 16; count; count--) {
-               intstat = read_sbdshr(sport,
-                                     R_DUART_ISRREG((uport->line) % 2));
-               intstat &= read_sbdshr(sport,
-                                      R_DUART_IMRREG((uport->line) % 2));
-               intstat &= M_DUART_ISR_ALL;
-               if (!intstat)
-                       break;
-
-               if (intstat & M_DUART_ISR_RX)
-                       sbd_receive_chars(sport);
-               if (intstat & M_DUART_ISR_IN)
-                       sbd_status_handle(sport);
-               if (intstat & M_DUART_ISR_TX)
-                       sbd_transmit_chars(sport);
-
-               status = IRQ_HANDLED;
-       }
-
-       return status;
-}
-
-
-static int sbd_startup(struct uart_port *uport)
-{
-       struct sbd_port *sport = to_sport(uport);
-       unsigned int mode1;
-       int ret;
-
-       ret = request_irq(sport->port.irq, sbd_interrupt,
-                         IRQF_SHARED, "sb1250-duart", sport);
-       if (ret)
-               return ret;
-
-       /* Clear the receive FIFO.  */
-       sbd_receive_drain(sport);
-
-       /* Clear the interrupt registers.  */
-       write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT);
-       read_sbdshr(sport, R_DUART_INCHREG((uport->line) % 2));
-
-       /* Set rx/tx interrupt to FIFO available.  */
-       mode1 = read_sbdchn(sport, R_DUART_MODE_REG_1);
-       mode1 &= ~(M_DUART_RX_IRQ_SEL_RXFULL | M_DUART_TX_IRQ_SEL_TXEMPT);
-       write_sbdchn(sport, R_DUART_MODE_REG_1, mode1);
-
-       /* Disable tx, enable rx.  */
-       write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS | M_DUART_RX_EN);
-       sport->tx_stopped = 1;
-
-       /* Enable interrupts.  */
-       write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2),
-                    M_DUART_IMR_IN | M_DUART_IMR_RX);
-
-       return 0;
-}
-
-static void sbd_shutdown(struct uart_port *uport)
-{
-       struct sbd_port *sport = to_sport(uport);
-
-       write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS | M_DUART_RX_DIS);
-       sport->tx_stopped = 1;
-       free_irq(sport->port.irq, sport);
-}
-
-
-static void sbd_init_port(struct sbd_port *sport)
-{
-       struct uart_port *uport = &sport->port;
-
-       if (sport->initialised)
-               return;
-
-       /* There is no DUART reset feature, so just set some sane defaults.  */
-       write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_TX);
-       write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_RX);
-       write_sbdchn(sport, R_DUART_MODE_REG_1, V_DUART_BITS_PER_CHAR_8);
-       write_sbdchn(sport, R_DUART_MODE_REG_2, 0);
-       write_sbdchn(sport, R_DUART_FULL_CTL,
-                    V_DUART_INT_TIME(0) | V_DUART_SIG_FULL(15));
-       write_sbdchn(sport, R_DUART_OPCR_X, 0);
-       write_sbdchn(sport, R_DUART_AUXCTL_X, 0);
-       write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), 0);
-
-       sport->initialised = 1;
-}
-
-static void sbd_set_termios(struct uart_port *uport, struct ktermios *termios,
-                           struct ktermios *old_termios)
-{
-       struct sbd_port *sport = to_sport(uport);
-       unsigned int mode1 = 0, mode2 = 0, aux = 0;
-       unsigned int mode1mask = 0, mode2mask = 0, auxmask = 0;
-       unsigned int oldmode1, oldmode2, oldaux;
-       unsigned int baud, brg;
-       unsigned int command;
-
-       mode1mask |= ~(M_DUART_PARITY_MODE | M_DUART_PARITY_TYPE_ODD |
-                      M_DUART_BITS_PER_CHAR);
-       mode2mask |= ~M_DUART_STOP_BIT_LEN_2;
-       auxmask |= ~M_DUART_CTS_CHNG_ENA;
-
-       /* Byte size.  */
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-       case CS6:
-               /* Unsupported, leave unchanged.  */
-               mode1mask |= M_DUART_PARITY_MODE;
-               break;
-       case CS7:
-               mode1 |= V_DUART_BITS_PER_CHAR_7;
-               break;
-       case CS8:
-       default:
-               mode1 |= V_DUART_BITS_PER_CHAR_8;
-               break;
-       }
-
-       /* Parity and stop bits.  */
-       if (termios->c_cflag & CSTOPB)
-               mode2 |= M_DUART_STOP_BIT_LEN_2;
-       else
-               mode2 |= M_DUART_STOP_BIT_LEN_1;
-       if (termios->c_cflag & PARENB)
-               mode1 |= V_DUART_PARITY_MODE_ADD;
-       else
-               mode1 |= V_DUART_PARITY_MODE_NONE;
-       if (termios->c_cflag & PARODD)
-               mode1 |= M_DUART_PARITY_TYPE_ODD;
-       else
-               mode1 |= M_DUART_PARITY_TYPE_EVEN;
-
-       baud = uart_get_baud_rate(uport, termios, old_termios, 1200, 5000000);
-       brg = V_DUART_BAUD_RATE(baud);
-       /* The actual lower bound is 1221bps, so compensate.  */
-       if (brg > M_DUART_CLK_COUNTER)
-               brg = M_DUART_CLK_COUNTER;
-
-       uart_update_timeout(uport, termios->c_cflag, baud);
-
-       uport->read_status_mask = M_DUART_OVRUN_ERR;
-       if (termios->c_iflag & INPCK)
-               uport->read_status_mask |= M_DUART_FRM_ERR |
-                                          M_DUART_PARITY_ERR;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               uport->read_status_mask |= M_DUART_RCVD_BRK;
-
-       uport->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               uport->ignore_status_mask |= M_DUART_FRM_ERR |
-                                            M_DUART_PARITY_ERR;
-       if (termios->c_iflag & IGNBRK) {
-               uport->ignore_status_mask |= M_DUART_RCVD_BRK;
-               if (termios->c_iflag & IGNPAR)
-                       uport->ignore_status_mask |= M_DUART_OVRUN_ERR;
-       }
-
-       if (termios->c_cflag & CREAD)
-               command = M_DUART_RX_EN;
-       else
-               command = M_DUART_RX_DIS;
-
-       if (termios->c_cflag & CRTSCTS)
-               aux |= M_DUART_CTS_CHNG_ENA;
-       else
-               aux &= ~M_DUART_CTS_CHNG_ENA;
-
-       spin_lock(&uport->lock);
-
-       if (sport->tx_stopped)
-               command |= M_DUART_TX_DIS;
-       else
-               command |= M_DUART_TX_EN;
-
-       oldmode1 = read_sbdchn(sport, R_DUART_MODE_REG_1) & mode1mask;
-       oldmode2 = read_sbdchn(sport, R_DUART_MODE_REG_2) & mode2mask;
-       oldaux = read_sbdchn(sport, R_DUART_AUXCTL_X) & auxmask;
-
-       if (!sport->tx_stopped)
-               sbd_line_drain(sport);
-       write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS | M_DUART_RX_DIS);
-
-       write_sbdchn(sport, R_DUART_MODE_REG_1, mode1 | oldmode1);
-       write_sbdchn(sport, R_DUART_MODE_REG_2, mode2 | oldmode2);
-       write_sbdchn(sport, R_DUART_CLK_SEL, brg);
-       write_sbdchn(sport, R_DUART_AUXCTL_X, aux | oldaux);
-
-       write_sbdchn(sport, R_DUART_CMD, command);
-
-       spin_unlock(&uport->lock);
-}
-
-
-static const char *sbd_type(struct uart_port *uport)
-{
-       return "SB1250 DUART";
-}
-
-static void sbd_release_port(struct uart_port *uport)
-{
-       struct sbd_port *sport = to_sport(uport);
-       struct sbd_duart *duart = sport->duart;
-       int map_guard;
-
-       iounmap(sport->memctrl);
-       sport->memctrl = NULL;
-       iounmap(uport->membase);
-       uport->membase = NULL;
-
-       map_guard = atomic_add_return(-1, &duart->map_guard);
-       if (!map_guard)
-               release_mem_region(duart->mapctrl, DUART_CHANREG_SPACING);
-       release_mem_region(uport->mapbase, DUART_CHANREG_SPACING);
-}
-
-static int sbd_map_port(struct uart_port *uport)
-{
-       const char *err = KERN_ERR "sbd: Cannot map MMIO\n";
-       struct sbd_port *sport = to_sport(uport);
-       struct sbd_duart *duart = sport->duart;
-
-       if (!uport->membase)
-               uport->membase = ioremap_nocache(uport->mapbase,
-                                                DUART_CHANREG_SPACING);
-       if (!uport->membase) {
-               printk(err);
-               return -ENOMEM;
-       }
-
-       if (!sport->memctrl)
-               sport->memctrl = ioremap_nocache(duart->mapctrl,
-                                                DUART_CHANREG_SPACING);
-       if (!sport->memctrl) {
-               printk(err);
-               iounmap(uport->membase);
-               uport->membase = NULL;
-               return -ENOMEM;
-       }
-
-       return 0;
-}
-
-static int sbd_request_port(struct uart_port *uport)
-{
-       const char *err = KERN_ERR "sbd: Unable to reserve MMIO resource\n";
-       struct sbd_duart *duart = to_sport(uport)->duart;
-       int map_guard;
-       int ret = 0;
-
-       if (!request_mem_region(uport->mapbase, DUART_CHANREG_SPACING,
-                               "sb1250-duart")) {
-               printk(err);
-               return -EBUSY;
-       }
-       map_guard = atomic_add_return(1, &duart->map_guard);
-       if (map_guard == 1) {
-               if (!request_mem_region(duart->mapctrl, DUART_CHANREG_SPACING,
-                                       "sb1250-duart")) {
-                       atomic_add(-1, &duart->map_guard);
-                       printk(err);
-                       ret = -EBUSY;
-               }
-       }
-       if (!ret) {
-               ret = sbd_map_port(uport);
-               if (ret) {
-                       map_guard = atomic_add_return(-1, &duart->map_guard);
-                       if (!map_guard)
-                               release_mem_region(duart->mapctrl,
-                                                  DUART_CHANREG_SPACING);
-               }
-       }
-       if (ret) {
-               release_mem_region(uport->mapbase, DUART_CHANREG_SPACING);
-               return ret;
-       }
-       return 0;
-}
-
-static void sbd_config_port(struct uart_port *uport, int flags)
-{
-       struct sbd_port *sport = to_sport(uport);
-
-       if (flags & UART_CONFIG_TYPE) {
-               if (sbd_request_port(uport))
-                       return;
-
-               uport->type = PORT_SB1250_DUART;
-
-               sbd_init_port(sport);
-       }
-}
-
-static int sbd_verify_port(struct uart_port *uport, struct serial_struct *ser)
-{
-       int ret = 0;
-
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_SB1250_DUART)
-               ret = -EINVAL;
-       if (ser->irq != uport->irq)
-               ret = -EINVAL;
-       if (ser->baud_base != uport->uartclk / 16)
-               ret = -EINVAL;
-       return ret;
-}
-
-
-static const struct uart_ops sbd_ops = {
-       .tx_empty       = sbd_tx_empty,
-       .set_mctrl      = sbd_set_mctrl,
-       .get_mctrl      = sbd_get_mctrl,
-       .stop_tx        = sbd_stop_tx,
-       .start_tx       = sbd_start_tx,
-       .stop_rx        = sbd_stop_rx,
-       .enable_ms      = sbd_enable_ms,
-       .break_ctl      = sbd_break_ctl,
-       .startup        = sbd_startup,
-       .shutdown       = sbd_shutdown,
-       .set_termios    = sbd_set_termios,
-       .type           = sbd_type,
-       .release_port   = sbd_release_port,
-       .request_port   = sbd_request_port,
-       .config_port    = sbd_config_port,
-       .verify_port    = sbd_verify_port,
-};
-
-/* Initialize SB1250 DUART port structures.  */
-static void __init sbd_probe_duarts(void)
-{
-       static int probed;
-       int chip, side;
-       int max_lines, line;
-
-       if (probed)
-               return;
-
-       /* Set the number of available units based on the SOC type.  */
-       switch (soc_type) {
-       case K_SYS_SOC_TYPE_BCM1x55:
-       case K_SYS_SOC_TYPE_BCM1x80:
-               max_lines = 4;
-               break;
-       default:
-               /* Assume at least two serial ports at the normal address.  */
-               max_lines = 2;
-               break;
-       }
-
-       probed = 1;
-
-       for (chip = 0, line = 0; chip < DUART_MAX_CHIP && line < max_lines;
-            chip++) {
-               sbd_duarts[chip].mapctrl = SBD_CTRLREGS(line);
-
-               for (side = 0; side < DUART_MAX_SIDE && line < max_lines;
-                    side++, line++) {
-                       struct sbd_port *sport = &sbd_duarts[chip].sport[side];
-                       struct uart_port *uport = &sport->port;
-
-                       sport->duart    = &sbd_duarts[chip];
-
-                       uport->irq      = SBD_INT(line);
-                       uport->uartclk  = 100000000 / 20 * 16;
-                       uport->fifosize = 16;
-                       uport->iotype   = UPIO_MEM;
-                       uport->flags    = UPF_BOOT_AUTOCONF;
-                       uport->ops      = &sbd_ops;
-                       uport->line     = line;
-                       uport->mapbase  = SBD_CHANREGS(line);
-               }
-       }
-}
-
-
-#ifdef CONFIG_SERIAL_SB1250_DUART_CONSOLE
-/*
- * Serial console stuff.  Very basic, polling driver for doing serial
- * console output.  The console_sem is held by the caller, so we
- * shouldn't be interrupted for more console activity.
- */
-static void sbd_console_putchar(struct uart_port *uport, int ch)
-{
-       struct sbd_port *sport = to_sport(uport);
-
-       sbd_transmit_drain(sport);
-       write_sbdchn(sport, R_DUART_TX_HOLD, ch);
-}
-
-static void sbd_console_write(struct console *co, const char *s,
-                             unsigned int count)
-{
-       int chip = co->index / DUART_MAX_SIDE;
-       int side = co->index % DUART_MAX_SIDE;
-       struct sbd_port *sport = &sbd_duarts[chip].sport[side];
-       struct uart_port *uport = &sport->port;
-       unsigned long flags;
-       unsigned int mask;
-
-       /* Disable transmit interrupts and enable the transmitter. */
-       spin_lock_irqsave(&uport->lock, flags);
-       mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2));
-       write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2),
-                    mask & ~M_DUART_IMR_TX);
-       write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_EN);
-       spin_unlock_irqrestore(&uport->lock, flags);
-
-       uart_console_write(&sport->port, s, count, sbd_console_putchar);
-
-       /* Restore transmit interrupts and the transmitter enable. */
-       spin_lock_irqsave(&uport->lock, flags);
-       sbd_line_drain(sport);
-       if (sport->tx_stopped)
-               write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS);
-       write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), mask);
-       spin_unlock_irqrestore(&uport->lock, flags);
-}
-
-static int __init sbd_console_setup(struct console *co, char *options)
-{
-       int chip = co->index / DUART_MAX_SIDE;
-       int side = co->index % DUART_MAX_SIDE;
-       struct sbd_port *sport = &sbd_duarts[chip].sport[side];
-       struct uart_port *uport = &sport->port;
-       int baud = 115200;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-       int ret;
-
-       if (!sport->duart)
-               return -ENXIO;
-
-       ret = sbd_map_port(uport);
-       if (ret)
-               return ret;
-
-       sbd_init_port(sport);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       return uart_set_options(uport, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver sbd_reg;
-static struct console sbd_console = {
-       .name   = "duart",
-       .write  = sbd_console_write,
-       .device = uart_console_device,
-       .setup  = sbd_console_setup,
-       .flags  = CON_PRINTBUFFER,
-       .index  = -1,
-       .data   = &sbd_reg
-};
-
-static int __init sbd_serial_console_init(void)
-{
-       sbd_probe_duarts();
-       register_console(&sbd_console);
-
-       return 0;
-}
-
-console_initcall(sbd_serial_console_init);
-
-#define SERIAL_SB1250_DUART_CONSOLE    &sbd_console
-#else
-#define SERIAL_SB1250_DUART_CONSOLE    NULL
-#endif /* CONFIG_SERIAL_SB1250_DUART_CONSOLE */
-
-
-static struct uart_driver sbd_reg = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "sb1250_duart",
-       .dev_name       = "duart",
-       .major          = TTY_MAJOR,
-       .minor          = SB1250_DUART_MINOR_BASE,
-       .nr             = DUART_MAX_CHIP * DUART_MAX_SIDE,
-       .cons           = SERIAL_SB1250_DUART_CONSOLE,
-};
-
-/* Set up the driver and register it.  */
-static int __init sbd_init(void)
-{
-       int i, ret;
-
-       sbd_probe_duarts();
-
-       ret = uart_register_driver(&sbd_reg);
-       if (ret)
-               return ret;
-
-       for (i = 0; i < DUART_MAX_CHIP * DUART_MAX_SIDE; i++) {
-               struct sbd_duart *duart = &sbd_duarts[i / DUART_MAX_SIDE];
-               struct sbd_port *sport = &duart->sport[i % DUART_MAX_SIDE];
-               struct uart_port *uport = &sport->port;
-
-               if (sport->duart)
-                       uart_add_one_port(&sbd_reg, uport);
-       }
-
-       return 0;
-}
-
-/* Unload the driver.  Unregister stuff, get ready to go away.  */
-static void __exit sbd_exit(void)
-{
-       int i;
-
-       for (i = DUART_MAX_CHIP * DUART_MAX_SIDE - 1; i >= 0; i--) {
-               struct sbd_duart *duart = &sbd_duarts[i / DUART_MAX_SIDE];
-               struct sbd_port *sport = &duart->sport[i % DUART_MAX_SIDE];
-               struct uart_port *uport = &sport->port;
-
-               if (sport->duart)
-                       uart_remove_one_port(&sbd_reg, uport);
-       }
-
-       uart_unregister_driver(&sbd_reg);
-}
-
-module_init(sbd_init);
-module_exit(sbd_exit);
diff --git a/drivers/serial/sc26xx.c b/drivers/serial/sc26xx.c
deleted file mode 100644 (file)
index 75038ad..0000000
+++ /dev/null
@@ -1,757 +0,0 @@
-/*
- * SC268xx.c: Serial driver for Philiphs SC2681/SC2692 devices.
- *
- * Copyright (C) 2006,2007 Thomas Bogendörfer (tsbogend@alpha.franken.de)
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/circ_buf.h>
-#include <linux/serial.h>
-#include <linux/sysrq.h>
-#include <linux/console.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/irq.h>
-
-#if defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
-#define SC26XX_MAJOR         204
-#define SC26XX_MINOR_START   205
-#define SC26XX_NR            2
-
-struct uart_sc26xx_port {
-       struct uart_port      port[2];
-       u8     dsr_mask[2];
-       u8     cts_mask[2];
-       u8     dcd_mask[2];
-       u8     ri_mask[2];
-       u8     dtr_mask[2];
-       u8     rts_mask[2];
-       u8     imr;
-};
-
-/* register common to both ports */
-#define RD_ISR      0x14
-#define RD_IPR      0x34
-
-#define WR_ACR      0x10
-#define WR_IMR      0x14
-#define WR_OPCR     0x34
-#define WR_OPR_SET  0x38
-#define WR_OPR_CLR  0x3C
-
-/* access common register */
-#define READ_SC(p, r)        readb((p)->membase + RD_##r)
-#define WRITE_SC(p, r, v)    writeb((v), (p)->membase + WR_##r)
-
-/* register per port */
-#define RD_PORT_MRx 0x00
-#define RD_PORT_SR  0x04
-#define RD_PORT_RHR 0x0c
-
-#define WR_PORT_MRx 0x00
-#define WR_PORT_CSR 0x04
-#define WR_PORT_CR  0x08
-#define WR_PORT_THR 0x0c
-
-/* SR bits */
-#define SR_BREAK    (1 << 7)
-#define SR_FRAME    (1 << 6)
-#define SR_PARITY   (1 << 5)
-#define SR_OVERRUN  (1 << 4)
-#define SR_TXRDY    (1 << 2)
-#define SR_RXRDY    (1 << 0)
-
-#define CR_RES_MR   (1 << 4)
-#define CR_RES_RX   (2 << 4)
-#define CR_RES_TX   (3 << 4)
-#define CR_STRT_BRK (6 << 4)
-#define CR_STOP_BRK (7 << 4)
-#define CR_DIS_TX   (1 << 3)
-#define CR_ENA_TX   (1 << 2)
-#define CR_DIS_RX   (1 << 1)
-#define CR_ENA_RX   (1 << 0)
-
-/* ISR bits */
-#define ISR_RXRDYB  (1 << 5)
-#define ISR_TXRDYB  (1 << 4)
-#define ISR_RXRDYA  (1 << 1)
-#define ISR_TXRDYA  (1 << 0)
-
-/* IMR bits */
-#define IMR_RXRDY   (1 << 1)
-#define IMR_TXRDY   (1 << 0)
-
-/* access port register */
-static inline u8 read_sc_port(struct uart_port *p, u8 reg)
-{
-       return readb(p->membase + p->line * 0x20 + reg);
-}
-
-static inline void write_sc_port(struct uart_port *p, u8 reg, u8 val)
-{
-       writeb(val, p->membase + p->line * 0x20 + reg);
-}
-
-#define READ_SC_PORT(p, r)     read_sc_port(p, RD_PORT_##r)
-#define WRITE_SC_PORT(p, r, v) write_sc_port(p, WR_PORT_##r, v)
-
-static void sc26xx_enable_irq(struct uart_port *port, int mask)
-{
-       struct uart_sc26xx_port *up;
-       int line = port->line;
-
-       port -= line;
-       up = container_of(port, struct uart_sc26xx_port, port[0]);
-
-       up->imr |= mask << (line * 4);
-       WRITE_SC(port, IMR, up->imr);
-}
-
-static void sc26xx_disable_irq(struct uart_port *port, int mask)
-{
-       struct uart_sc26xx_port *up;
-       int line = port->line;
-
-       port -= line;
-       up = container_of(port, struct uart_sc26xx_port, port[0]);
-
-       up->imr &= ~(mask << (line * 4));
-       WRITE_SC(port, IMR, up->imr);
-}
-
-static struct tty_struct *receive_chars(struct uart_port *port)
-{
-       struct tty_struct *tty = NULL;
-       int limit = 10000;
-       unsigned char ch;
-       char flag;
-       u8 status;
-
-       if (port->state != NULL)                /* Unopened serial console */
-               tty = port->state->port.tty;
-
-       while (limit-- > 0) {
-               status = READ_SC_PORT(port, SR);
-               if (!(status & SR_RXRDY))
-                       break;
-               ch = READ_SC_PORT(port, RHR);
-
-               flag = TTY_NORMAL;
-               port->icount.rx++;
-
-               if (unlikely(status & (SR_BREAK | SR_FRAME |
-                                      SR_PARITY | SR_OVERRUN))) {
-                       if (status & SR_BREAK) {
-                               status &= ~(SR_PARITY | SR_FRAME);
-                               port->icount.brk++;
-                               if (uart_handle_break(port))
-                                       continue;
-                       } else if (status & SR_PARITY)
-                               port->icount.parity++;
-                       else if (status & SR_FRAME)
-                               port->icount.frame++;
-                       if (status & SR_OVERRUN)
-                               port->icount.overrun++;
-
-                       status &= port->read_status_mask;
-                       if (status & SR_BREAK)
-                               flag = TTY_BREAK;
-                       else if (status & SR_PARITY)
-                               flag = TTY_PARITY;
-                       else if (status & SR_FRAME)
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(port, ch))
-                       continue;
-
-               if (status & port->ignore_status_mask)
-                       continue;
-
-               tty_insert_flip_char(tty, ch, flag);
-       }
-       return tty;
-}
-
-static void transmit_chars(struct uart_port *port)
-{
-       struct circ_buf *xmit;
-
-       if (!port->state)
-               return;
-
-       xmit = &port->state->xmit;
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               sc26xx_disable_irq(port, IMR_TXRDY);
-               return;
-       }
-       while (!uart_circ_empty(xmit)) {
-               if (!(READ_SC_PORT(port, SR) & SR_TXRDY))
-                       break;
-
-               WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-       }
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-}
-
-static irqreturn_t sc26xx_interrupt(int irq, void *dev_id)
-{
-       struct uart_sc26xx_port *up = dev_id;
-       struct tty_struct *tty;
-       unsigned long flags;
-       u8 isr;
-
-       spin_lock_irqsave(&up->port[0].lock, flags);
-
-       tty = NULL;
-       isr = READ_SC(&up->port[0], ISR);
-       if (isr & ISR_TXRDYA)
-           transmit_chars(&up->port[0]);
-       if (isr & ISR_RXRDYA)
-           tty = receive_chars(&up->port[0]);
-
-       spin_unlock(&up->port[0].lock);
-
-       if (tty)
-               tty_flip_buffer_push(tty);
-
-       spin_lock(&up->port[1].lock);
-
-       tty = NULL;
-       if (isr & ISR_TXRDYB)
-           transmit_chars(&up->port[1]);
-       if (isr & ISR_RXRDYB)
-           tty = receive_chars(&up->port[1]);
-
-       spin_unlock_irqrestore(&up->port[1].lock, flags);
-
-       if (tty)
-               tty_flip_buffer_push(tty);
-
-       return IRQ_HANDLED;
-}
-
-/* port->lock is not held.  */
-static unsigned int sc26xx_tx_empty(struct uart_port *port)
-{
-       return (READ_SC_PORT(port, SR) & SR_TXRDY) ? TIOCSER_TEMT : 0;
-}
-
-/* port->lock held by caller.  */
-static void sc26xx_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_sc26xx_port *up;
-       int line = port->line;
-
-       port -= line;
-       up = container_of(port, struct uart_sc26xx_port, port[0]);
-
-       if (up->dtr_mask[line]) {
-               if (mctrl & TIOCM_DTR)
-                       WRITE_SC(port, OPR_SET, up->dtr_mask[line]);
-               else
-                       WRITE_SC(port, OPR_CLR, up->dtr_mask[line]);
-       }
-       if (up->rts_mask[line]) {
-               if (mctrl & TIOCM_RTS)
-                       WRITE_SC(port, OPR_SET, up->rts_mask[line]);
-               else
-                       WRITE_SC(port, OPR_CLR, up->rts_mask[line]);
-       }
-}
-
-/* port->lock is held by caller and interrupts are disabled.  */
-static unsigned int sc26xx_get_mctrl(struct uart_port *port)
-{
-       struct uart_sc26xx_port *up;
-       int line = port->line;
-       unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR;
-       u8 ipr;
-
-       port -= line;
-       up = container_of(port, struct uart_sc26xx_port, port[0]);
-       ipr = READ_SC(port, IPR) ^ 0xff;
-
-       if (up->dsr_mask[line]) {
-               mctrl &= ~TIOCM_DSR;
-               mctrl |= ipr & up->dsr_mask[line] ? TIOCM_DSR : 0;
-       }
-       if (up->cts_mask[line]) {
-               mctrl &= ~TIOCM_CTS;
-               mctrl |= ipr & up->cts_mask[line] ? TIOCM_CTS : 0;
-       }
-       if (up->dcd_mask[line]) {
-               mctrl &= ~TIOCM_CAR;
-               mctrl |= ipr & up->dcd_mask[line] ? TIOCM_CAR : 0;
-       }
-       if (up->ri_mask[line]) {
-               mctrl &= ~TIOCM_RNG;
-               mctrl |= ipr & up->ri_mask[line] ? TIOCM_RNG : 0;
-       }
-       return mctrl;
-}
-
-/* port->lock held by caller.  */
-static void sc26xx_stop_tx(struct uart_port *port)
-{
-       return;
-}
-
-/* port->lock held by caller.  */
-static void sc26xx_start_tx(struct uart_port *port)
-{
-       struct circ_buf *xmit = &port->state->xmit;
-
-       while (!uart_circ_empty(xmit)) {
-               if (!(READ_SC_PORT(port, SR) & SR_TXRDY)) {
-                       sc26xx_enable_irq(port, IMR_TXRDY);
-                       break;
-               }
-               WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-       }
-}
-
-/* port->lock held by caller.  */
-static void sc26xx_stop_rx(struct uart_port *port)
-{
-}
-
-/* port->lock held by caller.  */
-static void sc26xx_enable_ms(struct uart_port *port)
-{
-}
-
-/* port->lock is not held.  */
-static void sc26xx_break_ctl(struct uart_port *port, int break_state)
-{
-       if (break_state == -1)
-               WRITE_SC_PORT(port, CR, CR_STRT_BRK);
-       else
-               WRITE_SC_PORT(port, CR, CR_STOP_BRK);
-}
-
-/* port->lock is not held.  */
-static int sc26xx_startup(struct uart_port *port)
-{
-       sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY);
-       WRITE_SC(port, OPCR, 0);
-
-       /* reset tx and rx */
-       WRITE_SC_PORT(port, CR, CR_RES_RX);
-       WRITE_SC_PORT(port, CR, CR_RES_TX);
-
-       /* start rx/tx */
-       WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX);
-
-       /* enable irqs */
-       sc26xx_enable_irq(port, IMR_RXRDY);
-       return 0;
-}
-
-/* port->lock is not held.  */
-static void sc26xx_shutdown(struct uart_port *port)
-{
-       /* disable interrupst */
-       sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY);
-
-       /* stop tx/rx */
-       WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX);
-}
-
-/* port->lock is not held.  */
-static void sc26xx_set_termios(struct uart_port *port, struct ktermios *termios,
-                             struct ktermios *old)
-{
-       unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
-       unsigned int quot = uart_get_divisor(port, baud);
-       unsigned int iflag, cflag;
-       unsigned long flags;
-       u8 mr1, mr2, csr;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc)
-               udelay(2);
-
-       WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX);
-
-       iflag = termios->c_iflag;
-       cflag = termios->c_cflag;
-
-       port->read_status_mask = SR_OVERRUN;
-       if (iflag & INPCK)
-               port->read_status_mask |= SR_PARITY | SR_FRAME;
-       if (iflag & (BRKINT | PARMRK))
-               port->read_status_mask |= SR_BREAK;
-
-       port->ignore_status_mask = 0;
-       if (iflag & IGNBRK)
-               port->ignore_status_mask |= SR_BREAK;
-       if ((cflag & CREAD) == 0)
-               port->ignore_status_mask |= SR_BREAK | SR_FRAME |
-                                           SR_PARITY | SR_OVERRUN;
-
-       switch (cflag & CSIZE) {
-       case CS5:
-               mr1 = 0x00;
-               break;
-       case CS6:
-               mr1 = 0x01;
-               break;
-       case CS7:
-               mr1 = 0x02;
-               break;
-       default:
-       case CS8:
-               mr1 = 0x03;
-               break;
-       }
-       mr2 = 0x07;
-       if (cflag & CSTOPB)
-               mr2 = 0x0f;
-       if (cflag & PARENB) {
-               if (cflag & PARODD)
-                       mr1 |= (1 << 2);
-       } else
-               mr1 |= (2 << 3);
-
-       switch (baud) {
-       case 50:
-               csr = 0x00;
-               break;
-       case 110:
-               csr = 0x11;
-               break;
-       case 134:
-               csr = 0x22;
-               break;
-       case 200:
-               csr = 0x33;
-               break;
-       case 300:
-               csr = 0x44;
-               break;
-       case 600:
-               csr = 0x55;
-               break;
-       case 1200:
-               csr = 0x66;
-               break;
-       case 2400:
-               csr = 0x88;
-               break;
-       case 4800:
-               csr = 0x99;
-               break;
-       default:
-       case 9600:
-               csr = 0xbb;
-               break;
-       case 19200:
-               csr = 0xcc;
-               break;
-       }
-
-       WRITE_SC_PORT(port, CR, CR_RES_MR);
-       WRITE_SC_PORT(port, MRx, mr1);
-       WRITE_SC_PORT(port, MRx, mr2);
-
-       WRITE_SC(port, ACR, 0x80);
-       WRITE_SC_PORT(port, CSR, csr);
-
-       /* reset tx and rx */
-       WRITE_SC_PORT(port, CR, CR_RES_RX);
-       WRITE_SC_PORT(port, CR, CR_RES_TX);
-
-       WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX);
-       while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc)
-               udelay(2);
-
-       /* XXX */
-       uart_update_timeout(port, cflag,
-                           (port->uartclk / (16 * quot)));
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *sc26xx_type(struct uart_port *port)
-{
-       return "SC26XX";
-}
-
-static void sc26xx_release_port(struct uart_port *port)
-{
-}
-
-static int sc26xx_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-static void sc26xx_config_port(struct uart_port *port, int flags)
-{
-}
-
-static int sc26xx_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       return -EINVAL;
-}
-
-static struct uart_ops sc26xx_ops = {
-       .tx_empty       = sc26xx_tx_empty,
-       .set_mctrl      = sc26xx_set_mctrl,
-       .get_mctrl      = sc26xx_get_mctrl,
-       .stop_tx        = sc26xx_stop_tx,
-       .start_tx       = sc26xx_start_tx,
-       .stop_rx        = sc26xx_stop_rx,
-       .enable_ms      = sc26xx_enable_ms,
-       .break_ctl      = sc26xx_break_ctl,
-       .startup        = sc26xx_startup,
-       .shutdown       = sc26xx_shutdown,
-       .set_termios    = sc26xx_set_termios,
-       .type           = sc26xx_type,
-       .release_port   = sc26xx_release_port,
-       .request_port   = sc26xx_request_port,
-       .config_port    = sc26xx_config_port,
-       .verify_port    = sc26xx_verify_port,
-};
-
-static struct uart_port *sc26xx_port;
-
-#ifdef CONFIG_SERIAL_SC26XX_CONSOLE
-static void sc26xx_console_putchar(struct uart_port *port, char c)
-{
-       unsigned long flags;
-       int limit = 1000000;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       while (limit-- > 0) {
-               if (READ_SC_PORT(port, SR) & SR_TXRDY) {
-                       WRITE_SC_PORT(port, THR, c);
-                       break;
-               }
-               udelay(2);
-       }
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void sc26xx_console_write(struct console *con, const char *s, unsigned n)
-{
-       struct uart_port *port = sc26xx_port;
-       int i;
-
-       for (i = 0; i < n; i++) {
-               if (*s == '\n')
-                       sc26xx_console_putchar(port, '\r');
-               sc26xx_console_putchar(port, *s++);
-       }
-}
-
-static int __init sc26xx_console_setup(struct console *con, char *options)
-{
-       struct uart_port *port = sc26xx_port;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       if (port->type != PORT_SC26XX)
-               return -1;
-
-       printk(KERN_INFO "Console: ttySC%d (SC26XX)\n", con->index);
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(port, con, baud, parity, bits, flow);
-}
-
-static struct uart_driver sc26xx_reg;
-static struct console sc26xx_console = {
-       .name   =       "ttySC",
-       .write  =       sc26xx_console_write,
-       .device =       uart_console_device,
-       .setup  =       sc26xx_console_setup,
-       .flags  =       CON_PRINTBUFFER,
-       .index  =       -1,
-       .data   =       &sc26xx_reg,
-};
-#define SC26XX_CONSOLE   &sc26xx_console
-#else
-#define SC26XX_CONSOLE   NULL
-#endif
-
-static struct uart_driver sc26xx_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "SC26xx",
-       .dev_name               = "ttySC",
-       .major                  = SC26XX_MAJOR,
-       .minor                  = SC26XX_MINOR_START,
-       .nr                     = SC26XX_NR,
-       .cons                   = SC26XX_CONSOLE,
-};
-
-static u8 sc26xx_flags2mask(unsigned int flags, unsigned int bitpos)
-{
-       unsigned int bit = (flags >> bitpos) & 15;
-
-       return bit ? (1 << (bit - 1)) : 0;
-}
-
-static void __devinit sc26xx_init_masks(struct uart_sc26xx_port *up,
-                                       int line, unsigned int data)
-{
-       up->dtr_mask[line] = sc26xx_flags2mask(data,  0);
-       up->rts_mask[line] = sc26xx_flags2mask(data,  4);
-       up->dsr_mask[line] = sc26xx_flags2mask(data,  8);
-       up->cts_mask[line] = sc26xx_flags2mask(data, 12);
-       up->dcd_mask[line] = sc26xx_flags2mask(data, 16);
-       up->ri_mask[line]  = sc26xx_flags2mask(data, 20);
-}
-
-static int __devinit sc26xx_probe(struct platform_device *dev)
-{
-       struct resource *res;
-       struct uart_sc26xx_port *up;
-       unsigned int *sc26xx_data = dev->dev.platform_data;
-       int err;
-
-       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-
-       up = kzalloc(sizeof *up, GFP_KERNEL);
-       if (unlikely(!up))
-               return -ENOMEM;
-
-       up->port[0].line = 0;
-       up->port[0].ops = &sc26xx_ops;
-       up->port[0].type = PORT_SC26XX;
-       up->port[0].uartclk = (29491200 / 16); /* arbitrary */
-
-       up->port[0].mapbase = res->start;
-       up->port[0].membase = ioremap_nocache(up->port[0].mapbase, 0x40);
-       up->port[0].iotype = UPIO_MEM;
-       up->port[0].irq = platform_get_irq(dev, 0);
-
-       up->port[0].dev = &dev->dev;
-
-       sc26xx_init_masks(up, 0, sc26xx_data[0]);
-
-       sc26xx_port = &up->port[0];
-
-       up->port[1].line = 1;
-       up->port[1].ops = &sc26xx_ops;
-       up->port[1].type = PORT_SC26XX;
-       up->port[1].uartclk = (29491200 / 16); /* arbitrary */
-
-       up->port[1].mapbase = up->port[0].mapbase;
-       up->port[1].membase = up->port[0].membase;
-       up->port[1].iotype = UPIO_MEM;
-       up->port[1].irq = up->port[0].irq;
-
-       up->port[1].dev = &dev->dev;
-
-       sc26xx_init_masks(up, 1, sc26xx_data[1]);
-
-       err = uart_register_driver(&sc26xx_reg);
-       if (err)
-               goto out_free_port;
-
-       sc26xx_reg.tty_driver->name_base = sc26xx_reg.minor;
-
-       err = uart_add_one_port(&sc26xx_reg, &up->port[0]);
-       if (err)
-               goto out_unregister_driver;
-
-       err = uart_add_one_port(&sc26xx_reg, &up->port[1]);
-       if (err)
-               goto out_remove_port0;
-
-       err = request_irq(up->port[0].irq, sc26xx_interrupt, 0, "sc26xx", up);
-       if (err)
-               goto out_remove_ports;
-
-       dev_set_drvdata(&dev->dev, up);
-       return 0;
-
-out_remove_ports:
-       uart_remove_one_port(&sc26xx_reg, &up->port[1]);
-out_remove_port0:
-       uart_remove_one_port(&sc26xx_reg, &up->port[0]);
-
-out_unregister_driver:
-       uart_unregister_driver(&sc26xx_reg);
-
-out_free_port:
-       kfree(up);
-       sc26xx_port = NULL;
-       return err;
-}
-
-
-static int __exit sc26xx_driver_remove(struct platform_device *dev)
-{
-       struct uart_sc26xx_port *up = dev_get_drvdata(&dev->dev);
-
-       free_irq(up->port[0].irq, up);
-
-       uart_remove_one_port(&sc26xx_reg, &up->port[0]);
-       uart_remove_one_port(&sc26xx_reg, &up->port[1]);
-
-       uart_unregister_driver(&sc26xx_reg);
-
-       kfree(up);
-       sc26xx_port = NULL;
-
-       dev_set_drvdata(&dev->dev, NULL);
-       return 0;
-}
-
-static struct platform_driver sc26xx_driver = {
-       .probe  = sc26xx_probe,
-       .remove = __devexit_p(sc26xx_driver_remove),
-       .driver = {
-               .name   = "SC26xx",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init sc26xx_init(void)
-{
-       return platform_driver_register(&sc26xx_driver);
-}
-
-static void __exit sc26xx_exit(void)
-{
-       platform_driver_unregister(&sc26xx_driver);
-}
-
-module_init(sc26xx_init);
-module_exit(sc26xx_exit);
-
-
-MODULE_AUTHOR("Thomas Bogendörfer");
-MODULE_DESCRIPTION("SC681/SC2692 serial driver");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:SC26xx");
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
deleted file mode 100644 (file)
index 460a72d..0000000
+++ /dev/null
@@ -1,2578 +0,0 @@
-/*
- *  linux/drivers/char/core.c
- *
- *  Driver core for serial ports
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *
- *  Copyright 1999 ARM Limited
- *  Copyright (C) 2000-2001 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/module.h>
-#include <linux/tty.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/device.h>
-#include <linux/serial.h> /* for serial_state and serial_icounter_struct */
-#include <linux/serial_core.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-
-/*
- * This is used to lock changes in serial line configuration.
- */
-static DEFINE_MUTEX(port_mutex);
-
-/*
- * lockdep: port->lock is initialized in two places, but we
- *          want only one lock-class:
- */
-static struct lock_class_key port_lock_key;
-
-#define HIGH_BITS_OFFSET       ((sizeof(long)-sizeof(int))*8)
-
-#ifdef CONFIG_SERIAL_CORE_CONSOLE
-#define uart_console(port)     ((port)->cons && (port)->cons->index == (port)->line)
-#else
-#define uart_console(port)     (0)
-#endif
-
-static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
-                                       struct ktermios *old_termios);
-static void __uart_wait_until_sent(struct uart_port *port, int timeout);
-static void uart_change_pm(struct uart_state *state, int pm_state);
-
-/*
- * This routine is used by the interrupt handler to schedule processing in
- * the software interrupt portion of the driver.
- */
-void uart_write_wakeup(struct uart_port *port)
-{
-       struct uart_state *state = port->state;
-       /*
-        * This means you called this function _after_ the port was
-        * closed.  No cookie for you.
-        */
-       BUG_ON(!state);
-       tasklet_schedule(&state->tlet);
-}
-
-static void uart_stop(struct tty_struct *tty)
-{
-       struct uart_state *state = tty->driver_data;
-       struct uart_port *port = state->uart_port;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       port->ops->stop_tx(port);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void __uart_start(struct tty_struct *tty)
-{
-       struct uart_state *state = tty->driver_data;
-       struct uart_port *port = state->uart_port;
-
-       if (!uart_circ_empty(&state->xmit) && state->xmit.buf &&
-           !tty->stopped && !tty->hw_stopped)
-               port->ops->start_tx(port);
-}
-
-static void uart_start(struct tty_struct *tty)
-{
-       struct uart_state *state = tty->driver_data;
-       struct uart_port *port = state->uart_port;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       __uart_start(tty);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void uart_tasklet_action(unsigned long data)
-{
-       struct uart_state *state = (struct uart_state *)data;
-       tty_wakeup(state->port.tty);
-}
-
-static inline void
-uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
-{
-       unsigned long flags;
-       unsigned int old;
-
-       spin_lock_irqsave(&port->lock, flags);
-       old = port->mctrl;
-       port->mctrl = (old & ~clear) | set;
-       if (old != port->mctrl)
-               port->ops->set_mctrl(port, port->mctrl);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-#define uart_set_mctrl(port, set)      uart_update_mctrl(port, set, 0)
-#define uart_clear_mctrl(port, clear)  uart_update_mctrl(port, 0, clear)
-
-/*
- * Startup the port.  This will be called once per open.  All calls
- * will be serialised by the per-port mutex.
- */
-static int uart_startup(struct tty_struct *tty, struct uart_state *state, int init_hw)
-{
-       struct uart_port *uport = state->uart_port;
-       struct tty_port *port = &state->port;
-       unsigned long page;
-       int retval = 0;
-
-       if (port->flags & ASYNC_INITIALIZED)
-               return 0;
-
-       /*
-        * Set the TTY IO error marker - we will only clear this
-        * once we have successfully opened the port.  Also set
-        * up the tty->alt_speed kludge
-        */
-       set_bit(TTY_IO_ERROR, &tty->flags);
-
-       if (uport->type == PORT_UNKNOWN)
-               return 0;
-
-       /*
-        * Initialise and allocate the transmit and temporary
-        * buffer.
-        */
-       if (!state->xmit.buf) {
-               /* This is protected by the per port mutex */
-               page = get_zeroed_page(GFP_KERNEL);
-               if (!page)
-                       return -ENOMEM;
-
-               state->xmit.buf = (unsigned char *) page;
-               uart_circ_clear(&state->xmit);
-       }
-
-       retval = uport->ops->startup(uport);
-       if (retval == 0) {
-               if (init_hw) {
-                       /*
-                        * Initialise the hardware port settings.
-                        */
-                       uart_change_speed(tty, state, NULL);
-
-                       /*
-                        * Setup the RTS and DTR signals once the
-                        * port is open and ready to respond.
-                        */
-                       if (tty->termios->c_cflag & CBAUD)
-                               uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
-               }
-
-               if (port->flags & ASYNC_CTS_FLOW) {
-                       spin_lock_irq(&uport->lock);
-                       if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS))
-                               tty->hw_stopped = 1;
-                       spin_unlock_irq(&uport->lock);
-               }
-
-               set_bit(ASYNCB_INITIALIZED, &port->flags);
-
-               clear_bit(TTY_IO_ERROR, &tty->flags);
-       }
-
-       if (retval && capable(CAP_SYS_ADMIN))
-               retval = 0;
-
-       return retval;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.  Calls to
- * uart_shutdown are serialised by the per-port semaphore.
- */
-static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
-{
-       struct uart_port *uport = state->uart_port;
-       struct tty_port *port = &state->port;
-
-       /*
-        * Set the TTY IO error marker
-        */
-       if (tty)
-               set_bit(TTY_IO_ERROR, &tty->flags);
-
-       if (test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) {
-               /*
-                * Turn off DTR and RTS early.
-                */
-               if (!tty || (tty->termios->c_cflag & HUPCL))
-                       uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
-
-               /*
-                * clear delta_msr_wait queue to avoid mem leaks: we may free
-                * the irq here so the queue might never be woken up.  Note
-                * that we won't end up waiting on delta_msr_wait again since
-                * any outstanding file descriptors should be pointing at
-                * hung_up_tty_fops now.
-                */
-               wake_up_interruptible(&port->delta_msr_wait);
-
-               /*
-                * Free the IRQ and disable the port.
-                */
-               uport->ops->shutdown(uport);
-
-               /*
-                * Ensure that the IRQ handler isn't running on another CPU.
-                */
-               synchronize_irq(uport->irq);
-       }
-
-       /*
-        * kill off our tasklet
-        */
-       tasklet_kill(&state->tlet);
-
-       /*
-        * Free the transmit buffer page.
-        */
-       if (state->xmit.buf) {
-               free_page((unsigned long)state->xmit.buf);
-               state->xmit.buf = NULL;
-       }
-}
-
-/**
- *     uart_update_timeout - update per-port FIFO timeout.
- *     @port:  uart_port structure describing the port
- *     @cflag: termios cflag value
- *     @baud:  speed of the port
- *
- *     Set the port FIFO timeout value.  The @cflag value should
- *     reflect the actual hardware settings.
- */
-void
-uart_update_timeout(struct uart_port *port, unsigned int cflag,
-                   unsigned int baud)
-{
-       unsigned int bits;
-
-       /* byte size and parity */
-       switch (cflag & CSIZE) {
-       case CS5:
-               bits = 7;
-               break;
-       case CS6:
-               bits = 8;
-               break;
-       case CS7:
-               bits = 9;
-               break;
-       default:
-               bits = 10;
-               break; /* CS8 */
-       }
-
-       if (cflag & CSTOPB)
-               bits++;
-       if (cflag & PARENB)
-               bits++;
-
-       /*
-        * The total number of bits to be transmitted in the fifo.
-        */
-       bits = bits * port->fifosize;
-
-       /*
-        * Figure the timeout to send the above number of bits.
-        * Add .02 seconds of slop
-        */
-       port->timeout = (HZ * bits) / baud + HZ/50;
-}
-
-EXPORT_SYMBOL(uart_update_timeout);
-
-/**
- *     uart_get_baud_rate - return baud rate for a particular port
- *     @port: uart_port structure describing the port in question.
- *     @termios: desired termios settings.
- *     @old: old termios (or NULL)
- *     @min: minimum acceptable baud rate
- *     @max: maximum acceptable baud rate
- *
- *     Decode the termios structure into a numeric baud rate,
- *     taking account of the magic 38400 baud rate (with spd_*
- *     flags), and mapping the %B0 rate to 9600 baud.
- *
- *     If the new baud rate is invalid, try the old termios setting.
- *     If it's still invalid, we try 9600 baud.
- *
- *     Update the @termios structure to reflect the baud rate
- *     we're actually going to be using. Don't do this for the case
- *     where B0 is requested ("hang up").
- */
-unsigned int
-uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
-                  struct ktermios *old, unsigned int min, unsigned int max)
-{
-       unsigned int try, baud, altbaud = 38400;
-       int hung_up = 0;
-       upf_t flags = port->flags & UPF_SPD_MASK;
-
-       if (flags == UPF_SPD_HI)
-               altbaud = 57600;
-       else if (flags == UPF_SPD_VHI)
-               altbaud = 115200;
-       else if (flags == UPF_SPD_SHI)
-               altbaud = 230400;
-       else if (flags == UPF_SPD_WARP)
-               altbaud = 460800;
-
-       for (try = 0; try < 2; try++) {
-               baud = tty_termios_baud_rate(termios);
-
-               /*
-                * The spd_hi, spd_vhi, spd_shi, spd_warp kludge...
-                * Die! Die! Die!
-                */
-               if (baud == 38400)
-                       baud = altbaud;
-
-               /*
-                * Special case: B0 rate.
-                */
-               if (baud == 0) {
-                       hung_up = 1;
-                       baud = 9600;
-               }
-
-               if (baud >= min && baud <= max)
-                       return baud;
-
-               /*
-                * Oops, the quotient was zero.  Try again with
-                * the old baud rate if possible.
-                */
-               termios->c_cflag &= ~CBAUD;
-               if (old) {
-                       baud = tty_termios_baud_rate(old);
-                       if (!hung_up)
-                               tty_termios_encode_baud_rate(termios,
-                                                               baud, baud);
-                       old = NULL;
-                       continue;
-               }
-
-               /*
-                * As a last resort, if the range cannot be met then clip to
-                * the nearest chip supported rate.
-                */
-               if (!hung_up) {
-                       if (baud <= min)
-                               tty_termios_encode_baud_rate(termios,
-                                                       min + 1, min + 1);
-                       else
-                               tty_termios_encode_baud_rate(termios,
-                                                       max - 1, max - 1);
-               }
-       }
-       /* Should never happen */
-       WARN_ON(1);
-       return 0;
-}
-
-EXPORT_SYMBOL(uart_get_baud_rate);
-
-/**
- *     uart_get_divisor - return uart clock divisor
- *     @port: uart_port structure describing the port.
- *     @baud: desired baud rate
- *
- *     Calculate the uart clock divisor for the port.
- */
-unsigned int
-uart_get_divisor(struct uart_port *port, unsigned int baud)
-{
-       unsigned int quot;
-
-       /*
-        * Old custom speed handling.
-        */
-       if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
-               quot = port->custom_divisor;
-       else
-               quot = (port->uartclk + (8 * baud)) / (16 * baud);
-
-       return quot;
-}
-
-EXPORT_SYMBOL(uart_get_divisor);
-
-/* FIXME: Consistent locking policy */
-static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
-                                       struct ktermios *old_termios)
-{
-       struct tty_port *port = &state->port;
-       struct uart_port *uport = state->uart_port;
-       struct ktermios *termios;
-
-       /*
-        * If we have no tty, termios, or the port does not exist,
-        * then we can't set the parameters for this port.
-        */
-       if (!tty || !tty->termios || uport->type == PORT_UNKNOWN)
-               return;
-
-       termios = tty->termios;
-
-       /*
-        * Set flags based on termios cflag
-        */
-       if (termios->c_cflag & CRTSCTS)
-               set_bit(ASYNCB_CTS_FLOW, &port->flags);
-       else
-               clear_bit(ASYNCB_CTS_FLOW, &port->flags);
-
-       if (termios->c_cflag & CLOCAL)
-               clear_bit(ASYNCB_CHECK_CD, &port->flags);
-       else
-               set_bit(ASYNCB_CHECK_CD, &port->flags);
-
-       uport->ops->set_termios(uport, termios, old_termios);
-}
-
-static inline int __uart_put_char(struct uart_port *port,
-                               struct circ_buf *circ, unsigned char c)
-{
-       unsigned long flags;
-       int ret = 0;
-
-       if (!circ->buf)
-               return 0;
-
-       spin_lock_irqsave(&port->lock, flags);
-       if (uart_circ_chars_free(circ) != 0) {
-               circ->buf[circ->head] = c;
-               circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1);
-               ret = 1;
-       }
-       spin_unlock_irqrestore(&port->lock, flags);
-       return ret;
-}
-
-static int uart_put_char(struct tty_struct *tty, unsigned char ch)
-{
-       struct uart_state *state = tty->driver_data;
-
-       return __uart_put_char(state->uart_port, &state->xmit, ch);
-}
-
-static void uart_flush_chars(struct tty_struct *tty)
-{
-       uart_start(tty);
-}
-
-static int uart_write(struct tty_struct *tty,
-                                       const unsigned char *buf, int count)
-{
-       struct uart_state *state = tty->driver_data;
-       struct uart_port *port;
-       struct circ_buf *circ;
-       unsigned long flags;
-       int c, ret = 0;
-
-       /*
-        * This means you called this function _after_ the port was
-        * closed.  No cookie for you.
-        */
-       if (!state) {
-               WARN_ON(1);
-               return -EL3HLT;
-       }
-
-       port = state->uart_port;
-       circ = &state->xmit;
-
-       if (!circ->buf)
-               return 0;
-
-       spin_lock_irqsave(&port->lock, flags);
-       while (1) {
-               c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
-               if (count < c)
-                       c = count;
-               if (c <= 0)
-                       break;
-               memcpy(circ->buf + circ->head, buf, c);
-               circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
-               buf += c;
-               count -= c;
-               ret += c;
-       }
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       uart_start(tty);
-       return ret;
-}
-
-static int uart_write_room(struct tty_struct *tty)
-{
-       struct uart_state *state = tty->driver_data;
-       unsigned long flags;
-       int ret;
-
-       spin_lock_irqsave(&state->uart_port->lock, flags);
-       ret = uart_circ_chars_free(&state->xmit);
-       spin_unlock_irqrestore(&state->uart_port->lock, flags);
-       return ret;
-}
-
-static int uart_chars_in_buffer(struct tty_struct *tty)
-{
-       struct uart_state *state = tty->driver_data;
-       unsigned long flags;
-       int ret;
-
-       spin_lock_irqsave(&state->uart_port->lock, flags);
-       ret = uart_circ_chars_pending(&state->xmit);
-       spin_unlock_irqrestore(&state->uart_port->lock, flags);
-       return ret;
-}
-
-static void uart_flush_buffer(struct tty_struct *tty)
-{
-       struct uart_state *state = tty->driver_data;
-       struct uart_port *port;
-       unsigned long flags;
-
-       /*
-        * This means you called this function _after_ the port was
-        * closed.  No cookie for you.
-        */
-       if (!state) {
-               WARN_ON(1);
-               return;
-       }
-
-       port = state->uart_port;
-       pr_debug("uart_flush_buffer(%d) called\n", tty->index);
-
-       spin_lock_irqsave(&port->lock, flags);
-       uart_circ_clear(&state->xmit);
-       if (port->ops->flush_buffer)
-               port->ops->flush_buffer(port);
-       spin_unlock_irqrestore(&port->lock, flags);
-       tty_wakeup(tty);
-}
-
-/*
- * This function is used to send a high-priority XON/XOFF character to
- * the device
- */
-static void uart_send_xchar(struct tty_struct *tty, char ch)
-{
-       struct uart_state *state = tty->driver_data;
-       struct uart_port *port = state->uart_port;
-       unsigned long flags;
-
-       if (port->ops->send_xchar)
-               port->ops->send_xchar(port, ch);
-       else {
-               port->x_char = ch;
-               if (ch) {
-                       spin_lock_irqsave(&port->lock, flags);
-                       port->ops->start_tx(port);
-                       spin_unlock_irqrestore(&port->lock, flags);
-               }
-       }
-}
-
-static void uart_throttle(struct tty_struct *tty)
-{
-       struct uart_state *state = tty->driver_data;
-
-       if (I_IXOFF(tty))
-               uart_send_xchar(tty, STOP_CHAR(tty));
-
-       if (tty->termios->c_cflag & CRTSCTS)
-               uart_clear_mctrl(state->uart_port, TIOCM_RTS);
-}
-
-static void uart_unthrottle(struct tty_struct *tty)
-{
-       struct uart_state *state = tty->driver_data;
-       struct uart_port *port = state->uart_port;
-
-       if (I_IXOFF(tty)) {
-               if (port->x_char)
-                       port->x_char = 0;
-               else
-                       uart_send_xchar(tty, START_CHAR(tty));
-       }
-
-       if (tty->termios->c_cflag & CRTSCTS)
-               uart_set_mctrl(port, TIOCM_RTS);
-}
-
-static int uart_get_info(struct uart_state *state,
-                        struct serial_struct __user *retinfo)
-{
-       struct uart_port *uport = state->uart_port;
-       struct tty_port *port = &state->port;
-       struct serial_struct tmp;
-
-       memset(&tmp, 0, sizeof(tmp));
-
-       /* Ensure the state we copy is consistent and no hardware changes
-          occur as we go */
-       mutex_lock(&port->mutex);
-
-       tmp.type            = uport->type;
-       tmp.line            = uport->line;
-       tmp.port            = uport->iobase;
-       if (HIGH_BITS_OFFSET)
-               tmp.port_high = (long) uport->iobase >> HIGH_BITS_OFFSET;
-       tmp.irq             = uport->irq;
-       tmp.flags           = uport->flags;
-       tmp.xmit_fifo_size  = uport->fifosize;
-       tmp.baud_base       = uport->uartclk / 16;
-       tmp.close_delay     = port->close_delay / 10;
-       tmp.closing_wait    = port->closing_wait == ASYNC_CLOSING_WAIT_NONE ?
-                               ASYNC_CLOSING_WAIT_NONE :
-                               port->closing_wait / 10;
-       tmp.custom_divisor  = uport->custom_divisor;
-       tmp.hub6            = uport->hub6;
-       tmp.io_type         = uport->iotype;
-       tmp.iomem_reg_shift = uport->regshift;
-       tmp.iomem_base      = (void *)(unsigned long)uport->mapbase;
-
-       mutex_unlock(&port->mutex);
-
-       if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
-               return -EFAULT;
-       return 0;
-}
-
-static int uart_set_info(struct tty_struct *tty, struct uart_state *state,
-                        struct serial_struct __user *newinfo)
-{
-       struct serial_struct new_serial;
-       struct uart_port *uport = state->uart_port;
-       struct tty_port *port = &state->port;
-       unsigned long new_port;
-       unsigned int change_irq, change_port, closing_wait;
-       unsigned int old_custom_divisor, close_delay;
-       upf_t old_flags, new_flags;
-       int retval = 0;
-
-       if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
-               return -EFAULT;
-
-       new_port = new_serial.port;
-       if (HIGH_BITS_OFFSET)
-               new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET;
-
-       new_serial.irq = irq_canonicalize(new_serial.irq);
-       close_delay = new_serial.close_delay * 10;
-       closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
-                       ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
-
-       /*
-        * This semaphore protects port->count.  It is also
-        * very useful to prevent opens.  Also, take the
-        * port configuration semaphore to make sure that a
-        * module insertion/removal doesn't change anything
-        * under us.
-        */
-       mutex_lock(&port->mutex);
-
-       change_irq  = !(uport->flags & UPF_FIXED_PORT)
-               && new_serial.irq != uport->irq;
-
-       /*
-        * Since changing the 'type' of the port changes its resource
-        * allocations, we should treat type changes the same as
-        * IO port changes.
-        */
-       change_port = !(uport->flags & UPF_FIXED_PORT)
-               && (new_port != uport->iobase ||
-                   (unsigned long)new_serial.iomem_base != uport->mapbase ||
-                   new_serial.hub6 != uport->hub6 ||
-                   new_serial.io_type != uport->iotype ||
-                   new_serial.iomem_reg_shift != uport->regshift ||
-                   new_serial.type != uport->type);
-
-       old_flags = uport->flags;
-       new_flags = new_serial.flags;
-       old_custom_divisor = uport->custom_divisor;
-
-       if (!capable(CAP_SYS_ADMIN)) {
-               retval = -EPERM;
-               if (change_irq || change_port ||
-                   (new_serial.baud_base != uport->uartclk / 16) ||
-                   (close_delay != port->close_delay) ||
-                   (closing_wait != port->closing_wait) ||
-                   (new_serial.xmit_fifo_size &&
-                    new_serial.xmit_fifo_size != uport->fifosize) ||
-                   (((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0))
-                       goto exit;
-               uport->flags = ((uport->flags & ~UPF_USR_MASK) |
-                              (new_flags & UPF_USR_MASK));
-               uport->custom_divisor = new_serial.custom_divisor;
-               goto check_and_exit;
-       }
-
-       /*
-        * Ask the low level driver to verify the settings.
-        */
-       if (uport->ops->verify_port)
-               retval = uport->ops->verify_port(uport, &new_serial);
-
-       if ((new_serial.irq >= nr_irqs) || (new_serial.irq < 0) ||
-           (new_serial.baud_base < 9600))
-               retval = -EINVAL;
-
-       if (retval)
-               goto exit;
-
-       if (change_port || change_irq) {
-               retval = -EBUSY;
-
-               /*
-                * Make sure that we are the sole user of this port.
-                */
-               if (tty_port_users(port) > 1)
-                       goto exit;
-
-               /*
-                * We need to shutdown the serial port at the old
-                * port/type/irq combination.
-                */
-               uart_shutdown(tty, state);
-       }
-
-       if (change_port) {
-               unsigned long old_iobase, old_mapbase;
-               unsigned int old_type, old_iotype, old_hub6, old_shift;
-
-               old_iobase = uport->iobase;
-               old_mapbase = uport->mapbase;
-               old_type = uport->type;
-               old_hub6 = uport->hub6;
-               old_iotype = uport->iotype;
-               old_shift = uport->regshift;
-
-               /*
-                * Free and release old regions
-                */
-               if (old_type != PORT_UNKNOWN)
-                       uport->ops->release_port(uport);
-
-               uport->iobase = new_port;
-               uport->type = new_serial.type;
-               uport->hub6 = new_serial.hub6;
-               uport->iotype = new_serial.io_type;
-               uport->regshift = new_serial.iomem_reg_shift;
-               uport->mapbase = (unsigned long)new_serial.iomem_base;
-
-               /*
-                * Claim and map the new regions
-                */
-               if (uport->type != PORT_UNKNOWN) {
-                       retval = uport->ops->request_port(uport);
-               } else {
-                       /* Always success - Jean II */
-                       retval = 0;
-               }
-
-               /*
-                * If we fail to request resources for the
-                * new port, try to restore the old settings.
-                */
-               if (retval && old_type != PORT_UNKNOWN) {
-                       uport->iobase = old_iobase;
-                       uport->type = old_type;
-                       uport->hub6 = old_hub6;
-                       uport->iotype = old_iotype;
-                       uport->regshift = old_shift;
-                       uport->mapbase = old_mapbase;
-                       retval = uport->ops->request_port(uport);
-                       /*
-                        * If we failed to restore the old settings,
-                        * we fail like this.
-                        */
-                       if (retval)
-                               uport->type = PORT_UNKNOWN;
-
-                       /*
-                        * We failed anyway.
-                        */
-                       retval = -EBUSY;
-                       /* Added to return the correct error -Ram Gupta */
-                       goto exit;
-               }
-       }
-
-       if (change_irq)
-               uport->irq      = new_serial.irq;
-       if (!(uport->flags & UPF_FIXED_PORT))
-               uport->uartclk  = new_serial.baud_base * 16;
-       uport->flags            = (uport->flags & ~UPF_CHANGE_MASK) |
-                                (new_flags & UPF_CHANGE_MASK);
-       uport->custom_divisor   = new_serial.custom_divisor;
-       port->close_delay     = close_delay;
-       port->closing_wait    = closing_wait;
-       if (new_serial.xmit_fifo_size)
-               uport->fifosize = new_serial.xmit_fifo_size;
-       if (port->tty)
-               port->tty->low_latency =
-                       (uport->flags & UPF_LOW_LATENCY) ? 1 : 0;
-
- check_and_exit:
-       retval = 0;
-       if (uport->type == PORT_UNKNOWN)
-               goto exit;
-       if (port->flags & ASYNC_INITIALIZED) {
-               if (((old_flags ^ uport->flags) & UPF_SPD_MASK) ||
-                   old_custom_divisor != uport->custom_divisor) {
-                       /*
-                        * If they're setting up a custom divisor or speed,
-                        * instead of clearing it, then bitch about it. No
-                        * need to rate-limit; it's CAP_SYS_ADMIN only.
-                        */
-                       if (uport->flags & UPF_SPD_MASK) {
-                               char buf[64];
-                               printk(KERN_NOTICE
-                                      "%s sets custom speed on %s. This "
-                                      "is deprecated.\n", current->comm,
-                                      tty_name(port->tty, buf));
-                       }
-                       uart_change_speed(tty, state, NULL);
-               }
-       } else
-               retval = uart_startup(tty, state, 1);
- exit:
-       mutex_unlock(&port->mutex);
-       return retval;
-}
-
-/**
- *     uart_get_lsr_info       -       get line status register info
- *     @tty: tty associated with the UART
- *     @state: UART being queried
- *     @value: returned modem value
- *
- *     Note: uart_ioctl protects us against hangups.
- */
-static int uart_get_lsr_info(struct tty_struct *tty,
-                       struct uart_state *state, unsigned int __user *value)
-{
-       struct uart_port *uport = state->uart_port;
-       unsigned int result;
-
-       result = uport->ops->tx_empty(uport);
-
-       /*
-        * If we're about to load something into the transmit
-        * register, we'll pretend the transmitter isn't empty to
-        * avoid a race condition (depending on when the transmit
-        * interrupt happens).
-        */
-       if (uport->x_char ||
-           ((uart_circ_chars_pending(&state->xmit) > 0) &&
-            !tty->stopped && !tty->hw_stopped))
-               result &= ~TIOCSER_TEMT;
-
-       return put_user(result, value);
-}
-
-static int uart_tiocmget(struct tty_struct *tty, struct file *file)
-{
-       struct uart_state *state = tty->driver_data;
-       struct tty_port *port = &state->port;
-       struct uart_port *uport = state->uart_port;
-       int result = -EIO;
-
-       mutex_lock(&port->mutex);
-       if ((!file || !tty_hung_up_p(file)) &&
-           !(tty->flags & (1 << TTY_IO_ERROR))) {
-               result = uport->mctrl;
-
-               spin_lock_irq(&uport->lock);
-               result |= uport->ops->get_mctrl(uport);
-               spin_unlock_irq(&uport->lock);
-       }
-       mutex_unlock(&port->mutex);
-
-       return result;
-}
-
-static int
-uart_tiocmset(struct tty_struct *tty, struct file *file,
-             unsigned int set, unsigned int clear)
-{
-       struct uart_state *state = tty->driver_data;
-       struct uart_port *uport = state->uart_port;
-       struct tty_port *port = &state->port;
-       int ret = -EIO;
-
-       mutex_lock(&port->mutex);
-       if ((!file || !tty_hung_up_p(file)) &&
-           !(tty->flags & (1 << TTY_IO_ERROR))) {
-               uart_update_mctrl(uport, set, clear);
-               ret = 0;
-       }
-       mutex_unlock(&port->mutex);
-       return ret;
-}
-
-static int uart_break_ctl(struct tty_struct *tty, int break_state)
-{
-       struct uart_state *state = tty->driver_data;
-       struct tty_port *port = &state->port;
-       struct uart_port *uport = state->uart_port;
-
-       mutex_lock(&port->mutex);
-
-       if (uport->type != PORT_UNKNOWN)
-               uport->ops->break_ctl(uport, break_state);
-
-       mutex_unlock(&port->mutex);
-       return 0;
-}
-
-static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state)
-{
-       struct uart_port *uport = state->uart_port;
-       struct tty_port *port = &state->port;
-       int flags, ret;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
-       /*
-        * Take the per-port semaphore.  This prevents count from
-        * changing, and hence any extra opens of the port while
-        * we're auto-configuring.
-        */
-       if (mutex_lock_interruptible(&port->mutex))
-               return -ERESTARTSYS;
-
-       ret = -EBUSY;
-       if (tty_port_users(port) == 1) {
-               uart_shutdown(tty, state);
-
-               /*
-                * If we already have a port type configured,
-                * we must release its resources.
-                */
-               if (uport->type != PORT_UNKNOWN)
-                       uport->ops->release_port(uport);
-
-               flags = UART_CONFIG_TYPE;
-               if (uport->flags & UPF_AUTO_IRQ)
-                       flags |= UART_CONFIG_IRQ;
-
-               /*
-                * This will claim the ports resources if
-                * a port is found.
-                */
-               uport->ops->config_port(uport, flags);
-
-               ret = uart_startup(tty, state, 1);
-       }
-       mutex_unlock(&port->mutex);
-       return ret;
-}
-
-/*
- * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
- * - mask passed in arg for lines of interest
- *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
- * Caller should use TIOCGICOUNT to see which one it was
- *
- * FIXME: This wants extracting into a common all driver implementation
- * of TIOCMWAIT using tty_port.
- */
-static int
-uart_wait_modem_status(struct uart_state *state, unsigned long arg)
-{
-       struct uart_port *uport = state->uart_port;
-       struct tty_port *port = &state->port;
-       DECLARE_WAITQUEUE(wait, current);
-       struct uart_icount cprev, cnow;
-       int ret;
-
-       /*
-        * note the counters on entry
-        */
-       spin_lock_irq(&uport->lock);
-       memcpy(&cprev, &uport->icount, sizeof(struct uart_icount));
-
-       /*
-        * Force modem status interrupts on
-        */
-       uport->ops->enable_ms(uport);
-       spin_unlock_irq(&uport->lock);
-
-       add_wait_queue(&port->delta_msr_wait, &wait);
-       for (;;) {
-               spin_lock_irq(&uport->lock);
-               memcpy(&cnow, &uport->icount, sizeof(struct uart_icount));
-               spin_unlock_irq(&uport->lock);
-
-               set_current_state(TASK_INTERRUPTIBLE);
-
-               if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
-                   ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
-                   ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
-                   ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
-                       ret = 0;
-                       break;
-               }
-
-               schedule();
-
-               /* see if a signal did it */
-               if (signal_pending(current)) {
-                       ret = -ERESTARTSYS;
-                       break;
-               }
-
-               cprev = cnow;
-       }
-
-       current->state = TASK_RUNNING;
-       remove_wait_queue(&port->delta_msr_wait, &wait);
-
-       return ret;
-}
-
-/*
- * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
- * Return: write counters to the user passed counter struct
- * NB: both 1->0 and 0->1 transitions are counted except for
- *     RI where only 0->1 is counted.
- */
-static int uart_get_icount(struct tty_struct *tty,
-                         struct serial_icounter_struct *icount)
-{
-       struct uart_state *state = tty->driver_data;
-       struct uart_icount cnow;
-       struct uart_port *uport = state->uart_port;
-
-       spin_lock_irq(&uport->lock);
-       memcpy(&cnow, &uport->icount, sizeof(struct uart_icount));
-       spin_unlock_irq(&uport->lock);
-
-       icount->cts         = cnow.cts;
-       icount->dsr         = cnow.dsr;
-       icount->rng         = cnow.rng;
-       icount->dcd         = cnow.dcd;
-       icount->rx          = cnow.rx;
-       icount->tx          = cnow.tx;
-       icount->frame       = cnow.frame;
-       icount->overrun     = cnow.overrun;
-       icount->parity      = cnow.parity;
-       icount->brk         = cnow.brk;
-       icount->buf_overrun = cnow.buf_overrun;
-
-       return 0;
-}
-
-/*
- * Called via sys_ioctl.  We can use spin_lock_irq() here.
- */
-static int
-uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
-          unsigned long arg)
-{
-       struct uart_state *state = tty->driver_data;
-       struct tty_port *port = &state->port;
-       void __user *uarg = (void __user *)arg;
-       int ret = -ENOIOCTLCMD;
-
-
-       /*
-        * These ioctls don't rely on the hardware to be present.
-        */
-       switch (cmd) {
-       case TIOCGSERIAL:
-               ret = uart_get_info(state, uarg);
-               break;
-
-       case TIOCSSERIAL:
-               ret = uart_set_info(tty, state, uarg);
-               break;
-
-       case TIOCSERCONFIG:
-               ret = uart_do_autoconfig(tty, state);
-               break;
-
-       case TIOCSERGWILD: /* obsolete */
-       case TIOCSERSWILD: /* obsolete */
-               ret = 0;
-               break;
-       }
-
-       if (ret != -ENOIOCTLCMD)
-               goto out;
-
-       if (tty->flags & (1 << TTY_IO_ERROR)) {
-               ret = -EIO;
-               goto out;
-       }
-
-       /*
-        * The following should only be used when hardware is present.
-        */
-       switch (cmd) {
-       case TIOCMIWAIT:
-               ret = uart_wait_modem_status(state, arg);
-               break;
-       }
-
-       if (ret != -ENOIOCTLCMD)
-               goto out;
-
-       mutex_lock(&port->mutex);
-
-       if (tty_hung_up_p(filp)) {
-               ret = -EIO;
-               goto out_up;
-       }
-
-       /*
-        * All these rely on hardware being present and need to be
-        * protected against the tty being hung up.
-        */
-       switch (cmd) {
-       case TIOCSERGETLSR: /* Get line status register */
-               ret = uart_get_lsr_info(tty, state, uarg);
-               break;
-
-       default: {
-               struct uart_port *uport = state->uart_port;
-               if (uport->ops->ioctl)
-                       ret = uport->ops->ioctl(uport, cmd, arg);
-               break;
-       }
-       }
-out_up:
-       mutex_unlock(&port->mutex);
-out:
-       return ret;
-}
-
-static void uart_set_ldisc(struct tty_struct *tty)
-{
-       struct uart_state *state = tty->driver_data;
-       struct uart_port *uport = state->uart_port;
-
-       if (uport->ops->set_ldisc)
-               uport->ops->set_ldisc(uport, tty->termios->c_line);
-}
-
-static void uart_set_termios(struct tty_struct *tty,
-                                               struct ktermios *old_termios)
-{
-       struct uart_state *state = tty->driver_data;
-       unsigned long flags;
-       unsigned int cflag = tty->termios->c_cflag;
-
-
-       /*
-        * These are the bits that are used to setup various
-        * flags in the low level driver. We can ignore the Bfoo
-        * bits in c_cflag; c_[io]speed will always be set
-        * appropriately by set_termios() in tty_ioctl.c
-        */
-#define RELEVANT_IFLAG(iflag)  ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-       if ((cflag ^ old_termios->c_cflag) == 0 &&
-           tty->termios->c_ospeed == old_termios->c_ospeed &&
-           tty->termios->c_ispeed == old_termios->c_ispeed &&
-           RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) {
-               return;
-       }
-
-       uart_change_speed(tty, state, old_termios);
-
-       /* Handle transition to B0 status */
-       if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
-               uart_clear_mctrl(state->uart_port, TIOCM_RTS | TIOCM_DTR);
-       /* Handle transition away from B0 status */
-       else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
-               unsigned int mask = TIOCM_DTR;
-               if (!(cflag & CRTSCTS) ||
-                   !test_bit(TTY_THROTTLED, &tty->flags))
-                       mask |= TIOCM_RTS;
-               uart_set_mctrl(state->uart_port, mask);
-       }
-
-       /* Handle turning off CRTSCTS */
-       if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) {
-               spin_lock_irqsave(&state->uart_port->lock, flags);
-               tty->hw_stopped = 0;
-               __uart_start(tty);
-               spin_unlock_irqrestore(&state->uart_port->lock, flags);
-       }
-       /* Handle turning on CRTSCTS */
-       else if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
-               spin_lock_irqsave(&state->uart_port->lock, flags);
-               if (!(state->uart_port->ops->get_mctrl(state->uart_port) & TIOCM_CTS)) {
-                       tty->hw_stopped = 1;
-                       state->uart_port->ops->stop_tx(state->uart_port);
-               }
-               spin_unlock_irqrestore(&state->uart_port->lock, flags);
-       }
-#if 0
-       /*
-        * No need to wake up processes in open wait, since they
-        * sample the CLOCAL flag once, and don't recheck it.
-        * XXX  It's not clear whether the current behavior is correct
-        * or not.  Hence, this may change.....
-        */
-       if (!(old_termios->c_cflag & CLOCAL) &&
-           (tty->termios->c_cflag & CLOCAL))
-               wake_up_interruptible(&state->uart_port.open_wait);
-#endif
-}
-
-/*
- * In 2.4.5, calls to this will be serialized via the BKL in
- *  linux/drivers/char/tty_io.c:tty_release()
- *  linux/drivers/char/tty_io.c:do_tty_handup()
- */
-static void uart_close(struct tty_struct *tty, struct file *filp)
-{
-       struct uart_state *state = tty->driver_data;
-       struct tty_port *port;
-       struct uart_port *uport;
-       unsigned long flags;
-
-       BUG_ON(!tty_locked());
-
-       if (!state)
-               return;
-
-       uport = state->uart_port;
-       port = &state->port;
-
-       pr_debug("uart_close(%d) called\n", uport->line);
-
-       mutex_lock(&port->mutex);
-       spin_lock_irqsave(&port->lock, flags);
-
-       if (tty_hung_up_p(filp)) {
-               spin_unlock_irqrestore(&port->lock, flags);
-               goto done;
-       }
-
-       if ((tty->count == 1) && (port->count != 1)) {
-               /*
-                * Uh, oh.  tty->count is 1, which means that the tty
-                * structure will be freed.  port->count should always
-                * be one in these conditions.  If it's greater than
-                * one, we've got real problems, since it means the
-                * serial port won't be shutdown.
-                */
-               printk(KERN_ERR "uart_close: bad serial port count; tty->count is 1, "
-                      "port->count is %d\n", port->count);
-               port->count = 1;
-       }
-       if (--port->count < 0) {
-               printk(KERN_ERR "uart_close: bad serial port count for %s: %d\n",
-                      tty->name, port->count);
-               port->count = 0;
-       }
-       if (port->count) {
-               spin_unlock_irqrestore(&port->lock, flags);
-               goto done;
-       }
-
-       /*
-        * Now we wait for the transmit buffer to clear; and we notify
-        * the line discipline to only process XON/XOFF characters by
-        * setting tty->closing.
-        */
-       tty->closing = 1;
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) {
-               /*
-                * hack: open-coded tty_wait_until_sent to avoid
-                * recursive tty_lock
-                */
-               long timeout = msecs_to_jiffies(port->closing_wait);
-               if (wait_event_interruptible_timeout(tty->write_wait,
-                               !tty_chars_in_buffer(tty), timeout) >= 0)
-                       __uart_wait_until_sent(uport, timeout);
-       }
-
-       /*
-        * At this point, we stop accepting input.  To do this, we
-        * disable the receive line status interrupts.
-        */
-       if (port->flags & ASYNC_INITIALIZED) {
-               unsigned long flags;
-               spin_lock_irqsave(&uport->lock, flags);
-               uport->ops->stop_rx(uport);
-               spin_unlock_irqrestore(&uport->lock, flags);
-               /*
-                * Before we drop DTR, make sure the UART transmitter
-                * has completely drained; this is especially
-                * important if there is a transmit FIFO!
-                */
-               __uart_wait_until_sent(uport, uport->timeout);
-       }
-
-       uart_shutdown(tty, state);
-       uart_flush_buffer(tty);
-
-       tty_ldisc_flush(tty);
-
-       tty_port_tty_set(port, NULL);
-       spin_lock_irqsave(&port->lock, flags);
-       tty->closing = 0;
-
-       if (port->blocked_open) {
-               spin_unlock_irqrestore(&port->lock, flags);
-               if (port->close_delay)
-                       msleep_interruptible(port->close_delay);
-               spin_lock_irqsave(&port->lock, flags);
-       } else if (!uart_console(uport)) {
-               spin_unlock_irqrestore(&port->lock, flags);
-               uart_change_pm(state, 3);
-               spin_lock_irqsave(&port->lock, flags);
-       }
-
-       /*
-        * Wake up anyone trying to open this port.
-        */
-       clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
-       spin_unlock_irqrestore(&port->lock, flags);
-       wake_up_interruptible(&port->open_wait);
-
-done:
-       mutex_unlock(&port->mutex);
-}
-
-static void __uart_wait_until_sent(struct uart_port *port, int timeout)
-{
-       unsigned long char_time, expire;
-
-       if (port->type == PORT_UNKNOWN || port->fifosize == 0)
-               return;
-
-       /*
-        * Set the check interval to be 1/5 of the estimated time to
-        * send a single character, and make it at least 1.  The check
-        * interval should also be less than the timeout.
-        *
-        * Note: we have to use pretty tight timings here to satisfy
-        * the NIST-PCTS.
-        */
-       char_time = (port->timeout - HZ/50) / port->fifosize;
-       char_time = char_time / 5;
-       if (char_time == 0)
-               char_time = 1;
-       if (timeout && timeout < char_time)
-               char_time = timeout;
-
-       /*
-        * If the transmitter hasn't cleared in twice the approximate
-        * amount of time to send the entire FIFO, it probably won't
-        * ever clear.  This assumes the UART isn't doing flow
-        * control, which is currently the case.  Hence, if it ever
-        * takes longer than port->timeout, this is probably due to a
-        * UART bug of some kind.  So, we clamp the timeout parameter at
-        * 2*port->timeout.
-        */
-       if (timeout == 0 || timeout > 2 * port->timeout)
-               timeout = 2 * port->timeout;
-
-       expire = jiffies + timeout;
-
-       pr_debug("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n",
-               port->line, jiffies, expire);
-
-       /*
-        * Check whether the transmitter is empty every 'char_time'.
-        * 'timeout' / 'expire' give us the maximum amount of time
-        * we wait.
-        */
-       while (!port->ops->tx_empty(port)) {
-               msleep_interruptible(jiffies_to_msecs(char_time));
-               if (signal_pending(current))
-                       break;
-               if (time_after(jiffies, expire))
-                       break;
-       }
-       set_current_state(TASK_RUNNING); /* might not be needed */
-}
-
-static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-       struct uart_state *state = tty->driver_data;
-       struct uart_port *port = state->uart_port;
-
-       tty_lock();
-       __uart_wait_until_sent(port, timeout);
-       tty_unlock();
-}
-
-/*
- * This is called with the BKL held in
- *  linux/drivers/char/tty_io.c:do_tty_hangup()
- * We're called from the eventd thread, so we can sleep for
- * a _short_ time only.
- */
-static void uart_hangup(struct tty_struct *tty)
-{
-       struct uart_state *state = tty->driver_data;
-       struct tty_port *port = &state->port;
-       unsigned long flags;
-
-       BUG_ON(!tty_locked());
-       pr_debug("uart_hangup(%d)\n", state->uart_port->line);
-
-       mutex_lock(&port->mutex);
-       if (port->flags & ASYNC_NORMAL_ACTIVE) {
-               uart_flush_buffer(tty);
-               uart_shutdown(tty, state);
-               spin_lock_irqsave(&port->lock, flags);
-               port->count = 0;
-               clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
-               spin_unlock_irqrestore(&port->lock, flags);
-               tty_port_tty_set(port, NULL);
-               wake_up_interruptible(&port->open_wait);
-               wake_up_interruptible(&port->delta_msr_wait);
-       }
-       mutex_unlock(&port->mutex);
-}
-
-/**
- *     uart_update_termios     -       update the terminal hw settings
- *     @tty: tty associated with UART
- *     @state: UART to update
- *
- *     Copy across the serial console cflag setting into the termios settings
- *     for the initial open of the port.  This allows continuity between the
- *     kernel settings, and the settings init adopts when it opens the port
- *     for the first time.
- */
-static void uart_update_termios(struct tty_struct *tty,
-                                               struct uart_state *state)
-{
-       struct uart_port *port = state->uart_port;
-
-       if (uart_console(port) && port->cons->cflag) {
-               tty->termios->c_cflag = port->cons->cflag;
-               port->cons->cflag = 0;
-       }
-
-       /*
-        * If the device failed to grab its irq resources,
-        * or some other error occurred, don't try to talk
-        * to the port hardware.
-        */
-       if (!(tty->flags & (1 << TTY_IO_ERROR))) {
-               /*
-                * Make termios settings take effect.
-                */
-               uart_change_speed(tty, state, NULL);
-
-               /*
-                * And finally enable the RTS and DTR signals.
-                */
-               if (tty->termios->c_cflag & CBAUD)
-                       uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
-       }
-}
-
-static int uart_carrier_raised(struct tty_port *port)
-{
-       struct uart_state *state = container_of(port, struct uart_state, port);
-       struct uart_port *uport = state->uart_port;
-       int mctrl;
-       spin_lock_irq(&uport->lock);
-       uport->ops->enable_ms(uport);
-       mctrl = uport->ops->get_mctrl(uport);
-       spin_unlock_irq(&uport->lock);
-       if (mctrl & TIOCM_CAR)
-               return 1;
-       return 0;
-}
-
-static void uart_dtr_rts(struct tty_port *port, int onoff)
-{
-       struct uart_state *state = container_of(port, struct uart_state, port);
-       struct uart_port *uport = state->uart_port;
-
-       if (onoff) {
-               uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
-
-               /*
-                * If this is the first open to succeed,
-                * adjust things to suit.
-                */
-               if (!test_and_set_bit(ASYNCB_NORMAL_ACTIVE, &port->flags))
-                       uart_update_termios(port->tty, state);
-       }
-       else
-               uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
-}
-
-static struct uart_state *uart_get(struct uart_driver *drv, int line)
-{
-       struct uart_state *state;
-       struct tty_port *port;
-       int ret = 0;
-
-       state = drv->state + line;
-       port = &state->port;
-       if (mutex_lock_interruptible(&port->mutex)) {
-               ret = -ERESTARTSYS;
-               goto err;
-       }
-
-       port->count++;
-       if (!state->uart_port || state->uart_port->flags & UPF_DEAD) {
-               ret = -ENXIO;
-               goto err_unlock;
-       }
-       return state;
-
- err_unlock:
-       port->count--;
-       mutex_unlock(&port->mutex);
- err:
-       return ERR_PTR(ret);
-}
-
-/*
- * calls to uart_open are serialised by the BKL in
- *   fs/char_dev.c:chrdev_open()
- * Note that if this fails, then uart_close() _will_ be called.
- *
- * In time, we want to scrap the "opening nonpresent ports"
- * behaviour and implement an alternative way for setserial
- * to set base addresses/ports/types.  This will allow us to
- * get rid of a certain amount of extra tests.
- */
-static int uart_open(struct tty_struct *tty, struct file *filp)
-{
-       struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state;
-       struct uart_state *state;
-       struct tty_port *port;
-       int retval, line = tty->index;
-
-       BUG_ON(!tty_locked());
-       pr_debug("uart_open(%d) called\n", line);
-
-       /*
-        * tty->driver->num won't change, so we won't fail here with
-        * tty->driver_data set to something non-NULL (and therefore
-        * we won't get caught by uart_close()).
-        */
-       retval = -ENODEV;
-       if (line >= tty->driver->num)
-               goto fail;
-
-       /*
-        * We take the semaphore inside uart_get to guarantee that we won't
-        * be re-entered while allocating the state structure, or while we
-        * request any IRQs that the driver may need.  This also has the nice
-        * side-effect that it delays the action of uart_hangup, so we can
-        * guarantee that state->port.tty will always contain something
-        * reasonable.
-        */
-       state = uart_get(drv, line);
-       if (IS_ERR(state)) {
-               retval = PTR_ERR(state);
-               goto fail;
-       }
-       port = &state->port;
-
-       /*
-        * Once we set tty->driver_data here, we are guaranteed that
-        * uart_close() will decrement the driver module use count.
-        * Any failures from here onwards should not touch the count.
-        */
-       tty->driver_data = state;
-       state->uart_port->state = state;
-       tty->low_latency = (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0;
-       tty->alt_speed = 0;
-       tty_port_tty_set(port, tty);
-
-       /*
-        * If the port is in the middle of closing, bail out now.
-        */
-       if (tty_hung_up_p(filp)) {
-               retval = -EAGAIN;
-               port->count--;
-               mutex_unlock(&port->mutex);
-               goto fail;
-       }
-
-       /*
-        * Make sure the device is in D0 state.
-        */
-       if (port->count == 1)
-               uart_change_pm(state, 0);
-
-       /*
-        * Start up the serial port.
-        */
-       retval = uart_startup(tty, state, 0);
-
-       /*
-        * If we succeeded, wait until the port is ready.
-        */
-       mutex_unlock(&port->mutex);
-       if (retval == 0)
-               retval = tty_port_block_til_ready(port, tty, filp);
-
-fail:
-       return retval;
-}
-
-static const char *uart_type(struct uart_port *port)
-{
-       const char *str = NULL;
-
-       if (port->ops->type)
-               str = port->ops->type(port);
-
-       if (!str)
-               str = "unknown";
-
-       return str;
-}
-
-#ifdef CONFIG_PROC_FS
-
-static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
-{
-       struct uart_state *state = drv->state + i;
-       struct tty_port *port = &state->port;
-       int pm_state;
-       struct uart_port *uport = state->uart_port;
-       char stat_buf[32];
-       unsigned int status;
-       int mmio;
-
-       if (!uport)
-               return;
-
-       mmio = uport->iotype >= UPIO_MEM;
-       seq_printf(m, "%d: uart:%s %s%08llX irq:%d",
-                       uport->line, uart_type(uport),
-                       mmio ? "mmio:0x" : "port:",
-                       mmio ? (unsigned long long)uport->mapbase
-                            : (unsigned long long)uport->iobase,
-                       uport->irq);
-
-       if (uport->type == PORT_UNKNOWN) {
-               seq_putc(m, '\n');
-               return;
-       }
-
-       if (capable(CAP_SYS_ADMIN)) {
-               mutex_lock(&port->mutex);
-               pm_state = state->pm_state;
-               if (pm_state)
-                       uart_change_pm(state, 0);
-               spin_lock_irq(&uport->lock);
-               status = uport->ops->get_mctrl(uport);
-               spin_unlock_irq(&uport->lock);
-               if (pm_state)
-                       uart_change_pm(state, pm_state);
-               mutex_unlock(&port->mutex);
-
-               seq_printf(m, " tx:%d rx:%d",
-                               uport->icount.tx, uport->icount.rx);
-               if (uport->icount.frame)
-                       seq_printf(m, " fe:%d",
-                               uport->icount.frame);
-               if (uport->icount.parity)
-                       seq_printf(m, " pe:%d",
-                               uport->icount.parity);
-               if (uport->icount.brk)
-                       seq_printf(m, " brk:%d",
-                               uport->icount.brk);
-               if (uport->icount.overrun)
-                       seq_printf(m, " oe:%d",
-                               uport->icount.overrun);
-
-#define INFOBIT(bit, str) \
-       if (uport->mctrl & (bit)) \
-               strncat(stat_buf, (str), sizeof(stat_buf) - \
-                       strlen(stat_buf) - 2)
-#define STATBIT(bit, str) \
-       if (status & (bit)) \
-               strncat(stat_buf, (str), sizeof(stat_buf) - \
-                      strlen(stat_buf) - 2)
-
-               stat_buf[0] = '\0';
-               stat_buf[1] = '\0';
-               INFOBIT(TIOCM_RTS, "|RTS");
-               STATBIT(TIOCM_CTS, "|CTS");
-               INFOBIT(TIOCM_DTR, "|DTR");
-               STATBIT(TIOCM_DSR, "|DSR");
-               STATBIT(TIOCM_CAR, "|CD");
-               STATBIT(TIOCM_RNG, "|RI");
-               if (stat_buf[0])
-                       stat_buf[0] = ' ';
-
-               seq_puts(m, stat_buf);
-       }
-       seq_putc(m, '\n');
-#undef STATBIT
-#undef INFOBIT
-}
-
-static int uart_proc_show(struct seq_file *m, void *v)
-{
-       struct tty_driver *ttydrv = m->private;
-       struct uart_driver *drv = ttydrv->driver_state;
-       int i;
-
-       seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n",
-                       "", "", "");
-       for (i = 0; i < drv->nr; i++)
-               uart_line_info(m, drv, i);
-       return 0;
-}
-
-static int uart_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, uart_proc_show, PDE(inode)->data);
-}
-
-static const struct file_operations uart_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = uart_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-#endif
-
-#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
-/*
- *     uart_console_write - write a console message to a serial port
- *     @port: the port to write the message
- *     @s: array of characters
- *     @count: number of characters in string to write
- *     @write: function to write character to port
- */
-void uart_console_write(struct uart_port *port, const char *s,
-                       unsigned int count,
-                       void (*putchar)(struct uart_port *, int))
-{
-       unsigned int i;
-
-       for (i = 0; i < count; i++, s++) {
-               if (*s == '\n')
-                       putchar(port, '\r');
-               putchar(port, *s);
-       }
-}
-EXPORT_SYMBOL_GPL(uart_console_write);
-
-/*
- *     Check whether an invalid uart number has been specified, and
- *     if so, search for the first available port that does have
- *     console support.
- */
-struct uart_port * __init
-uart_get_console(struct uart_port *ports, int nr, struct console *co)
-{
-       int idx = co->index;
-
-       if (idx < 0 || idx >= nr || (ports[idx].iobase == 0 &&
-                                    ports[idx].membase == NULL))
-               for (idx = 0; idx < nr; idx++)
-                       if (ports[idx].iobase != 0 ||
-                           ports[idx].membase != NULL)
-                               break;
-
-       co->index = idx;
-
-       return ports + idx;
-}
-
-/**
- *     uart_parse_options - Parse serial port baud/parity/bits/flow contro.
- *     @options: pointer to option string
- *     @baud: pointer to an 'int' variable for the baud rate.
- *     @parity: pointer to an 'int' variable for the parity.
- *     @bits: pointer to an 'int' variable for the number of data bits.
- *     @flow: pointer to an 'int' variable for the flow control character.
- *
- *     uart_parse_options decodes a string containing the serial console
- *     options.  The format of the string is <baud><parity><bits><flow>,
- *     eg: 115200n8r
- */
-void
-uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow)
-{
-       char *s = options;
-
-       *baud = simple_strtoul(s, NULL, 10);
-       while (*s >= '0' && *s <= '9')
-               s++;
-       if (*s)
-               *parity = *s++;
-       if (*s)
-               *bits = *s++ - '0';
-       if (*s)
-               *flow = *s;
-}
-EXPORT_SYMBOL_GPL(uart_parse_options);
-
-struct baud_rates {
-       unsigned int rate;
-       unsigned int cflag;
-};
-
-static const struct baud_rates baud_rates[] = {
-       { 921600, B921600 },
-       { 460800, B460800 },
-       { 230400, B230400 },
-       { 115200, B115200 },
-       {  57600, B57600  },
-       {  38400, B38400  },
-       {  19200, B19200  },
-       {   9600, B9600   },
-       {   4800, B4800   },
-       {   2400, B2400   },
-       {   1200, B1200   },
-       {      0, B38400  }
-};
-
-/**
- *     uart_set_options - setup the serial console parameters
- *     @port: pointer to the serial ports uart_port structure
- *     @co: console pointer
- *     @baud: baud rate
- *     @parity: parity character - 'n' (none), 'o' (odd), 'e' (even)
- *     @bits: number of data bits
- *     @flow: flow control character - 'r' (rts)
- */
-int
-uart_set_options(struct uart_port *port, struct console *co,
-                int baud, int parity, int bits, int flow)
-{
-       struct ktermios termios;
-       static struct ktermios dummy;
-       int i;
-
-       /*
-        * Ensure that the serial console lock is initialised
-        * early.
-        */
-       spin_lock_init(&port->lock);
-       lockdep_set_class(&port->lock, &port_lock_key);
-
-       memset(&termios, 0, sizeof(struct ktermios));
-
-       termios.c_cflag = CREAD | HUPCL | CLOCAL;
-
-       /*
-        * Construct a cflag setting.
-        */
-       for (i = 0; baud_rates[i].rate; i++)
-               if (baud_rates[i].rate <= baud)
-                       break;
-
-       termios.c_cflag |= baud_rates[i].cflag;
-
-       if (bits == 7)
-               termios.c_cflag |= CS7;
-       else
-               termios.c_cflag |= CS8;
-
-       switch (parity) {
-       case 'o': case 'O':
-               termios.c_cflag |= PARODD;
-               /*fall through*/
-       case 'e': case 'E':
-               termios.c_cflag |= PARENB;
-               break;
-       }
-
-       if (flow == 'r')
-               termios.c_cflag |= CRTSCTS;
-
-       /*
-        * some uarts on other side don't support no flow control.
-        * So we set * DTR in host uart to make them happy
-        */
-       port->mctrl |= TIOCM_DTR;
-
-       port->ops->set_termios(port, &termios, &dummy);
-       /*
-        * Allow the setting of the UART parameters with a NULL console
-        * too:
-        */
-       if (co)
-               co->cflag = termios.c_cflag;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(uart_set_options);
-#endif /* CONFIG_SERIAL_CORE_CONSOLE */
-
-static void uart_change_pm(struct uart_state *state, int pm_state)
-{
-       struct uart_port *port = state->uart_port;
-
-       if (state->pm_state != pm_state) {
-               if (port->ops->pm)
-                       port->ops->pm(port, pm_state, state->pm_state);
-               state->pm_state = pm_state;
-       }
-}
-
-struct uart_match {
-       struct uart_port *port;
-       struct uart_driver *driver;
-};
-
-static int serial_match_port(struct device *dev, void *data)
-{
-       struct uart_match *match = data;
-       struct tty_driver *tty_drv = match->driver->tty_driver;
-       dev_t devt = MKDEV(tty_drv->major, tty_drv->minor_start) +
-               match->port->line;
-
-       return dev->devt == devt; /* Actually, only one tty per port */
-}
-
-int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
-{
-       struct uart_state *state = drv->state + uport->line;
-       struct tty_port *port = &state->port;
-       struct device *tty_dev;
-       struct uart_match match = {uport, drv};
-       struct tty_struct *tty;
-
-       mutex_lock(&port->mutex);
-
-       /* Must be inside the mutex lock until we convert to tty_port */
-       tty = port->tty;
-
-       tty_dev = device_find_child(uport->dev, &match, serial_match_port);
-       if (device_may_wakeup(tty_dev)) {
-               if (!enable_irq_wake(uport->irq))
-                       uport->irq_wake = 1;
-               put_device(tty_dev);
-               mutex_unlock(&port->mutex);
-               return 0;
-       }
-       if (console_suspend_enabled || !uart_console(uport))
-               uport->suspended = 1;
-
-       if (port->flags & ASYNC_INITIALIZED) {
-               const struct uart_ops *ops = uport->ops;
-               int tries;
-
-               if (console_suspend_enabled || !uart_console(uport)) {
-                       set_bit(ASYNCB_SUSPENDED, &port->flags);
-                       clear_bit(ASYNCB_INITIALIZED, &port->flags);
-
-                       spin_lock_irq(&uport->lock);
-                       ops->stop_tx(uport);
-                       ops->set_mctrl(uport, 0);
-                       ops->stop_rx(uport);
-                       spin_unlock_irq(&uport->lock);
-               }
-
-               /*
-                * Wait for the transmitter to empty.
-                */
-               for (tries = 3; !ops->tx_empty(uport) && tries; tries--)
-                       msleep(10);
-               if (!tries)
-                       printk(KERN_ERR "%s%s%s%d: Unable to drain "
-                                       "transmitter\n",
-                              uport->dev ? dev_name(uport->dev) : "",
-                              uport->dev ? ": " : "",
-                              drv->dev_name,
-                              drv->tty_driver->name_base + uport->line);
-
-               if (console_suspend_enabled || !uart_console(uport))
-                       ops->shutdown(uport);
-       }
-
-       /*
-        * Disable the console device before suspending.
-        */
-       if (console_suspend_enabled && uart_console(uport))
-               console_stop(uport->cons);
-
-       if (console_suspend_enabled || !uart_console(uport))
-               uart_change_pm(state, 3);
-
-       mutex_unlock(&port->mutex);
-
-       return 0;
-}
-
-int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
-{
-       struct uart_state *state = drv->state + uport->line;
-       struct tty_port *port = &state->port;
-       struct device *tty_dev;
-       struct uart_match match = {uport, drv};
-       struct ktermios termios;
-
-       mutex_lock(&port->mutex);
-
-       tty_dev = device_find_child(uport->dev, &match, serial_match_port);
-       if (!uport->suspended && device_may_wakeup(tty_dev)) {
-               if (uport->irq_wake) {
-                       disable_irq_wake(uport->irq);
-                       uport->irq_wake = 0;
-               }
-               mutex_unlock(&port->mutex);
-               return 0;
-       }
-       uport->suspended = 0;
-
-       /*
-        * Re-enable the console device after suspending.
-        */
-       if (console_suspend_enabled && uart_console(uport)) {
-               /*
-                * First try to use the console cflag setting.
-                */
-               memset(&termios, 0, sizeof(struct ktermios));
-               termios.c_cflag = uport->cons->cflag;
-
-               /*
-                * If that's unset, use the tty termios setting.
-                */
-               if (port->tty && port->tty->termios && termios.c_cflag == 0)
-                       termios = *(port->tty->termios);
-
-               uart_change_pm(state, 0);
-               uport->ops->set_termios(uport, &termios, NULL);
-               console_start(uport->cons);
-       }
-
-       if (port->flags & ASYNC_SUSPENDED) {
-               const struct uart_ops *ops = uport->ops;
-               int ret;
-
-               uart_change_pm(state, 0);
-               spin_lock_irq(&uport->lock);
-               ops->set_mctrl(uport, 0);
-               spin_unlock_irq(&uport->lock);
-               if (console_suspend_enabled || !uart_console(uport)) {
-                       /* Protected by port mutex for now */
-                       struct tty_struct *tty = port->tty;
-                       ret = ops->startup(uport);
-                       if (ret == 0) {
-                               if (tty)
-                                       uart_change_speed(tty, state, NULL);
-                               spin_lock_irq(&uport->lock);
-                               ops->set_mctrl(uport, uport->mctrl);
-                               ops->start_tx(uport);
-                               spin_unlock_irq(&uport->lock);
-                               set_bit(ASYNCB_INITIALIZED, &port->flags);
-                       } else {
-                               /*
-                                * Failed to resume - maybe hardware went away?
-                                * Clear the "initialized" flag so we won't try
-                                * to call the low level drivers shutdown method.
-                                */
-                               uart_shutdown(tty, state);
-                       }
-               }
-
-               clear_bit(ASYNCB_SUSPENDED, &port->flags);
-       }
-
-       mutex_unlock(&port->mutex);
-
-       return 0;
-}
-
-static inline void
-uart_report_port(struct uart_driver *drv, struct uart_port *port)
-{
-       char address[64];
-
-       switch (port->iotype) {
-       case UPIO_PORT:
-               snprintf(address, sizeof(address), "I/O 0x%lx", port->iobase);
-               break;
-       case UPIO_HUB6:
-               snprintf(address, sizeof(address),
-                        "I/O 0x%lx offset 0x%x", port->iobase, port->hub6);
-               break;
-       case UPIO_MEM:
-       case UPIO_MEM32:
-       case UPIO_AU:
-       case UPIO_TSI:
-       case UPIO_DWAPB:
-       case UPIO_DWAPB32:
-               snprintf(address, sizeof(address),
-                        "MMIO 0x%llx", (unsigned long long)port->mapbase);
-               break;
-       default:
-               strlcpy(address, "*unknown*", sizeof(address));
-               break;
-       }
-
-       printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n",
-              port->dev ? dev_name(port->dev) : "",
-              port->dev ? ": " : "",
-              drv->dev_name,
-              drv->tty_driver->name_base + port->line,
-              address, port->irq, uart_type(port));
-}
-
-static void
-uart_configure_port(struct uart_driver *drv, struct uart_state *state,
-                   struct uart_port *port)
-{
-       unsigned int flags;
-
-       /*
-        * If there isn't a port here, don't do anything further.
-        */
-       if (!port->iobase && !port->mapbase && !port->membase)
-               return;
-
-       /*
-        * Now do the auto configuration stuff.  Note that config_port
-        * is expected to claim the resources and map the port for us.
-        */
-       flags = 0;
-       if (port->flags & UPF_AUTO_IRQ)
-               flags |= UART_CONFIG_IRQ;
-       if (port->flags & UPF_BOOT_AUTOCONF) {
-               if (!(port->flags & UPF_FIXED_TYPE)) {
-                       port->type = PORT_UNKNOWN;
-                       flags |= UART_CONFIG_TYPE;
-               }
-               port->ops->config_port(port, flags);
-       }
-
-       if (port->type != PORT_UNKNOWN) {
-               unsigned long flags;
-
-               uart_report_port(drv, port);
-
-               /* Power up port for set_mctrl() */
-               uart_change_pm(state, 0);
-
-               /*
-                * Ensure that the modem control lines are de-activated.
-                * keep the DTR setting that is set in uart_set_options()
-                * We probably don't need a spinlock around this, but
-                */
-               spin_lock_irqsave(&port->lock, flags);
-               port->ops->set_mctrl(port, port->mctrl & TIOCM_DTR);
-               spin_unlock_irqrestore(&port->lock, flags);
-
-               /*
-                * If this driver supports console, and it hasn't been
-                * successfully registered yet, try to re-register it.
-                * It may be that the port was not available.
-                */
-               if (port->cons && !(port->cons->flags & CON_ENABLED))
-                       register_console(port->cons);
-
-               /*
-                * Power down all ports by default, except the
-                * console if we have one.
-                */
-               if (!uart_console(port))
-                       uart_change_pm(state, 3);
-       }
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-
-static int uart_poll_init(struct tty_driver *driver, int line, char *options)
-{
-       struct uart_driver *drv = driver->driver_state;
-       struct uart_state *state = drv->state + line;
-       struct uart_port *port;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       if (!state || !state->uart_port)
-               return -1;
-
-       port = state->uart_port;
-       if (!(port->ops->poll_get_char && port->ops->poll_put_char))
-               return -1;
-
-       if (options) {
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-               return uart_set_options(port, NULL, baud, parity, bits, flow);
-       }
-
-       return 0;
-}
-
-static int uart_poll_get_char(struct tty_driver *driver, int line)
-{
-       struct uart_driver *drv = driver->driver_state;
-       struct uart_state *state = drv->state + line;
-       struct uart_port *port;
-
-       if (!state || !state->uart_port)
-               return -1;
-
-       port = state->uart_port;
-       return port->ops->poll_get_char(port);
-}
-
-static void uart_poll_put_char(struct tty_driver *driver, int line, char ch)
-{
-       struct uart_driver *drv = driver->driver_state;
-       struct uart_state *state = drv->state + line;
-       struct uart_port *port;
-
-       if (!state || !state->uart_port)
-               return;
-
-       port = state->uart_port;
-       port->ops->poll_put_char(port, ch);
-}
-#endif
-
-static const struct tty_operations uart_ops = {
-       .open           = uart_open,
-       .close          = uart_close,
-       .write          = uart_write,
-       .put_char       = uart_put_char,
-       .flush_chars    = uart_flush_chars,
-       .write_room     = uart_write_room,
-       .chars_in_buffer= uart_chars_in_buffer,
-       .flush_buffer   = uart_flush_buffer,
-       .ioctl          = uart_ioctl,
-       .throttle       = uart_throttle,
-       .unthrottle     = uart_unthrottle,
-       .send_xchar     = uart_send_xchar,
-       .set_termios    = uart_set_termios,
-       .set_ldisc      = uart_set_ldisc,
-       .stop           = uart_stop,
-       .start          = uart_start,
-       .hangup         = uart_hangup,
-       .break_ctl      = uart_break_ctl,
-       .wait_until_sent= uart_wait_until_sent,
-#ifdef CONFIG_PROC_FS
-       .proc_fops      = &uart_proc_fops,
-#endif
-       .tiocmget       = uart_tiocmget,
-       .tiocmset       = uart_tiocmset,
-       .get_icount     = uart_get_icount,
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_init      = uart_poll_init,
-       .poll_get_char  = uart_poll_get_char,
-       .poll_put_char  = uart_poll_put_char,
-#endif
-};
-
-static const struct tty_port_operations uart_port_ops = {
-       .carrier_raised = uart_carrier_raised,
-       .dtr_rts        = uart_dtr_rts,
-};
-
-/**
- *     uart_register_driver - register a driver with the uart core layer
- *     @drv: low level driver structure
- *
- *     Register a uart driver with the core driver.  We in turn register
- *     with the tty layer, and initialise the core driver per-port state.
- *
- *     We have a proc file in /proc/tty/driver which is named after the
- *     normal driver.
- *
- *     drv->port should be NULL, and the per-port structures should be
- *     registered using uart_add_one_port after this call has succeeded.
- */
-int uart_register_driver(struct uart_driver *drv)
-{
-       struct tty_driver *normal;
-       int i, retval;
-
-       BUG_ON(drv->state);
-
-       /*
-        * Maybe we should be using a slab cache for this, especially if
-        * we have a large number of ports to handle.
-        */
-       drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
-       if (!drv->state)
-               goto out;
-
-       normal = alloc_tty_driver(drv->nr);
-       if (!normal)
-               goto out_kfree;
-
-       drv->tty_driver = normal;
-
-       normal->owner           = drv->owner;
-       normal->driver_name     = drv->driver_name;
-       normal->name            = drv->dev_name;
-       normal->major           = drv->major;
-       normal->minor_start     = drv->minor;
-       normal->type            = TTY_DRIVER_TYPE_SERIAL;
-       normal->subtype         = SERIAL_TYPE_NORMAL;
-       normal->init_termios    = tty_std_termios;
-       normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-       normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
-       normal->flags           = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
-       normal->driver_state    = drv;
-       tty_set_operations(normal, &uart_ops);
-
-       /*
-        * Initialise the UART state(s).
-        */
-       for (i = 0; i < drv->nr; i++) {
-               struct uart_state *state = drv->state + i;
-               struct tty_port *port = &state->port;
-
-               tty_port_init(port);
-               port->ops = &uart_port_ops;
-               port->close_delay     = 500;    /* .5 seconds */
-               port->closing_wait    = 30000;  /* 30 seconds */
-               tasklet_init(&state->tlet, uart_tasklet_action,
-                            (unsigned long)state);
-       }
-
-       retval = tty_register_driver(normal);
-       if (retval >= 0)
-               return retval;
-
-       put_tty_driver(normal);
-out_kfree:
-       kfree(drv->state);
-out:
-       return -ENOMEM;
-}
-
-/**
- *     uart_unregister_driver - remove a driver from the uart core layer
- *     @drv: low level driver structure
- *
- *     Remove all references to a driver from the core driver.  The low
- *     level driver must have removed all its ports via the
- *     uart_remove_one_port() if it registered them with uart_add_one_port().
- *     (ie, drv->port == NULL)
- */
-void uart_unregister_driver(struct uart_driver *drv)
-{
-       struct tty_driver *p = drv->tty_driver;
-       tty_unregister_driver(p);
-       put_tty_driver(p);
-       kfree(drv->state);
-       drv->tty_driver = NULL;
-}
-
-struct tty_driver *uart_console_device(struct console *co, int *index)
-{
-       struct uart_driver *p = co->data;
-       *index = co->index;
-       return p->tty_driver;
-}
-
-/**
- *     uart_add_one_port - attach a driver-defined port structure
- *     @drv: pointer to the uart low level driver structure for this port
- *     @uport: uart port structure to use for this port.
- *
- *     This allows the driver to register its own uart_port structure
- *     with the core driver.  The main purpose is to allow the low
- *     level uart drivers to expand uart_port, rather than having yet
- *     more levels of structures.
- */
-int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
-{
-       struct uart_state *state;
-       struct tty_port *port;
-       int ret = 0;
-       struct device *tty_dev;
-
-       BUG_ON(in_interrupt());
-
-       if (uport->line >= drv->nr)
-               return -EINVAL;
-
-       state = drv->state + uport->line;
-       port = &state->port;
-
-       mutex_lock(&port_mutex);
-       mutex_lock(&port->mutex);
-       if (state->uart_port) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       state->uart_port = uport;
-       state->pm_state = -1;
-
-       uport->cons = drv->cons;
-       uport->state = state;
-
-       /*
-        * If this port is a console, then the spinlock is already
-        * initialised.
-        */
-       if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) {
-               spin_lock_init(&uport->lock);
-               lockdep_set_class(&uport->lock, &port_lock_key);
-       }
-
-       uart_configure_port(drv, state, uport);
-
-       /*
-        * Register the port whether it's detected or not.  This allows
-        * setserial to be used to alter this ports parameters.
-        */
-       tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev);
-       if (likely(!IS_ERR(tty_dev))) {
-               device_init_wakeup(tty_dev, 1);
-               device_set_wakeup_enable(tty_dev, 0);
-       } else
-               printk(KERN_ERR "Cannot register tty device on line %d\n",
-                      uport->line);
-
-       /*
-        * Ensure UPF_DEAD is not set.
-        */
-       uport->flags &= ~UPF_DEAD;
-
- out:
-       mutex_unlock(&port->mutex);
-       mutex_unlock(&port_mutex);
-
-       return ret;
-}
-
-/**
- *     uart_remove_one_port - detach a driver defined port structure
- *     @drv: pointer to the uart low level driver structure for this port
- *     @uport: uart port structure for this port
- *
- *     This unhooks (and hangs up) the specified port structure from the
- *     core driver.  No further calls will be made to the low-level code
- *     for this port.
- */
-int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
-{
-       struct uart_state *state = drv->state + uport->line;
-       struct tty_port *port = &state->port;
-
-       BUG_ON(in_interrupt());
-
-       if (state->uart_port != uport)
-               printk(KERN_ALERT "Removing wrong port: %p != %p\n",
-                       state->uart_port, uport);
-
-       mutex_lock(&port_mutex);
-
-       /*
-        * Mark the port "dead" - this prevents any opens from
-        * succeeding while we shut down the port.
-        */
-       mutex_lock(&port->mutex);
-       uport->flags |= UPF_DEAD;
-       mutex_unlock(&port->mutex);
-
-       /*
-        * Remove the devices from the tty layer
-        */
-       tty_unregister_device(drv->tty_driver, uport->line);
-
-       if (port->tty)
-               tty_vhangup(port->tty);
-
-       /*
-        * Free the port IO and memory resources, if any.
-        */
-       if (uport->type != PORT_UNKNOWN)
-               uport->ops->release_port(uport);
-
-       /*
-        * Indicate that there isn't a port here anymore.
-        */
-       uport->type = PORT_UNKNOWN;
-
-       /*
-        * Kill the tasklet, and free resources.
-        */
-       tasklet_kill(&state->tlet);
-
-       state->uart_port = NULL;
-       mutex_unlock(&port_mutex);
-
-       return 0;
-}
-
-/*
- *     Are the two ports equivalent?
- */
-int uart_match_port(struct uart_port *port1, struct uart_port *port2)
-{
-       if (port1->iotype != port2->iotype)
-               return 0;
-
-       switch (port1->iotype) {
-       case UPIO_PORT:
-               return (port1->iobase == port2->iobase);
-       case UPIO_HUB6:
-               return (port1->iobase == port2->iobase) &&
-                      (port1->hub6   == port2->hub6);
-       case UPIO_MEM:
-       case UPIO_MEM32:
-       case UPIO_AU:
-       case UPIO_TSI:
-       case UPIO_DWAPB:
-       case UPIO_DWAPB32:
-               return (port1->mapbase == port2->mapbase);
-       }
-       return 0;
-}
-EXPORT_SYMBOL(uart_match_port);
-
-EXPORT_SYMBOL(uart_write_wakeup);
-EXPORT_SYMBOL(uart_register_driver);
-EXPORT_SYMBOL(uart_unregister_driver);
-EXPORT_SYMBOL(uart_suspend_port);
-EXPORT_SYMBOL(uart_resume_port);
-EXPORT_SYMBOL(uart_add_one_port);
-EXPORT_SYMBOL(uart_remove_one_port);
-
-MODULE_DESCRIPTION("Serial driver core");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
deleted file mode 100644 (file)
index 93760b2..0000000
+++ /dev/null
@@ -1,869 +0,0 @@
-/*======================================================================
-
-    A driver for PCMCIA serial devices
-
-    serial_cs.c 1.134 2002/05/04 05:48:53
-
-    The contents of this file are subject to the Mozilla Public
-    License Version 1.1 (the "License"); you may not use this file
-    except in compliance with the License. You may obtain a copy of
-    the License at http://www.mozilla.org/MPL/
-
-    Software distributed under the License is distributed on an "AS
-    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-    implied. See the License for the specific language governing
-    rights and limitations under the License.
-
-    The initial developer of the original code is David A. Hinds
-    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
-    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
-
-    Alternatively, the contents of this file may be used under the
-    terms of the GNU General Public License version 2 (the "GPL"), in which
-    case the provisions of the GPL are applicable instead of the
-    above.  If you wish to allow the use of your version of this file
-    only under the terms of the GPL and not to allow others to use
-    your version of this file under the MPL, indicate your decision
-    by deleting the provisions above and replace them with the notice
-    and other provisions required by the GPL.  If you do not delete
-    the provisions above, a recipient may use your version of this
-    file under either the MPL or the GPL.
-    
-======================================================================*/
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/serial_core.h>
-#include <linux/delay.h>
-#include <linux/major.h>
-#include <asm/io.h>
-#include <asm/system.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ciscode.h>
-#include <pcmcia/ds.h>
-#include <pcmcia/cisreg.h>
-
-#include "8250.h"
-
-
-/*====================================================================*/
-
-/* Parameters that can be set with 'insmod' */
-
-/* Enable the speaker? */
-static int do_sound = 1;
-/* Skip strict UART tests? */
-static int buggy_uart;
-
-module_param(do_sound, int, 0444);
-module_param(buggy_uart, int, 0444);
-
-/*====================================================================*/
-
-/* Table of multi-port card ID's */
-
-struct serial_quirk {
-       unsigned int manfid;
-       unsigned int prodid;
-       int multi;              /* 1 = multifunction, > 1 = # ports */
-       void (*config)(struct pcmcia_device *);
-       void (*setup)(struct pcmcia_device *, struct uart_port *);
-       void (*wakeup)(struct pcmcia_device *);
-       int (*post)(struct pcmcia_device *);
-};
-
-struct serial_info {
-       struct pcmcia_device    *p_dev;
-       int                     ndev;
-       int                     multi;
-       int                     slave;
-       int                     manfid;
-       int                     prodid;
-       int                     c950ctrl;
-       int                     line[4];
-       const struct serial_quirk *quirk;
-};
-
-struct serial_cfg_mem {
-       tuple_t tuple;
-       cisparse_t parse;
-       u_char buf[256];
-};
-
-/*
- * vers_1 5.0, "Brain Boxes", "2-Port RS232 card", "r6"
- * manfid 0x0160, 0x0104
- * This card appears to have a 14.7456MHz clock.
- */
-/* Generic Modem: MD55x (GPRS/EDGE) have
- * Elan VPU16551 UART with 14.7456MHz oscillator
- * manfid 0x015D, 0x4C45
- */
-static void quirk_setup_brainboxes_0104(struct pcmcia_device *link, struct uart_port *port)
-{
-       port->uartclk = 14745600;
-}
-
-static int quirk_post_ibm(struct pcmcia_device *link)
-{
-       u8 val;
-       int ret;
-
-       ret = pcmcia_read_config_byte(link, 0x800, &val);
-       if (ret)
-               goto failed;
-
-       ret = pcmcia_write_config_byte(link, 0x800, val | 1);
-       if (ret)
-               goto failed;
-       return 0;
-
- failed:
-       return -ENODEV;
-}
-
-/*
- * Nokia cards are not really multiport cards.  Shouldn't this
- * be handled by setting the quirk entry .multi = 0 | 1 ?
- */
-static void quirk_config_nokia(struct pcmcia_device *link)
-{
-       struct serial_info *info = link->priv;
-
-       if (info->multi > 1)
-               info->multi = 1;
-}
-
-static void quirk_wakeup_oxsemi(struct pcmcia_device *link)
-{
-       struct serial_info *info = link->priv;
-
-       if (info->c950ctrl)
-               outb(12, info->c950ctrl + 1);
-}
-
-/* request_region? oxsemi branch does no request_region too... */
-/*
- * This sequence is needed to properly initialize MC45 attached to OXCF950.
- * I tried decreasing these msleep()s, but it worked properly (survived
- * 1000 stop/start operations) with these timeouts (or bigger).
- */
-static void quirk_wakeup_possio_gcc(struct pcmcia_device *link)
-{
-       struct serial_info *info = link->priv;
-       unsigned int ctrl = info->c950ctrl;
-
-       outb(0xA, ctrl + 1);
-       msleep(100);
-       outb(0xE, ctrl + 1);
-       msleep(300);
-       outb(0xC, ctrl + 1);
-       msleep(100);
-       outb(0xE, ctrl + 1);
-       msleep(200);
-       outb(0xF, ctrl + 1);
-       msleep(100);
-       outb(0xE, ctrl + 1);
-       msleep(100);
-       outb(0xC, ctrl + 1);
-}
-
-/*
- * Socket Dual IO: this enables irq's for second port
- */
-static void quirk_config_socket(struct pcmcia_device *link)
-{
-       struct serial_info *info = link->priv;
-
-       if (info->multi)
-               link->config_flags |= CONF_ENABLE_ESR;
-}
-
-static const struct serial_quirk quirks[] = {
-       {
-               .manfid = 0x0160,
-               .prodid = 0x0104,
-               .multi  = -1,
-               .setup  = quirk_setup_brainboxes_0104,
-       }, {
-               .manfid = 0x015D,
-               .prodid = 0x4C45,
-               .multi  = -1,
-               .setup  = quirk_setup_brainboxes_0104,
-       }, {
-               .manfid = MANFID_IBM,
-               .prodid = ~0,
-               .multi  = -1,
-               .post   = quirk_post_ibm,
-       }, {
-               .manfid = MANFID_INTEL,
-               .prodid = PRODID_INTEL_DUAL_RS232,
-               .multi  = 2,
-       }, {
-               .manfid = MANFID_NATINST,
-               .prodid = PRODID_NATINST_QUAD_RS232,
-               .multi  = 4,
-       }, {
-               .manfid = MANFID_NOKIA,
-               .prodid = ~0,
-               .multi  = -1,
-               .config = quirk_config_nokia,
-       }, {
-               .manfid = MANFID_OMEGA,
-               .prodid = PRODID_OMEGA_QSP_100,
-               .multi  = 4,
-       }, {
-               .manfid = MANFID_OXSEMI,
-               .prodid = ~0,
-               .multi  = -1,
-               .wakeup = quirk_wakeup_oxsemi,
-       }, {
-               .manfid = MANFID_POSSIO,
-               .prodid = PRODID_POSSIO_GCC,
-               .multi  = -1,
-               .wakeup = quirk_wakeup_possio_gcc,
-       }, {
-               .manfid = MANFID_QUATECH,
-               .prodid = PRODID_QUATECH_DUAL_RS232,
-               .multi  = 2,
-       }, {
-               .manfid = MANFID_QUATECH,
-               .prodid = PRODID_QUATECH_DUAL_RS232_D1,
-               .multi  = 2,
-       }, {
-               .manfid = MANFID_QUATECH,
-               .prodid = PRODID_QUATECH_DUAL_RS232_G,
-               .multi  = 2,
-       }, {
-               .manfid = MANFID_QUATECH,
-               .prodid = PRODID_QUATECH_QUAD_RS232,
-               .multi  = 4,
-       }, {
-               .manfid = MANFID_SOCKET,
-               .prodid = PRODID_SOCKET_DUAL_RS232,
-               .multi  = 2,
-               .config = quirk_config_socket,
-       }, {
-               .manfid = MANFID_SOCKET,
-               .prodid = ~0,
-               .multi  = -1,
-               .config = quirk_config_socket,
-       }
-};
-
-
-static int serial_config(struct pcmcia_device * link);
-
-
-static void serial_remove(struct pcmcia_device *link)
-{
-       struct serial_info *info = link->priv;
-       int i;
-
-       dev_dbg(&link->dev, "serial_release\n");
-
-       /*
-        * Recheck to see if the device is still configured.
-        */
-       for (i = 0; i < info->ndev; i++)
-               serial8250_unregister_port(info->line[i]);
-
-       if (!info->slave)
-               pcmcia_disable_device(link);
-}
-
-static int serial_suspend(struct pcmcia_device *link)
-{
-       struct serial_info *info = link->priv;
-       int i;
-
-       for (i = 0; i < info->ndev; i++)
-               serial8250_suspend_port(info->line[i]);
-
-       return 0;
-}
-
-static int serial_resume(struct pcmcia_device *link)
-{
-       struct serial_info *info = link->priv;
-       int i;
-
-       for (i = 0; i < info->ndev; i++)
-               serial8250_resume_port(info->line[i]);
-
-       if (info->quirk && info->quirk->wakeup)
-               info->quirk->wakeup(link);
-
-       return 0;
-}
-
-static int serial_probe(struct pcmcia_device *link)
-{
-       struct serial_info *info;
-
-       dev_dbg(&link->dev, "serial_attach()\n");
-
-       /* Create new serial device */
-       info = kzalloc(sizeof (*info), GFP_KERNEL);
-       if (!info)
-               return -ENOMEM;
-       info->p_dev = link;
-       link->priv = info;
-
-       link->config_flags |= CONF_ENABLE_IRQ;
-       if (do_sound)
-               link->config_flags |= CONF_ENABLE_SPKR;
-
-       return serial_config(link);
-}
-
-static void serial_detach(struct pcmcia_device *link)
-{
-       struct serial_info *info = link->priv;
-
-       dev_dbg(&link->dev, "serial_detach\n");
-
-       /*
-        * Ensure that the ports have been released.
-        */
-       serial_remove(link);
-
-       /* free bits */
-       kfree(info);
-}
-
-/*====================================================================*/
-
-static int setup_serial(struct pcmcia_device *handle, struct serial_info * info,
-                       unsigned int iobase, int irq)
-{
-       struct uart_port port;
-       int line;
-
-       memset(&port, 0, sizeof (struct uart_port));
-       port.iobase = iobase;
-       port.irq = irq;
-       port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
-       port.uartclk = 1843200;
-       port.dev = &handle->dev;
-       if (buggy_uart)
-               port.flags |= UPF_BUGGY_UART;
-
-       if (info->quirk && info->quirk->setup)
-               info->quirk->setup(handle, &port);
-
-       line = serial8250_register_port(&port);
-       if (line < 0) {
-               printk(KERN_NOTICE "serial_cs: serial8250_register_port() at "
-                      "0x%04lx, irq %d failed\n", (u_long)iobase, irq);
-               return -EINVAL;
-       }
-
-       info->line[info->ndev] = line;
-       info->ndev++;
-
-       return 0;
-}
-
-/*====================================================================*/
-
-static int pfc_config(struct pcmcia_device *p_dev)
-{
-       unsigned int port = 0;
-       struct serial_info *info = p_dev->priv;
-
-       if ((p_dev->resource[1]->end != 0) &&
-               (resource_size(p_dev->resource[1]) == 8)) {
-               port = p_dev->resource[1]->start;
-               info->slave = 1;
-       } else if ((info->manfid == MANFID_OSITECH) &&
-               (resource_size(p_dev->resource[0]) == 0x40)) {
-               port = p_dev->resource[0]->start + 0x28;
-               info->slave = 1;
-       }
-       if (info->slave)
-               return setup_serial(p_dev, info, port, p_dev->irq);
-
-       dev_warn(&p_dev->dev, "no usable port range found, giving up\n");
-       return -ENODEV;
-}
-
-static int simple_config_check(struct pcmcia_device *p_dev, void *priv_data)
-{
-       static const int size_table[2] = { 8, 16 };
-       int *try = priv_data;
-
-       if (p_dev->resource[0]->start == 0)
-               return -ENODEV;
-
-       if ((*try & 0x1) == 0)
-               p_dev->io_lines = 16;
-
-       if (p_dev->resource[0]->end != size_table[(*try >> 1)])
-               return -ENODEV;
-
-       p_dev->resource[0]->end = 8;
-       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-
-       return pcmcia_request_io(p_dev);
-}
-
-static int simple_config_check_notpicky(struct pcmcia_device *p_dev,
-                                       void *priv_data)
-{
-       static const unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
-       int j;
-
-       if (p_dev->io_lines > 3)
-               return -ENODEV;
-
-       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-       p_dev->resource[0]->end = 8;
-
-       for (j = 0; j < 5; j++) {
-               p_dev->resource[0]->start = base[j];
-               p_dev->io_lines = base[j] ? 16 : 3;
-               if (!pcmcia_request_io(p_dev))
-                       return 0;
-       }
-       return -ENODEV;
-}
-
-static int simple_config(struct pcmcia_device *link)
-{
-       struct serial_info *info = link->priv;
-       int i = -ENODEV, try;
-
-       /* First pass: look for a config entry that looks normal.
-        * Two tries: without IO aliases, then with aliases */
-       link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_SET_IO;
-       for (try = 0; try < 4; try++)
-               if (!pcmcia_loop_config(link, simple_config_check, &try))
-                       goto found_port;
-
-       /* Second pass: try to find an entry that isn't picky about
-          its base address, then try to grab any standard serial port
-          address, and finally try to get any free port. */
-       if (!pcmcia_loop_config(link, simple_config_check_notpicky, NULL))
-               goto found_port;
-
-       dev_warn(&link->dev, "no usable port range found, giving up\n");
-       return -1;
-
-found_port:
-       if (info->multi && (info->manfid == MANFID_3COM))
-               link->config_index &= ~(0x08);
-
-       /*
-        * Apply any configuration quirks.
-        */
-       if (info->quirk && info->quirk->config)
-               info->quirk->config(link);
-
-       i = pcmcia_enable_device(link);
-       if (i != 0)
-               return -1;
-       return setup_serial(link, info, link->resource[0]->start, link->irq);
-}
-
-static int multi_config_check(struct pcmcia_device *p_dev, void *priv_data)
-{
-       int *multi = priv_data;
-
-       if (p_dev->resource[1]->end)
-               return -EINVAL;
-
-       /* The quad port cards have bad CIS's, so just look for a
-          window larger than 8 ports and assume it will be right */
-       if (p_dev->resource[0]->end <= 8)
-               return -EINVAL;
-
-       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-       p_dev->resource[0]->end = *multi * 8;
-
-       if (pcmcia_request_io(p_dev))
-               return -ENODEV;
-       return 0;
-}
-
-static int multi_config_check_notpicky(struct pcmcia_device *p_dev,
-                                      void *priv_data)
-{
-       int *base2 = priv_data;
-
-       if (!p_dev->resource[0]->end || !p_dev->resource[1]->end)
-               return -ENODEV;
-
-       p_dev->resource[0]->end = p_dev->resource[1]->end = 8;
-       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-
-       if (pcmcia_request_io(p_dev))
-               return -ENODEV;
-
-       *base2 = p_dev->resource[0]->start + 8;
-       return 0;
-}
-
-static int multi_config(struct pcmcia_device *link)
-{
-       struct serial_info *info = link->priv;
-       int i, base2 = 0;
-
-       link->config_flags |= CONF_AUTO_SET_IO;
-       /* First, look for a generic full-sized window */
-       if (!pcmcia_loop_config(link, multi_config_check, &info->multi))
-               base2 = link->resource[0]->start + 8;
-       else {
-               /* If that didn't work, look for two windows */
-               info->multi = 2;
-               if (pcmcia_loop_config(link, multi_config_check_notpicky,
-                                      &base2)) {
-                       dev_warn(&link->dev, "no usable port range "
-                              "found, giving up\n");
-                       return -ENODEV;
-               }
-       }
-
-       if (!link->irq)
-               dev_warn(&link->dev, "no usable IRQ found, continuing...\n");
-
-       /*
-        * Apply any configuration quirks.
-        */
-       if (info->quirk && info->quirk->config)
-               info->quirk->config(link);
-
-       i = pcmcia_enable_device(link);
-       if (i != 0)
-               return -ENODEV;
-
-       /* The Oxford Semiconductor OXCF950 cards are in fact single-port:
-        * 8 registers are for the UART, the others are extra registers.
-        * Siemen's MC45 PCMCIA (Possio's GCC) is OXCF950 based too.
-        */
-       if (info->manfid == MANFID_OXSEMI || (info->manfid == MANFID_POSSIO &&
-                               info->prodid == PRODID_POSSIO_GCC)) {
-               int err;
-
-               if (link->config_index == 1 ||
-                   link->config_index == 3) {
-                       err = setup_serial(link, info, base2,
-                                       link->irq);
-                       base2 = link->resource[0]->start;
-               } else {
-                       err = setup_serial(link, info, link->resource[0]->start,
-                                       link->irq);
-               }
-               info->c950ctrl = base2;
-
-               /*
-                * FIXME: We really should wake up the port prior to
-                * handing it over to the serial layer.
-                */
-               if (info->quirk && info->quirk->wakeup)
-                       info->quirk->wakeup(link);
-
-               return 0;
-       }
-
-       setup_serial(link, info, link->resource[0]->start, link->irq);
-       for (i = 0; i < info->multi - 1; i++)
-               setup_serial(link, info, base2 + (8 * i),
-                               link->irq);
-       return 0;
-}
-
-static int serial_check_for_multi(struct pcmcia_device *p_dev,  void *priv_data)
-{
-       struct serial_info *info = p_dev->priv;
-
-       if (!p_dev->resource[0]->end)
-               return -EINVAL;
-
-       if ((!p_dev->resource[1]->end) && (p_dev->resource[0]->end % 8 == 0))
-               info->multi = p_dev->resource[0]->end >> 3;
-
-       if ((p_dev->resource[1]->end) && (p_dev->resource[0]->end == 8)
-               && (p_dev->resource[1]->end == 8))
-               info->multi = 2;
-
-       return 0; /* break */
-}
-
-
-static int serial_config(struct pcmcia_device * link)
-{
-       struct serial_info *info = link->priv;
-       int i;
-
-       dev_dbg(&link->dev, "serial_config\n");
-
-       /* Is this a compliant multifunction card? */
-       info->multi = (link->socket->functions > 1);
-
-       /* Is this a multiport card? */
-       info->manfid = link->manf_id;
-       info->prodid = link->card_id;
-
-       for (i = 0; i < ARRAY_SIZE(quirks); i++)
-               if ((quirks[i].manfid == ~0 ||
-                    quirks[i].manfid == info->manfid) &&
-                   (quirks[i].prodid == ~0 ||
-                    quirks[i].prodid == info->prodid)) {
-                       info->quirk = &quirks[i];
-                       break;
-               }
-
-       /* Another check for dual-serial cards: look for either serial or
-          multifunction cards that ask for appropriate IO port ranges */
-       if ((info->multi == 0) &&
-           (link->has_func_id) &&
-           (link->socket->pcmcia_pfc == 0) &&
-           ((link->func_id == CISTPL_FUNCID_MULTI) ||
-            (link->func_id == CISTPL_FUNCID_SERIAL)))
-               pcmcia_loop_config(link, serial_check_for_multi, info);
-
-       /*
-        * Apply any multi-port quirk.
-        */
-       if (info->quirk && info->quirk->multi != -1)
-               info->multi = info->quirk->multi;
-
-       dev_info(&link->dev,
-               "trying to set up [0x%04x:0x%04x] (pfc: %d, multi: %d, quirk: %p)\n",
-               link->manf_id, link->card_id,
-               link->socket->pcmcia_pfc, info->multi, info->quirk);
-       if (link->socket->pcmcia_pfc)
-               i = pfc_config(link);
-       else if (info->multi > 1)
-               i = multi_config(link);
-       else
-               i = simple_config(link);
-
-       if (i || info->ndev == 0)
-               goto failed;
-
-       /*
-        * Apply any post-init quirk.  FIXME: This should really happen
-        * before we register the port, since it might already be in use.
-        */
-       if (info->quirk && info->quirk->post)
-               if (info->quirk->post(link))
-                       goto failed;
-
-       return 0;
-
-failed:
-       dev_warn(&link->dev, "failed to initialize\n");
-       serial_remove(link);
-       return -ENODEV;
-}
-
-static struct pcmcia_device_id serial_ids[] = {
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0057, 0x0021),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0089, 0x110a),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0104, 0x000a),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0d0a),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0e0a),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0xea15),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0109, 0x0501),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0138, 0x110a),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0140, 0x000a),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0143, 0x3341),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0143, 0xc0ab),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x016c, 0x0081),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x021b, 0x0101),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x08a1, 0xc0ab),
-       PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63),
-       PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63),
-       PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef),
-       PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef),
-       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM28", 0x2e3ee845, 0x0ea978ea),
-       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM33", 0x2e3ee845, 0x80609023),
-       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM56", 0x2e3ee845, 0xa650c32a),
-       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "REM10", 0x2e3ee845, 0x76df1d29),
-       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "XEM5600", 0x2e3ee845, 0xf1403719),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "AnyCom", "Fast Ethernet + 56K COMBO", 0x578ba6e7, 0xb0ac62c4),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "ATKK", "LM33-PCM-T", 0xba9eb7e2, 0x077c174e),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "D-Link", "DME336T", 0x1a424a1c, 0xb23897ff),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "MICRO RESEARCH", "COMBO-L/M-336", 0xb2ced065, 0x3ced0555),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "NEC", "PK-UG-J001" ,0x18df0ba0 ,0x831b1064),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c648f),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Xircom", "CreditCard Ethernet+Modem II", 0x2e3ee845, 0xeca401bf),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0e01),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0a05),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x1101),
-       PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0104, 0x0070),
-       PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0101, 0x0562),
-       PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0104, 0x0070),
-       PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x016c, 0x0020),
-       PCMCIA_MFC_DEVICE_PROD_ID123(1, "APEX DATA", "MULTICARD", "ETHERNET-MODEM", 0x11c2da09, 0x7289dc5d, 0xaad95e1f),
-       PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "Home and Away 28.8 PC Card       ", 0xb569a6e5, 0x5bd4ff2c),
-       PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "Home and Away Credit Card Adapter", 0xb569a6e5, 0x4bdf15c3),
-       PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "w95 Home and Away Credit Card ", 0xb569a6e5, 0xae911c15),
-       PCMCIA_MFC_DEVICE_PROD_ID1(1, "Motorola MARQUIS", 0xf03e4e77),
-       PCMCIA_MFC_DEVICE_PROD_ID2(1, "FAX/Modem/Ethernet Combo Card ", 0x1ed59302),
-       PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0301),
-       PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x0276),
-       PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0039),
-       PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0006),
-       PCMCIA_DEVICE_MANF_CARD(0x0105, 0x0101), /* TDK DF2814 */
-       PCMCIA_DEVICE_MANF_CARD(0x0105, 0x100a), /* Xircom CM-56G */
-       PCMCIA_DEVICE_MANF_CARD(0x0105, 0x3e0a), /* TDK DF5660 */
-       PCMCIA_DEVICE_MANF_CARD(0x0105, 0x410a),
-       PCMCIA_DEVICE_MANF_CARD(0x0107, 0x0002), /* USRobotics 14,400 */
-       PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d50),
-       PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d51),
-       PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d52),
-       PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d53),
-       PCMCIA_DEVICE_MANF_CARD(0x010b, 0xd180),
-       PCMCIA_DEVICE_MANF_CARD(0x0115, 0x3330), /* USRobotics/SUN 14,400 */
-       PCMCIA_DEVICE_MANF_CARD(0x0124, 0x0100), /* Nokia DTP-2 ver II */
-       PCMCIA_DEVICE_MANF_CARD(0x0134, 0x5600), /* LASAT COMMUNICATIONS A/S */
-       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x000e),
-       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x001b),
-       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0025),
-       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0045),
-       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0052),
-       PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0006), /* Psion 56K+Fax */
-       PCMCIA_DEVICE_MANF_CARD(0x0200, 0x0001), /* MultiMobile */
-       PCMCIA_DEVICE_PROD_ID134("ADV", "TECH", "COMpad-32/85", 0x67459937, 0x916d02ba, 0x8fbe92ae),
-       PCMCIA_DEVICE_PROD_ID124("GATEWAY2000", "CC3144", "PCMCIA MODEM", 0x506bccae, 0xcb3685f1, 0xbd6c43ef),
-       PCMCIA_DEVICE_PROD_ID14("MEGAHERTZ", "PCMCIA MODEM", 0xf510db04, 0xbd6c43ef),
-       PCMCIA_DEVICE_PROD_ID124("TOSHIBA", "T144PF", "PCMCIA MODEM", 0xb4585a1a, 0x7271409c, 0xbd6c43ef),
-       PCMCIA_DEVICE_PROD_ID123("FUJITSU", "FC14F ", "MBH10213", 0x6ee5a3d8, 0x30ead12b, 0xb00f05a0),
-       PCMCIA_DEVICE_PROD_ID123("Novatel Wireless", "Merlin UMTS Modem", "U630", 0x32607776, 0xd9e73b13, 0xe87332e),
-       PCMCIA_DEVICE_PROD_ID13("MEGAHERTZ", "V.34 PCMCIA MODEM", 0xf510db04, 0xbb2cce4a),
-       PCMCIA_DEVICE_PROD_ID12("Brain Boxes", "Bluetooth PC Card", 0xee138382, 0xd4ce9b02),
-       PCMCIA_DEVICE_PROD_ID12("CIRRUS LOGIC", "FAX MODEM", 0xe625f451, 0xcecd6dfa),
-       PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 28800 FAX/DATA MODEM", 0xa3a3062c, 0x8cbd7c76),
-       PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 33600 FAX/DATA MODEM", 0xa3a3062c, 0x5a00ce95),
-       PCMCIA_DEVICE_PROD_ID12("Computerboards, Inc.", "PCM-COM422", 0xd0b78f51, 0x7e2d49ed),
-       PCMCIA_DEVICE_PROD_ID12("Dr. Neuhaus", "FURY CARD 14K4", 0x76942813, 0x8b96ce65),
-       PCMCIA_DEVICE_PROD_ID12("IBM", "ISDN/56K/GSM", 0xb569a6e5, 0xfee5297b),
-       PCMCIA_DEVICE_PROD_ID12("Intelligent", "ANGIA FAX/MODEM", 0xb496e65e, 0xf31602a6),
-       PCMCIA_DEVICE_PROD_ID12("Intel", "MODEM 2400+", 0x816cc815, 0x412729fb),
-       PCMCIA_DEVICE_PROD_ID12("Intertex", "IX34-PCMCIA", 0xf8a097e3, 0x97880447),
-       PCMCIA_DEVICE_PROD_ID12("IOTech Inc ", "PCMCIA Dual RS-232 Serial Port Card", 0x3bd2d898, 0x92abc92f),
-       PCMCIA_DEVICE_PROD_ID12("MACRONIX", "FAX/MODEM", 0x668388b3, 0x3f9bdf2f),
-       PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT1432LT", 0x5f73be51, 0x0b3e2383),
-       PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT2834LT", 0x5f73be51, 0x4cd7c09e),
-       PCMCIA_DEVICE_PROD_ID12("OEM      ", "C288MX     ", 0xb572d360, 0xd2385b7a),
-       PCMCIA_DEVICE_PROD_ID12("Option International", "V34bis GSM/PSTN Data/Fax Modem", 0x9d7cd6f5, 0x5cb8bf41),
-       PCMCIA_DEVICE_PROD_ID12("PCMCIA   ", "C336MX     ", 0x99bcafe9, 0xaa25bcab),
-       PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "PCMCIA Dual RS-232 Serial Port Card", 0xc4420b35, 0x92abc92f),
-       PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "Dual RS-232 Serial Port PC Card", 0xc4420b35, 0x031a380d),
-       PCMCIA_DEVICE_PROD_ID12("Telia", "SurfinBird 560P/A+", 0xe2cdd5e, 0xc9314b38),
-       PCMCIA_DEVICE_PROD_ID1("Smart Serial Port", 0x2d8ce292),
-       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "EN2218-LAN/MODEM", 0x281f1c5d, 0x570f348e, "cis/PCMLM28.cis"),
-       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "UE2218-LAN/MODEM", 0x281f1c5d, 0x6fdcacee, "cis/PCMLM28.cis"),
-       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "cis/PCMLM28.cis"),
-       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet GSM", 0xf5f025c2, 0x4ae85d35, "cis/PCMLM28.cis"),
-       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "cis/PCMLM28.cis"),
-       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "TOSHIBA", "Modem/LAN Card", 0xb4585a1a, 0x53f922f8, "cis/PCMLM28.cis"),
-       PCMCIA_MFC_DEVICE_CIS_PROD_ID12(1, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "cis/DP83903.cis"),
-       PCMCIA_MFC_DEVICE_CIS_PROD_ID4(1, "NSC MF LAN/Modem", 0x58fc6056, "cis/DP83903.cis"),
-       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0556, "cis/3CCFEM556.cis"),
-       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0175, 0x0000, "cis/DP83903.cis"),
-       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0035, "cis/3CXEM556.cis"),
-       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x003d, "cis/3CXEM556.cis"),
-       PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC850", 0xd85f6206, 0x42a2c018, "cis/SW_8xx_SER.cis"), /* Sierra Wireless AC850 3G Network Adapter R1 */
-       PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC860", 0xd85f6206, 0x698f93db, "cis/SW_8xx_SER.cis"), /* Sierra Wireless AC860 3G Network Adapter R1 */
-       PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC710/AC750", 0xd85f6206, 0x761b11e0, "cis/SW_7xx_SER.cis"),  /* Sierra Wireless AC710/AC750 GPRS Network Adapter R1 */
-       PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0xa555, "cis/SW_555_SER.cis"),  /* Sierra Aircard 555 CDMA 1xrtt Modem -- pre update */
-       PCMCIA_DEVICE_CIS_MANF_CARD(0x013f, 0xa555, "cis/SW_555_SER.cis"),  /* Sierra Aircard 555 CDMA 1xrtt Modem -- post update */
-       PCMCIA_DEVICE_CIS_PROD_ID12("MultiTech", "PCMCIA 56K DataFax", 0x842047ee, 0xc2efcf03, "cis/MT5634ZLX.cis"),
-       PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-2", 0x96913a85, 0x27ab5437, "cis/COMpad2.cis"),
-       PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-4", 0x96913a85, 0xcec8f102, "cis/COMpad4.cis"),
-       PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "cis/COMpad2.cis"),
-       PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "cis/RS-COM-2P.cis"),
-       PCMCIA_DEVICE_CIS_MANF_CARD(0x0013, 0x0000, "cis/GLOBETROTTER.cis"),
-       PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100  1.00.",0x19ca78af,0xf964f42b),
-       PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100",0x19ca78af,0x71d98e83),
-       PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL232  1.00.",0x19ca78af,0x69fb7490),
-       PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL232",0x19ca78af,0xb6bc0235),
-       PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.","SERIAL CARD: CF232",0x63f2e0bd,0xb9e175d3),
-       PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.","SERIAL CARD: CF232-5",0x63f2e0bd,0xfce33442),
-       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF232",0x3beb8cf2,0x171e7190),
-       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF232-5",0x3beb8cf2,0x20da4262),
-       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF428",0x3beb8cf2,0xea5dd57d),
-       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF500",0x3beb8cf2,0xd77255fa),
-       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: IC232",0x3beb8cf2,0x6a709903),
-       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: SL232",0x3beb8cf2,0x18430676),
-       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: XL232",0x3beb8cf2,0x6f933767),
-       PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: CF332",0x3beb8cf2,0x16dc1ba7),
-       PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL332",0x3beb8cf2,0x19816c41),
-       PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL385",0x3beb8cf2,0x64112029),
-       PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
-       PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc),
-       PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: CF332",0x3beb8cf2,0x16dc1ba7),
-       PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL332",0x3beb8cf2,0x19816c41),
-       PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL385",0x3beb8cf2,0x64112029),
-       PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
-       PCMCIA_MFC_DEVICE_PROD_ID12(2,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
-       PCMCIA_MFC_DEVICE_PROD_ID12(3,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
-       PCMCIA_DEVICE_MANF_CARD(0x0279, 0x950b),
-       /* too generic */
-       /* PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0160, 0x0002), */
-       /* PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0160, 0x0002), */
-       PCMCIA_DEVICE_FUNC_ID(2),
-       PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, serial_ids);
-
-MODULE_FIRMWARE("cis/PCMLM28.cis");
-MODULE_FIRMWARE("cis/DP83903.cis");
-MODULE_FIRMWARE("cis/3CCFEM556.cis");
-MODULE_FIRMWARE("cis/3CXEM556.cis");
-MODULE_FIRMWARE("cis/SW_8xx_SER.cis");
-MODULE_FIRMWARE("cis/SW_7xx_SER.cis");
-MODULE_FIRMWARE("cis/SW_555_SER.cis");
-MODULE_FIRMWARE("cis/MT5634ZLX.cis");
-MODULE_FIRMWARE("cis/COMpad2.cis");
-MODULE_FIRMWARE("cis/COMpad4.cis");
-MODULE_FIRMWARE("cis/RS-COM-2P.cis");
-
-static struct pcmcia_driver serial_cs_driver = {
-       .owner          = THIS_MODULE,
-       .name           = "serial_cs",
-       .probe          = serial_probe,
-       .remove         = serial_detach,
-       .id_table       = serial_ids,
-       .suspend        = serial_suspend,
-       .resume         = serial_resume,
-};
-
-static int __init init_serial_cs(void)
-{
-       return pcmcia_register_driver(&serial_cs_driver);
-}
-
-static void __exit exit_serial_cs(void)
-{
-       pcmcia_unregister_driver(&serial_cs_driver);
-}
-
-module_init(init_serial_cs);
-module_exit(exit_serial_cs);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/serial_ks8695.c b/drivers/serial/serial_ks8695.c
deleted file mode 100644 (file)
index b196202..0000000
+++ /dev/null
@@ -1,705 +0,0 @@
-/*
- *  drivers/serial/serial_ks8695.c
- *
- *  Driver for KS8695 serial ports
- *
- *  Based on drivers/serial/serial_amba.c, by Kam Lee.
- *
- *  Copyright 2002-2005 Micrel Inc.
- *
- * 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.
- *
- */
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/serial.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/device.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/mach/irq.h>
-
-#include <mach/regs-uart.h>
-#include <mach/regs-irq.h>
-
-#if defined(CONFIG_SERIAL_KS8695_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
-
-#define SERIAL_KS8695_MAJOR    204
-#define SERIAL_KS8695_MINOR    16
-#define SERIAL_KS8695_DEVNAME  "ttyAM"
-
-#define SERIAL_KS8695_NR       1
-
-/*
- * Access macros for the KS8695 UART
- */
-#define UART_GET_CHAR(p)       (__raw_readl((p)->membase + KS8695_URRB) & 0xFF)
-#define UART_PUT_CHAR(p, c)    __raw_writel((c), (p)->membase + KS8695_URTH)
-#define UART_GET_FCR(p)                __raw_readl((p)->membase + KS8695_URFC)
-#define UART_PUT_FCR(p, c)     __raw_writel((c), (p)->membase + KS8695_URFC)
-#define UART_GET_MSR(p)                __raw_readl((p)->membase + KS8695_URMS)
-#define UART_GET_LSR(p)                __raw_readl((p)->membase + KS8695_URLS)
-#define UART_GET_LCR(p)                __raw_readl((p)->membase + KS8695_URLC)
-#define UART_PUT_LCR(p, c)     __raw_writel((c), (p)->membase + KS8695_URLC)
-#define UART_GET_MCR(p)                __raw_readl((p)->membase + KS8695_URMC)
-#define UART_PUT_MCR(p, c)     __raw_writel((c), (p)->membase + KS8695_URMC)
-#define UART_GET_BRDR(p)       __raw_readl((p)->membase + KS8695_URBD)
-#define UART_PUT_BRDR(p, c)    __raw_writel((c), (p)->membase + KS8695_URBD)
-
-#define KS8695_CLR_TX_INT()    __raw_writel(1 << KS8695_IRQ_UART_TX, KS8695_IRQ_VA + KS8695_INTST)
-
-#define UART_DUMMY_LSR_RX      0x100
-#define UART_PORT_SIZE         (KS8695_USR - KS8695_URRB + 4)
-
-static inline int tx_enabled(struct uart_port *port)
-{
-       return port->unused[0] & 1;
-}
-
-static inline int rx_enabled(struct uart_port *port)
-{
-       return port->unused[0] & 2;
-}
-
-static inline int ms_enabled(struct uart_port *port)
-{
-       return port->unused[0] & 4;
-}
-
-static inline void ms_enable(struct uart_port *port, int enabled)
-{
-       if(enabled)
-               port->unused[0] |= 4;
-       else
-               port->unused[0] &= ~4;
-}
-
-static inline void rx_enable(struct uart_port *port, int enabled)
-{
-       if(enabled)
-               port->unused[0] |= 2;
-       else
-               port->unused[0] &= ~2;
-}
-
-static inline void tx_enable(struct uart_port *port, int enabled)
-{
-       if(enabled)
-               port->unused[0] |= 1;
-       else
-               port->unused[0] &= ~1;
-}
-
-
-#ifdef SUPPORT_SYSRQ
-static struct console ks8695_console;
-#endif
-
-static void ks8695uart_stop_tx(struct uart_port *port)
-{
-       if (tx_enabled(port)) {
-               /* use disable_irq_nosync() and not disable_irq() to avoid self
-                * imposed deadlock by not waiting for irq handler to end,
-                * since this ks8695uart_stop_tx() is called from interrupt context.
-                */
-               disable_irq_nosync(KS8695_IRQ_UART_TX);
-               tx_enable(port, 0);
-       }
-}
-
-static void ks8695uart_start_tx(struct uart_port *port)
-{
-       if (!tx_enabled(port)) {
-               enable_irq(KS8695_IRQ_UART_TX);
-               tx_enable(port, 1);
-       }
-}
-
-static void ks8695uart_stop_rx(struct uart_port *port)
-{
-       if (rx_enabled(port)) {
-               disable_irq(KS8695_IRQ_UART_RX);
-               rx_enable(port, 0);
-       }
-}
-
-static void ks8695uart_enable_ms(struct uart_port *port)
-{
-       if (!ms_enabled(port)) {
-               enable_irq(KS8695_IRQ_UART_MODEM_STATUS);
-               ms_enable(port,1);
-       }
-}
-
-static void ks8695uart_disable_ms(struct uart_port *port)
-{
-       if (ms_enabled(port)) {
-               disable_irq(KS8695_IRQ_UART_MODEM_STATUS);
-               ms_enable(port,0);
-       }
-}
-
-static irqreturn_t ks8695uart_rx_chars(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       struct tty_struct *tty = port->state->port.tty;
-       unsigned int status, ch, lsr, flg, max_count = 256;
-
-       status = UART_GET_LSR(port);            /* clears pending LSR interrupts */
-       while ((status & URLS_URDR) && max_count--) {
-               ch = UART_GET_CHAR(port);
-               flg = TTY_NORMAL;
-
-               port->icount.rx++;
-
-               /*
-                * Note that the error handling code is
-                * out of the main execution path
-                */
-               lsr = UART_GET_LSR(port) | UART_DUMMY_LSR_RX;
-               if (unlikely(lsr & (URLS_URBI | URLS_URPE | URLS_URFE | URLS_URROE))) {
-                       if (lsr & URLS_URBI) {
-                               lsr &= ~(URLS_URFE | URLS_URPE);
-                               port->icount.brk++;
-                               if (uart_handle_break(port))
-                                       goto ignore_char;
-                       }
-                       if (lsr & URLS_URPE)
-                               port->icount.parity++;
-                       if (lsr & URLS_URFE)
-                               port->icount.frame++;
-                       if (lsr & URLS_URROE)
-                               port->icount.overrun++;
-
-                       lsr &= port->read_status_mask;
-
-                       if (lsr & URLS_URBI)
-                               flg = TTY_BREAK;
-                       else if (lsr & URLS_URPE)
-                               flg = TTY_PARITY;
-                       else if (lsr & URLS_URFE)
-                               flg = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(port, ch))
-                       goto ignore_char;
-
-               uart_insert_char(port, lsr, URLS_URROE, ch, flg);
-
-ignore_char:
-               status = UART_GET_LSR(port);
-       }
-       tty_flip_buffer_push(tty);
-
-       return IRQ_HANDLED;
-}
-
-
-static irqreturn_t ks8695uart_tx_chars(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       struct circ_buf *xmit = &port->state->xmit;
-       unsigned int count;
-
-       if (port->x_char) {
-               KS8695_CLR_TX_INT();
-               UART_PUT_CHAR(port, port->x_char);
-               port->icount.tx++;
-               port->x_char = 0;
-               return IRQ_HANDLED;
-       }
-
-       if (uart_tx_stopped(port) || uart_circ_empty(xmit)) {
-               ks8695uart_stop_tx(port);
-               return IRQ_HANDLED;
-       }
-
-       count = 16;     /* fifo size */
-       while (!uart_circ_empty(xmit) && (count-- > 0)) {
-               KS8695_CLR_TX_INT();
-               UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
-
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (uart_circ_empty(xmit))
-               ks8695uart_stop_tx(port);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t ks8695uart_modem_status(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       unsigned int status;
-
-       /*
-        * clear modem interrupt by reading MSR
-        */
-       status = UART_GET_MSR(port);
-
-       if (status & URMS_URDDCD)
-               uart_handle_dcd_change(port, status & URMS_URDDCD);
-
-       if (status & URMS_URDDST)
-               port->icount.dsr++;
-
-       if (status & URMS_URDCTS)
-               uart_handle_cts_change(port, status & URMS_URDCTS);
-
-       if (status & URMS_URTERI)
-               port->icount.rng++;
-
-       wake_up_interruptible(&port->state->port.delta_msr_wait);
-
-       return IRQ_HANDLED;
-}
-
-static unsigned int ks8695uart_tx_empty(struct uart_port *port)
-{
-       return (UART_GET_LSR(port) & URLS_URTE) ? TIOCSER_TEMT : 0;
-}
-
-static unsigned int ks8695uart_get_mctrl(struct uart_port *port)
-{
-       unsigned int result = 0;
-       unsigned int status;
-
-       status = UART_GET_MSR(port);
-       if (status & URMS_URDCD)
-               result |= TIOCM_CAR;
-       if (status & URMS_URDSR)
-               result |= TIOCM_DSR;
-       if (status & URMS_URCTS)
-               result |= TIOCM_CTS;
-       if (status & URMS_URRI)
-               result |= TIOCM_RI;
-
-       return result;
-}
-
-static void ks8695uart_set_mctrl(struct uart_port *port, u_int mctrl)
-{
-       unsigned int mcr;
-
-       mcr = UART_GET_MCR(port);
-       if (mctrl & TIOCM_RTS)
-               mcr |= URMC_URRTS;
-       else
-               mcr &= ~URMC_URRTS;
-
-       if (mctrl & TIOCM_DTR)
-               mcr |= URMC_URDTR;
-       else
-               mcr &= ~URMC_URDTR;
-
-       UART_PUT_MCR(port, mcr);
-}
-
-static void ks8695uart_break_ctl(struct uart_port *port, int break_state)
-{
-       unsigned int lcr;
-
-       lcr = UART_GET_LCR(port);
-
-       if (break_state == -1)
-               lcr |= URLC_URSBC;
-       else
-               lcr &= ~URLC_URSBC;
-
-       UART_PUT_LCR(port, lcr);
-}
-
-static int ks8695uart_startup(struct uart_port *port)
-{
-       int retval;
-
-       set_irq_flags(KS8695_IRQ_UART_TX, IRQF_VALID | IRQF_NOAUTOEN);
-       tx_enable(port, 0);
-       rx_enable(port, 1);
-       ms_enable(port, 1);
-
-       /*
-        * Allocate the IRQ
-        */
-       retval = request_irq(KS8695_IRQ_UART_TX, ks8695uart_tx_chars, IRQF_DISABLED, "UART TX", port);
-       if (retval)
-               goto err_tx;
-
-       retval = request_irq(KS8695_IRQ_UART_RX, ks8695uart_rx_chars, IRQF_DISABLED, "UART RX", port);
-       if (retval)
-               goto err_rx;
-
-       retval = request_irq(KS8695_IRQ_UART_LINE_STATUS, ks8695uart_rx_chars, IRQF_DISABLED, "UART LineStatus", port);
-       if (retval)
-               goto err_ls;
-
-       retval = request_irq(KS8695_IRQ_UART_MODEM_STATUS, ks8695uart_modem_status, IRQF_DISABLED, "UART ModemStatus", port);
-       if (retval)
-               goto err_ms;
-
-       return 0;
-
-err_ms:
-       free_irq(KS8695_IRQ_UART_LINE_STATUS, port);
-err_ls:
-       free_irq(KS8695_IRQ_UART_RX, port);
-err_rx:
-       free_irq(KS8695_IRQ_UART_TX, port);
-err_tx:
-       return retval;
-}
-
-static void ks8695uart_shutdown(struct uart_port *port)
-{
-       /*
-        * Free the interrupt
-        */
-       free_irq(KS8695_IRQ_UART_RX, port);
-       free_irq(KS8695_IRQ_UART_TX, port);
-       free_irq(KS8695_IRQ_UART_MODEM_STATUS, port);
-       free_irq(KS8695_IRQ_UART_LINE_STATUS, port);
-
-       /* disable break condition and fifos */
-       UART_PUT_LCR(port, UART_GET_LCR(port) & ~URLC_URSBC);
-       UART_PUT_FCR(port, UART_GET_FCR(port) & ~URFC_URFE);
-}
-
-static void ks8695uart_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old)
-{
-       unsigned int lcr, fcr = 0;
-       unsigned long flags;
-       unsigned int baud, quot;
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
-       quot = uart_get_divisor(port, baud);
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               lcr = URCL_5;
-               break;
-       case CS6:
-               lcr = URCL_6;
-               break;
-       case CS7:
-               lcr = URCL_7;
-               break;
-       default:
-               lcr = URCL_8;
-               break;
-       }
-
-       /* stop bits */
-       if (termios->c_cflag & CSTOPB)
-               lcr |= URLC_URSB;
-
-       /* parity */
-       if (termios->c_cflag & PARENB) {
-               if (termios->c_cflag & CMSPAR) {        /* Mark or Space parity */
-                       if (termios->c_cflag & PARODD)
-                               lcr |= URPE_MARK;
-                       else
-                               lcr |= URPE_SPACE;
-               }
-               else if (termios->c_cflag & PARODD)
-                       lcr |= URPE_ODD;
-               else
-                       lcr |= URPE_EVEN;
-       }
-
-       if (port->fifosize > 1)
-               fcr = URFC_URFRT_8 | URFC_URTFR | URFC_URRFR | URFC_URFE;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       port->read_status_mask = URLS_URROE;
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= (URLS_URFE | URLS_URPE);
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               port->read_status_mask |= URLS_URBI;
-
-       /*
-        * Characters to ignore
-        */
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= (URLS_URFE | URLS_URPE);
-       if (termios->c_iflag & IGNBRK) {
-               port->ignore_status_mask |= URLS_URBI;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       port->ignore_status_mask |= URLS_URROE;
-       }
-
-       /*
-        * Ignore all characters if CREAD is not set.
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               port->ignore_status_mask |= UART_DUMMY_LSR_RX;
-
-       /* first, disable everything */
-       if (UART_ENABLE_MS(port, termios->c_cflag))
-               ks8695uart_enable_ms(port);
-       else
-               ks8695uart_disable_ms(port);
-
-       /* Set baud rate */
-       UART_PUT_BRDR(port, quot);
-
-       UART_PUT_LCR(port, lcr);
-       UART_PUT_FCR(port, fcr);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *ks8695uart_type(struct uart_port *port)
-{
-       return port->type == PORT_KS8695 ? "KS8695" : NULL;
-}
-
-/*
- * Release the memory region(s) being used by 'port'
- */
-static void ks8695uart_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 ks8695uart_request_port(struct uart_port *port)
-{
-       return request_mem_region(port->mapbase, UART_PORT_SIZE,
-                       "serial_ks8695") != NULL ? 0 : -EBUSY;
-}
-
-/*
- * Configure/autoconfigure the port.
- */
-static void ks8695uart_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE) {
-               port->type = PORT_KS8695;
-               ks8695uart_request_port(port);
-       }
-}
-
-/*
- * verify the new serial_struct (for TIOCSSERIAL).
- */
-static int ks8695uart_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       int ret = 0;
-
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_KS8695)
-               ret = -EINVAL;
-       if (ser->irq != port->irq)
-               ret = -EINVAL;
-       if (ser->baud_base < 9600)
-               ret = -EINVAL;
-       return ret;
-}
-
-static struct uart_ops ks8695uart_pops = {
-       .tx_empty       = ks8695uart_tx_empty,
-       .set_mctrl      = ks8695uart_set_mctrl,
-       .get_mctrl      = ks8695uart_get_mctrl,
-       .stop_tx        = ks8695uart_stop_tx,
-       .start_tx       = ks8695uart_start_tx,
-       .stop_rx        = ks8695uart_stop_rx,
-       .enable_ms      = ks8695uart_enable_ms,
-       .break_ctl      = ks8695uart_break_ctl,
-       .startup        = ks8695uart_startup,
-       .shutdown       = ks8695uart_shutdown,
-       .set_termios    = ks8695uart_set_termios,
-       .type           = ks8695uart_type,
-       .release_port   = ks8695uart_release_port,
-       .request_port   = ks8695uart_request_port,
-       .config_port    = ks8695uart_config_port,
-       .verify_port    = ks8695uart_verify_port,
-};
-
-static struct uart_port ks8695uart_ports[SERIAL_KS8695_NR] = {
-       {
-               .membase        = (void *) KS8695_UART_VA,
-               .mapbase        = KS8695_UART_VA,
-               .iotype         = SERIAL_IO_MEM,
-               .irq            = KS8695_IRQ_UART_TX,
-               .uartclk        = KS8695_CLOCK_RATE * 16,
-               .fifosize       = 16,
-               .ops            = &ks8695uart_pops,
-               .flags          = ASYNC_BOOT_AUTOCONF,
-               .line           = 0,
-       }
-};
-
-#ifdef CONFIG_SERIAL_KS8695_CONSOLE
-static void ks8695_console_putchar(struct uart_port *port, int ch)
-{
-       while (!(UART_GET_LSR(port) & URLS_URTHRE))
-               barrier();
-
-       UART_PUT_CHAR(port, ch);
-}
-
-static void ks8695_console_write(struct console *co, const char *s, u_int count)
-{
-       struct uart_port *port = ks8695uart_ports + co->index;
-
-       uart_console_write(port, s, count, ks8695_console_putchar);
-}
-
-static void __init ks8695_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
-{
-       unsigned int lcr;
-
-       lcr = UART_GET_LCR(port);
-
-       switch (lcr & URLC_PARITY) {
-               case URPE_ODD:
-                       *parity = 'o';
-                       break;
-               case URPE_EVEN:
-                       *parity = 'e';
-                       break;
-               default:
-                       *parity = 'n';
-       }
-
-       switch (lcr & URLC_URCL) {
-               case URCL_5:
-                       *bits = 5;
-                       break;
-               case URCL_6:
-                       *bits = 6;
-                       break;
-               case URCL_7:
-                       *bits = 7;
-                       break;
-               default:
-                       *bits = 8;
-       }
-
-       *baud = port->uartclk / (UART_GET_BRDR(port) & 0x0FFF);
-       *baud /= 16;
-       *baud &= 0xFFFFFFF0;
-}
-
-static int __init ks8695_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port;
-       int baud = 115200;
-       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(ks8695uart_ports, SERIAL_KS8695_NR, co);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               ks8695_console_get_options(port, &baud, &parity, &bits);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver ks8695_reg;
-
-static struct console ks8695_console = {
-       .name           = SERIAL_KS8695_DEVNAME,
-       .write          = ks8695_console_write,
-       .device         = uart_console_device,
-       .setup          = ks8695_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &ks8695_reg,
-};
-
-static int __init ks8695_console_init(void)
-{
-       add_preferred_console(SERIAL_KS8695_DEVNAME, 0, NULL);
-       register_console(&ks8695_console);
-       return 0;
-}
-
-console_initcall(ks8695_console_init);
-
-#define KS8695_CONSOLE &ks8695_console
-#else
-#define KS8695_CONSOLE NULL
-#endif
-
-static struct uart_driver ks8695_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "serial_ks8695",
-       .dev_name               = SERIAL_KS8695_DEVNAME,
-       .major                  = SERIAL_KS8695_MAJOR,
-       .minor                  = SERIAL_KS8695_MINOR,
-       .nr                     = SERIAL_KS8695_NR,
-       .cons                   = KS8695_CONSOLE,
-};
-
-static int __init ks8695uart_init(void)
-{
-       int i, ret;
-
-       printk(KERN_INFO "Serial: Micrel KS8695 UART driver\n");
-
-       ret = uart_register_driver(&ks8695_reg);
-       if (ret)
-               return ret;
-
-       for (i = 0; i < SERIAL_KS8695_NR; i++)
-               uart_add_one_port(&ks8695_reg, &ks8695uart_ports[0]);
-
-       return 0;
-}
-
-static void __exit ks8695uart_exit(void)
-{
-       int i;
-
-       for (i = 0; i < SERIAL_KS8695_NR; i++)
-               uart_remove_one_port(&ks8695_reg, &ks8695uart_ports[0]);
-       uart_unregister_driver(&ks8695_reg);
-}
-
-module_init(ks8695uart_init);
-module_exit(ks8695uart_exit);
-
-MODULE_DESCRIPTION("KS8695 serial port driver");
-MODULE_AUTHOR("Micrel Inc.");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c
deleted file mode 100644 (file)
index ea74470..0000000
+++ /dev/null
@@ -1,682 +0,0 @@
-/* drivers/serial/serial_lh7a40x.c
- *
- *  Copyright (C) 2004 Coastal Environmental Systems
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  version 2 as published by the Free Software Foundation.
- *
- */
-
-/* Driver for Sharp LH7A40X embedded serial ports
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *  Based on drivers/serial/amba.c, by Deep Blue Solutions Ltd.
- *
- *  ---
- *
- * This driver supports the embedded UARTs of the Sharp LH7A40X series
- * CPUs.  While similar to the 16550 and other UART chips, there is
- * nothing close to register compatibility.  Moreover, some of the
- * modem control lines are not available, either in the chip or they
- * are lacking in the board-level implementation.
- *
- * - Use of SIRDIS
- *   For simplicity, we disable the IR functions of any UART whenever
- *   we enable it.
- *
- */
-
-
-#if defined(CONFIG_SERIAL_LH7A40X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <mach/hardware.h>
-
-#define DEV_MAJOR      204
-#define DEV_MINOR      16
-#define DEV_NR         3
-
-#define ISR_LOOP_LIMIT 256
-
-#define UR(p,o)        _UR ((p)->membase, o)
-#define _UR(b,o) (*((volatile unsigned int*)(((unsigned char*) b) + (o))))
-#define BIT_CLR(p,o,m) UR(p,o) = UR(p,o) & (~(unsigned int)m)
-#define BIT_SET(p,o,m) UR(p,o) = UR(p,o) | ( (unsigned int)m)
-
-#define UART_REG_SIZE  32
-
-#define UART_R_DATA    (0x00)
-#define UART_R_FCON    (0x04)
-#define UART_R_BRCON   (0x08)
-#define UART_R_CON     (0x0c)
-#define UART_R_STATUS  (0x10)
-#define UART_R_RAWISR  (0x14)
-#define UART_R_INTEN   (0x18)
-#define UART_R_ISR     (0x1c)
-
-#define UARTEN         (0x01)          /* UART enable */
-#define SIRDIS         (0x02)          /* Serial IR disable (UART1 only) */
-
-#define RxEmpty                (0x10)
-#define TxEmpty                (0x80)
-#define TxFull         (0x20)
-#define nRxRdy         RxEmpty
-#define nTxRdy         TxFull
-#define TxBusy         (0x08)
-
-#define RxBreak                (0x0800)
-#define RxOverrunError (0x0400)
-#define RxParityError  (0x0200)
-#define RxFramingError (0x0100)
-#define RxError     (RxBreak | RxOverrunError | RxParityError | RxFramingError)
-
-#define DCD            (0x04)
-#define DSR            (0x02)
-#define CTS            (0x01)
-
-#define RxInt          (0x01)
-#define TxInt          (0x02)
-#define ModemInt       (0x04)
-#define RxTimeoutInt   (0x08)
-
-#define MSEOI          (0x10)
-
-#define WLEN_8         (0x60)
-#define WLEN_7         (0x40)
-#define WLEN_6         (0x20)
-#define WLEN_5         (0x00)
-#define WLEN           (0x60)  /* Mask for all word-length bits */
-#define STP2           (0x08)
-#define PEN            (0x02)  /* Parity Enable */
-#define EPS            (0x04)  /* Even Parity Set */
-#define FEN            (0x10)  /* FIFO Enable */
-#define BRK            (0x01)  /* Send Break */
-
-
-struct uart_port_lh7a40x {
-       struct uart_port port;
-       unsigned int statusPrev; /* Most recently read modem status */
-};
-
-static void lh7a40xuart_stop_tx (struct uart_port* port)
-{
-       BIT_CLR (port, UART_R_INTEN, TxInt);
-}
-
-static void lh7a40xuart_start_tx (struct uart_port* port)
-{
-       BIT_SET (port, UART_R_INTEN, TxInt);
-
-       /* *** FIXME: do I need to check for startup of the
-                     transmitter?  The old driver did, but AMBA
-                     doesn't . */
-}
-
-static void lh7a40xuart_stop_rx (struct uart_port* port)
-{
-       BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
-}
-
-static void lh7a40xuart_enable_ms (struct uart_port* port)
-{
-       BIT_SET (port, UART_R_INTEN, ModemInt);
-}
-
-static void lh7a40xuart_rx_chars (struct uart_port* port)
-{
-       struct tty_struct* tty = port->state->port.tty;
-       int cbRxMax = 256;      /* (Gross) limit on receive */
-       unsigned int data;      /* Received data and status */
-       unsigned int flag;
-
-       while (!(UR (port, UART_R_STATUS) & nRxRdy) && --cbRxMax) {
-               data = UR (port, UART_R_DATA);
-               flag = TTY_NORMAL;
-               ++port->icount.rx;
-
-               if (unlikely(data & RxError)) {
-                       if (data & RxBreak) {
-                               data &= ~(RxFramingError | RxParityError);
-                               ++port->icount.brk;
-                               if (uart_handle_break (port))
-                                       continue;
-                       }
-                       else if (data & RxParityError)
-                               ++port->icount.parity;
-                       else if (data & RxFramingError)
-                               ++port->icount.frame;
-                       if (data & RxOverrunError)
-                               ++port->icount.overrun;
-
-                               /* Mask by termios, leave Rx'd byte */
-                       data &= port->read_status_mask | 0xff;
-
-                       if (data & RxBreak)
-                               flag = TTY_BREAK;
-                       else if (data & RxParityError)
-                               flag = TTY_PARITY;
-                       else if (data & RxFramingError)
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char (port, (unsigned char) data))
-                       continue;
-
-               uart_insert_char(port, data, RxOverrunError, data, flag);
-       }
-       tty_flip_buffer_push (tty);
-       return;
-}
-
-static void lh7a40xuart_tx_chars (struct uart_port* port)
-{
-       struct circ_buf* xmit = &port->state->xmit;
-       int cbTxMax = port->fifosize;
-
-       if (port->x_char) {
-               UR (port, UART_R_DATA) = port->x_char;
-               ++port->icount.tx;
-               port->x_char = 0;
-               return;
-       }
-       if (uart_circ_empty (xmit) || uart_tx_stopped (port)) {
-               lh7a40xuart_stop_tx (port);
-               return;
-       }
-
-       /* Unlike the AMBA UART, the lh7a40x UART does not guarantee
-          that at least half of the FIFO is empty.  Instead, we check
-          status for every character.  Using the AMBA method causes
-          the transmitter to drop characters. */
-
-       do {
-               UR (port, UART_R_DATA) = xmit->buf[xmit->tail];
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               ++port->icount.tx;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (!(UR (port, UART_R_STATUS) & nTxRdy)
-                && cbTxMax--);
-
-       if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS)
-               uart_write_wakeup (port);
-
-       if (uart_circ_empty (xmit))
-               lh7a40xuart_stop_tx (port);
-}
-
-static void lh7a40xuart_modem_status (struct uart_port* port)
-{
-       unsigned int status = UR (port, UART_R_STATUS);
-       unsigned int delta
-               = status ^ ((struct uart_port_lh7a40x*) port)->statusPrev;
-
-       BIT_SET (port, UART_R_RAWISR, MSEOI); /* Clear modem status intr */
-
-       if (!delta)             /* Only happens if we missed 2 transitions */
-               return;
-
-       ((struct uart_port_lh7a40x*) port)->statusPrev = status;
-
-       if (delta & DCD)
-               uart_handle_dcd_change (port, status & DCD);
-
-       if (delta & DSR)
-               ++port->icount.dsr;
-
-       if (delta & CTS)
-               uart_handle_cts_change (port, status & CTS);
-
-       wake_up_interruptible (&port->state->port.delta_msr_wait);
-}
-
-static irqreturn_t lh7a40xuart_int (int irq, void* dev_id)
-{
-       struct uart_port* port = dev_id;
-       unsigned int cLoopLimit = ISR_LOOP_LIMIT;
-       unsigned int isr = UR (port, UART_R_ISR);
-
-
-       do {
-               if (isr & (RxInt | RxTimeoutInt))
-                       lh7a40xuart_rx_chars(port);
-               if (isr & ModemInt)
-                       lh7a40xuart_modem_status (port);
-               if (isr & TxInt)
-                       lh7a40xuart_tx_chars (port);
-
-               if (--cLoopLimit == 0)
-                       break;
-
-               isr = UR (port, UART_R_ISR);
-       } while (isr & (RxInt | TxInt | RxTimeoutInt));
-
-       return IRQ_HANDLED;
-}
-
-static unsigned int lh7a40xuart_tx_empty (struct uart_port* port)
-{
-       return (UR (port, UART_R_STATUS) & TxEmpty) ? TIOCSER_TEMT : 0;
-}
-
-static unsigned int lh7a40xuart_get_mctrl (struct uart_port* port)
-{
-       unsigned int result = 0;
-       unsigned int status = UR (port, UART_R_STATUS);
-
-       if (status & DCD)
-               result |= TIOCM_CAR;
-       if (status & DSR)
-               result |= TIOCM_DSR;
-       if (status & CTS)
-               result |= TIOCM_CTS;
-
-       return result;
-}
-
-static void lh7a40xuart_set_mctrl (struct uart_port* port, unsigned int mctrl)
-{
-       /* None of the ports supports DTR. UART1 supports RTS through GPIO. */
-       /* Note, kernel appears to be setting DTR and RTS on console. */
-
-       /* *** FIXME: this deserves more work.  There's some work in
-              tracing all of the IO pins. */
-#if 0
-       if( port->mapbase == UART1_PHYS) {
-               gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS);
-
-               if (mctrl & TIOCM_RTS)
-                       gpio->pbdr &= ~GPIOB_UART1_RTS;
-               else
-                       gpio->pbdr |= GPIOB_UART1_RTS;
-       }
-#endif
-}
-
-static void lh7a40xuart_break_ctl (struct uart_port* port, int break_state)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       if (break_state == -1)
-               BIT_SET (port, UART_R_FCON, BRK); /* Assert break */
-       else
-               BIT_CLR (port, UART_R_FCON, BRK); /* Deassert break */
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static int lh7a40xuart_startup (struct uart_port* port)
-{
-       int retval;
-
-       retval = request_irq (port->irq, lh7a40xuart_int, 0,
-                             "serial_lh7a40x", port);
-       if (retval)
-               return retval;
-
-                               /* Initial modem control-line settings */
-       ((struct uart_port_lh7a40x*) port)->statusPrev
-               = UR (port, UART_R_STATUS);
-
-       /* There is presently no configuration option to enable IR.
-          Thus, we always disable it. */
-
-       BIT_SET (port, UART_R_CON, UARTEN | SIRDIS);
-       BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
-
-       return 0;
-}
-
-static void lh7a40xuart_shutdown (struct uart_port* port)
-{
-       free_irq (port->irq, port);
-       BIT_CLR (port, UART_R_FCON, BRK | FEN);
-       BIT_CLR (port, UART_R_CON, UARTEN);
-}
-
-static void lh7a40xuart_set_termios (struct uart_port* port,
-                                    struct ktermios* termios,
-                                    struct ktermios* old)
-{
-       unsigned int con;
-       unsigned int inten;
-       unsigned int fcon;
-       unsigned long flags;
-       unsigned int baud;
-       unsigned int quot;
-
-       baud = uart_get_baud_rate (port, termios, old, 8, port->uartclk/16);
-       quot = uart_get_divisor (port, baud); /* -1 performed elsewhere */
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               fcon = WLEN_5;
-               break;
-       case CS6:
-               fcon = WLEN_6;
-               break;
-       case CS7:
-               fcon = WLEN_7;
-               break;
-       case CS8:
-       default:
-               fcon = WLEN_8;
-               break;
-       }
-       if (termios->c_cflag & CSTOPB)
-               fcon |= STP2;
-       if (termios->c_cflag & PARENB) {
-               fcon |= PEN;
-               if (!(termios->c_cflag & PARODD))
-                       fcon |= EPS;
-       }
-       if (port->fifosize > 1)
-               fcon |= FEN;
-
-       spin_lock_irqsave (&port->lock, flags);
-
-       uart_update_timeout (port, termios->c_cflag, baud);
-
-       port->read_status_mask = RxOverrunError;
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= RxFramingError | RxParityError;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               port->read_status_mask |= RxBreak;
-
-               /* Figure mask for status we ignore */
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= RxFramingError | RxParityError;
-       if (termios->c_iflag & IGNBRK) {
-               port->ignore_status_mask |= RxBreak;
-               /* Ignore overrun when ignorning parity */
-               /* *** FIXME: is this in the right place? */
-               if (termios->c_iflag & IGNPAR)
-                       port->ignore_status_mask |= RxOverrunError;
-       }
-
-               /* Ignore all receive errors when receive disabled */
-       if ((termios->c_cflag & CREAD) == 0)
-               port->ignore_status_mask |= RxError;
-
-       con   = UR (port, UART_R_CON);
-       inten = (UR (port, UART_R_INTEN) & ~ModemInt);
-
-       if (UART_ENABLE_MS (port, termios->c_cflag))
-               inten |= ModemInt;
-
-       BIT_CLR (port, UART_R_CON, UARTEN);     /* Disable UART */
-       UR (port, UART_R_INTEN) = 0;            /* Disable interrupts */
-       UR (port, UART_R_BRCON) = quot - 1;     /* Set baud rate divisor */
-       UR (port, UART_R_FCON)  = fcon;         /* Set FIFO and frame ctrl */
-       UR (port, UART_R_INTEN) = inten;        /* Enable interrupts */
-       UR (port, UART_R_CON)   = con;          /* Restore UART mode */
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char* lh7a40xuart_type (struct uart_port* port)
-{
-       return port->type == PORT_LH7A40X ? "LH7A40X" : NULL;
-}
-
-static void lh7a40xuart_release_port (struct uart_port* port)
-{
-       release_mem_region (port->mapbase, UART_REG_SIZE);
-}
-
-static int lh7a40xuart_request_port (struct uart_port* port)
-{
-       return request_mem_region (port->mapbase, UART_REG_SIZE,
-                                  "serial_lh7a40x") != NULL
-               ? 0 : -EBUSY;
-}
-
-static void lh7a40xuart_config_port (struct uart_port* port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE) {
-               port->type = PORT_LH7A40X;
-               lh7a40xuart_request_port (port);
-       }
-}
-
-static int lh7a40xuart_verify_port (struct uart_port* port,
-                                   struct serial_struct* ser)
-{
-       int ret = 0;
-
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_LH7A40X)
-               ret = -EINVAL;
-       if (ser->irq < 0 || ser->irq >= nr_irqs)
-               ret = -EINVAL;
-       if (ser->baud_base < 9600) /* *** FIXME: is this true? */
-               ret = -EINVAL;
-       return ret;
-}
-
-static struct uart_ops lh7a40x_uart_ops = {
-       .tx_empty       = lh7a40xuart_tx_empty,
-       .set_mctrl      = lh7a40xuart_set_mctrl,
-       .get_mctrl      = lh7a40xuart_get_mctrl,
-       .stop_tx        = lh7a40xuart_stop_tx,
-       .start_tx       = lh7a40xuart_start_tx,
-       .stop_rx        = lh7a40xuart_stop_rx,
-       .enable_ms      = lh7a40xuart_enable_ms,
-       .break_ctl      = lh7a40xuart_break_ctl,
-       .startup        = lh7a40xuart_startup,
-       .shutdown       = lh7a40xuart_shutdown,
-       .set_termios    = lh7a40xuart_set_termios,
-       .type           = lh7a40xuart_type,
-       .release_port   = lh7a40xuart_release_port,
-       .request_port   = lh7a40xuart_request_port,
-       .config_port    = lh7a40xuart_config_port,
-       .verify_port    = lh7a40xuart_verify_port,
-};
-
-static struct uart_port_lh7a40x lh7a40x_ports[DEV_NR] = {
-       {
-               .port = {
-                       .membase        = (void*) io_p2v (UART1_PHYS),
-                       .mapbase        = UART1_PHYS,
-                       .iotype         = UPIO_MEM,
-                       .irq            = IRQ_UART1INTR,
-                       .uartclk        = 14745600/2,
-                       .fifosize       = 16,
-                       .ops            = &lh7a40x_uart_ops,
-                       .flags          = UPF_BOOT_AUTOCONF,
-                       .line           = 0,
-               },
-       },
-       {
-               .port = {
-                       .membase        = (void*) io_p2v (UART2_PHYS),
-                       .mapbase        = UART2_PHYS,
-                       .iotype         = UPIO_MEM,
-                       .irq            = IRQ_UART2INTR,
-                       .uartclk        = 14745600/2,
-                       .fifosize       = 16,
-                       .ops            = &lh7a40x_uart_ops,
-                       .flags          = UPF_BOOT_AUTOCONF,
-                       .line           = 1,
-               },
-       },
-       {
-               .port = {
-                       .membase        = (void*) io_p2v (UART3_PHYS),
-                       .mapbase        = UART3_PHYS,
-                       .iotype         = UPIO_MEM,
-                       .irq            = IRQ_UART3INTR,
-                       .uartclk        = 14745600/2,
-                       .fifosize       = 16,
-                       .ops            = &lh7a40x_uart_ops,
-                       .flags          = UPF_BOOT_AUTOCONF,
-                       .line           = 2,
-               },
-       },
-};
-
-#ifndef CONFIG_SERIAL_LH7A40X_CONSOLE
-# define LH7A40X_CONSOLE NULL
-#else
-# define LH7A40X_CONSOLE &lh7a40x_console
-
-static void lh7a40xuart_console_putchar(struct uart_port *port, int ch)
-{
-       while (UR(port, UART_R_STATUS) & nTxRdy)
-               ;
-       UR(port, UART_R_DATA) = ch;
-}
-
-static void lh7a40xuart_console_write (struct console* co,
-                                      const char* s,
-                                      unsigned int count)
-{
-       struct uart_port* port = &lh7a40x_ports[co->index].port;
-       unsigned int con = UR (port, UART_R_CON);
-       unsigned int inten = UR (port, UART_R_INTEN);
-
-
-       UR (port, UART_R_INTEN) = 0;            /* Disable all interrupts */
-       BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); /* Enable UART */
-
-       uart_console_write(port, s, count, lh7a40xuart_console_putchar);
-
-                               /* Wait until all characters are sent */
-       while (UR (port, UART_R_STATUS) & TxBusy)
-               ;
-
-                               /* Restore control and interrupt mask */
-       UR (port, UART_R_CON) = con;
-       UR (port, UART_R_INTEN) = inten;
-}
-
-static void __init lh7a40xuart_console_get_options (struct uart_port* port,
-                                                   int* baud,
-                                                   int* parity,
-                                                   int* bits)
-{
-       if (UR (port, UART_R_CON) & UARTEN) {
-               unsigned int fcon = UR (port, UART_R_FCON);
-               unsigned int quot = UR (port, UART_R_BRCON) + 1;
-
-               switch (fcon & (PEN | EPS)) {
-               default:        *parity = 'n'; break;
-               case PEN:       *parity = 'o'; break;
-               case PEN | EPS: *parity = 'e'; break;
-               }
-
-               switch (fcon & WLEN) {
-               default:
-               case WLEN_8: *bits = 8; break;
-               case WLEN_7: *bits = 7; break;
-               case WLEN_6: *bits = 6; break;
-               case WLEN_5: *bits = 5; break;
-               }
-
-               *baud = port->uartclk/(16*quot);
-       }
-}
-
-static int __init lh7a40xuart_console_setup (struct console* co, char* options)
-{
-       struct uart_port* port;
-       int baud = 38400;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       if (co->index >= DEV_NR) /* Bounds check on device number */
-               co->index = 0;
-       port = &lh7a40x_ports[co->index].port;
-
-       if (options)
-               uart_parse_options (options, &baud, &parity, &bits, &flow);
-       else
-               lh7a40xuart_console_get_options (port, &baud, &parity, &bits);
-
-       return uart_set_options (port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver lh7a40x_reg;
-static struct console lh7a40x_console = {
-       .name           = "ttyAM",
-       .write          = lh7a40xuart_console_write,
-       .device         = uart_console_device,
-       .setup          = lh7a40xuart_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &lh7a40x_reg,
-};
-
-static int __init lh7a40xuart_console_init(void)
-{
-       register_console (&lh7a40x_console);
-       return 0;
-}
-
-console_initcall (lh7a40xuart_console_init);
-
-#endif
-
-static struct uart_driver lh7a40x_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "ttyAM",
-       .dev_name               = "ttyAM",
-       .major                  = DEV_MAJOR,
-       .minor                  = DEV_MINOR,
-       .nr                     = DEV_NR,
-       .cons                   = LH7A40X_CONSOLE,
-};
-
-static int __init lh7a40xuart_init(void)
-{
-       int ret;
-
-       printk (KERN_INFO "serial: LH7A40X serial driver\n");
-
-       ret = uart_register_driver (&lh7a40x_reg);
-
-       if (ret == 0) {
-               int i;
-
-               for (i = 0; i < DEV_NR; i++) {
-                       /* UART3, when used, requires GPIO pin reallocation */
-                       if (lh7a40x_ports[i].port.mapbase == UART3_PHYS)
-                               GPIO_PINMUX |= 1<<3;
-                       uart_add_one_port (&lh7a40x_reg,
-                                          &lh7a40x_ports[i].port);
-               }
-       }
-       return ret;
-}
-
-static void __exit lh7a40xuart_exit(void)
-{
-       int i;
-
-       for (i = 0; i < DEV_NR; i++)
-               uart_remove_one_port (&lh7a40x_reg, &lh7a40x_ports[i].port);
-
-       uart_unregister_driver (&lh7a40x_reg);
-}
-
-module_init (lh7a40xuart_init);
-module_exit (lh7a40xuart_exit);
-
-MODULE_AUTHOR ("Marc Singer");
-MODULE_DESCRIPTION ("Sharp LH7A40X serial port driver");
-MODULE_LICENSE ("GPL");
diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c
deleted file mode 100644 (file)
index c50e9fb..0000000
+++ /dev/null
@@ -1,1344 +0,0 @@
-/*
- *  drivers/serial/serial_txx9.c
- *
- * Derived from many drivers using generic_serial interface,
- * especially serial_tx3912.c by Steven J. Hill and r39xx_serial.c
- * (was in Linux/VR tree) by Jim Pick.
- *
- *  Copyright (C) 1999 Harald Koerfgen
- *  Copyright (C) 2000 Jim Pick <jim@jimpick.com>
- *  Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com)
- *  Copyright (C) 2000-2002 Toshiba Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  Serial driver for TX3927/TX4927/TX4925/TX4938 internal SIO controller
- */
-
-#if defined(CONFIG_SERIAL_TXX9_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/pci.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-
-#include <asm/io.h>
-
-static char *serial_version = "1.11";
-static char *serial_name = "TX39/49 Serial driver";
-
-#define PASS_LIMIT     256
-
-#if !defined(CONFIG_SERIAL_TXX9_STDSERIAL)
-/* "ttyS" is used for standard serial driver */
-#define TXX9_TTY_NAME "ttyTX"
-#define TXX9_TTY_MINOR_START   196
-#define TXX9_TTY_MAJOR 204
-#else
-/* acts like standard serial driver */
-#define TXX9_TTY_NAME "ttyS"
-#define TXX9_TTY_MINOR_START   64
-#define TXX9_TTY_MAJOR TTY_MAJOR
-#endif
-
-/* flag aliases */
-#define UPF_TXX9_HAVE_CTS_LINE UPF_BUGGY_UART
-#define UPF_TXX9_USE_SCLK      UPF_MAGIC_MULTIPLIER
-
-#ifdef CONFIG_PCI
-/* support for Toshiba TC86C001 SIO */
-#define ENABLE_SERIAL_TXX9_PCI
-#endif
-
-/*
- * Number of serial ports
- */
-#define UART_NR  CONFIG_SERIAL_TXX9_NR_UARTS
-
-struct uart_txx9_port {
-       struct uart_port        port;
-       /* No additional info for now */
-};
-
-#define TXX9_REGION_SIZE       0x24
-
-/* TXX9 Serial Registers */
-#define TXX9_SILCR     0x00
-#define TXX9_SIDICR    0x04
-#define TXX9_SIDISR    0x08
-#define TXX9_SICISR    0x0c
-#define TXX9_SIFCR     0x10
-#define TXX9_SIFLCR    0x14
-#define TXX9_SIBGR     0x18
-#define TXX9_SITFIFO   0x1c
-#define TXX9_SIRFIFO   0x20
-
-/* SILCR : Line Control */
-#define TXX9_SILCR_SCS_MASK    0x00000060
-#define TXX9_SILCR_SCS_IMCLK   0x00000000
-#define TXX9_SILCR_SCS_IMCLK_BG        0x00000020
-#define TXX9_SILCR_SCS_SCLK    0x00000040
-#define TXX9_SILCR_SCS_SCLK_BG 0x00000060
-#define TXX9_SILCR_UEPS        0x00000010
-#define TXX9_SILCR_UPEN        0x00000008
-#define TXX9_SILCR_USBL_MASK   0x00000004
-#define TXX9_SILCR_USBL_1BIT   0x00000000
-#define TXX9_SILCR_USBL_2BIT   0x00000004
-#define TXX9_SILCR_UMODE_MASK  0x00000003
-#define TXX9_SILCR_UMODE_8BIT  0x00000000
-#define TXX9_SILCR_UMODE_7BIT  0x00000001
-
-/* SIDICR : DMA/Int. Control */
-#define TXX9_SIDICR_TDE        0x00008000
-#define TXX9_SIDICR_RDE        0x00004000
-#define TXX9_SIDICR_TIE        0x00002000
-#define TXX9_SIDICR_RIE        0x00001000
-#define TXX9_SIDICR_SPIE       0x00000800
-#define TXX9_SIDICR_CTSAC      0x00000600
-#define TXX9_SIDICR_STIE_MASK  0x0000003f
-#define TXX9_SIDICR_STIE_OERS          0x00000020
-#define TXX9_SIDICR_STIE_CTSS          0x00000010
-#define TXX9_SIDICR_STIE_RBRKD 0x00000008
-#define TXX9_SIDICR_STIE_TRDY          0x00000004
-#define TXX9_SIDICR_STIE_TXALS 0x00000002
-#define TXX9_SIDICR_STIE_UBRKD 0x00000001
-
-/* SIDISR : DMA/Int. Status */
-#define TXX9_SIDISR_UBRK       0x00008000
-#define TXX9_SIDISR_UVALID     0x00004000
-#define TXX9_SIDISR_UFER       0x00002000
-#define TXX9_SIDISR_UPER       0x00001000
-#define TXX9_SIDISR_UOER       0x00000800
-#define TXX9_SIDISR_ERI        0x00000400
-#define TXX9_SIDISR_TOUT       0x00000200
-#define TXX9_SIDISR_TDIS       0x00000100
-#define TXX9_SIDISR_RDIS       0x00000080
-#define TXX9_SIDISR_STIS       0x00000040
-#define TXX9_SIDISR_RFDN_MASK  0x0000001f
-
-/* SICISR : Change Int. Status */
-#define TXX9_SICISR_OERS       0x00000020
-#define TXX9_SICISR_CTSS       0x00000010
-#define TXX9_SICISR_RBRKD      0x00000008
-#define TXX9_SICISR_TRDY       0x00000004
-#define TXX9_SICISR_TXALS      0x00000002
-#define TXX9_SICISR_UBRKD      0x00000001
-
-/* SIFCR : FIFO Control */
-#define TXX9_SIFCR_SWRST       0x00008000
-#define TXX9_SIFCR_RDIL_MASK   0x00000180
-#define TXX9_SIFCR_RDIL_1      0x00000000
-#define TXX9_SIFCR_RDIL_4      0x00000080
-#define TXX9_SIFCR_RDIL_8      0x00000100
-#define TXX9_SIFCR_RDIL_12     0x00000180
-#define TXX9_SIFCR_RDIL_MAX    0x00000180
-#define TXX9_SIFCR_TDIL_MASK   0x00000018
-#define TXX9_SIFCR_TDIL_MASK   0x00000018
-#define TXX9_SIFCR_TDIL_1      0x00000000
-#define TXX9_SIFCR_TDIL_4      0x00000001
-#define TXX9_SIFCR_TDIL_8      0x00000010
-#define TXX9_SIFCR_TDIL_MAX    0x00000010
-#define TXX9_SIFCR_TFRST       0x00000004
-#define TXX9_SIFCR_RFRST       0x00000002
-#define TXX9_SIFCR_FRSTE       0x00000001
-#define TXX9_SIO_TX_FIFO       8
-#define TXX9_SIO_RX_FIFO       16
-
-/* SIFLCR : Flow Control */
-#define TXX9_SIFLCR_RCS        0x00001000
-#define TXX9_SIFLCR_TES        0x00000800
-#define TXX9_SIFLCR_RTSSC      0x00000200
-#define TXX9_SIFLCR_RSDE       0x00000100
-#define TXX9_SIFLCR_TSDE       0x00000080
-#define TXX9_SIFLCR_RTSTL_MASK 0x0000001e
-#define TXX9_SIFLCR_RTSTL_MAX  0x0000001e
-#define TXX9_SIFLCR_TBRK       0x00000001
-
-/* SIBGR : Baudrate Control */
-#define TXX9_SIBGR_BCLK_MASK   0x00000300
-#define TXX9_SIBGR_BCLK_T0     0x00000000
-#define TXX9_SIBGR_BCLK_T2     0x00000100
-#define TXX9_SIBGR_BCLK_T4     0x00000200
-#define TXX9_SIBGR_BCLK_T6     0x00000300
-#define TXX9_SIBGR_BRD_MASK    0x000000ff
-
-static inline unsigned int sio_in(struct uart_txx9_port *up, int offset)
-{
-       switch (up->port.iotype) {
-       default:
-               return __raw_readl(up->port.membase + offset);
-       case UPIO_PORT:
-               return inl(up->port.iobase + offset);
-       }
-}
-
-static inline void
-sio_out(struct uart_txx9_port *up, int offset, int value)
-{
-       switch (up->port.iotype) {
-       default:
-               __raw_writel(value, up->port.membase + offset);
-               break;
-       case UPIO_PORT:
-               outl(value, up->port.iobase + offset);
-               break;
-       }
-}
-
-static inline void
-sio_mask(struct uart_txx9_port *up, int offset, unsigned int value)
-{
-       sio_out(up, offset, sio_in(up, offset) & ~value);
-}
-static inline void
-sio_set(struct uart_txx9_port *up, int offset, unsigned int value)
-{
-       sio_out(up, offset, sio_in(up, offset) | value);
-}
-
-static inline void
-sio_quot_set(struct uart_txx9_port *up, int quot)
-{
-       quot >>= 1;
-       if (quot < 256)
-               sio_out(up, TXX9_SIBGR, quot | TXX9_SIBGR_BCLK_T0);
-       else if (quot < (256 << 2))
-               sio_out(up, TXX9_SIBGR, (quot >> 2) | TXX9_SIBGR_BCLK_T2);
-       else if (quot < (256 << 4))
-               sio_out(up, TXX9_SIBGR, (quot >> 4) | TXX9_SIBGR_BCLK_T4);
-       else if (quot < (256 << 6))
-               sio_out(up, TXX9_SIBGR, (quot >> 6) | TXX9_SIBGR_BCLK_T6);
-       else
-               sio_out(up, TXX9_SIBGR, 0xff | TXX9_SIBGR_BCLK_T6);
-}
-
-static struct uart_txx9_port *to_uart_txx9_port(struct uart_port *port)
-{
-       return container_of(port, struct uart_txx9_port, port);
-}
-
-static void serial_txx9_stop_tx(struct uart_port *port)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-       sio_mask(up, TXX9_SIDICR, TXX9_SIDICR_TIE);
-}
-
-static void serial_txx9_start_tx(struct uart_port *port)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-       sio_set(up, TXX9_SIDICR, TXX9_SIDICR_TIE);
-}
-
-static void serial_txx9_stop_rx(struct uart_port *port)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-       up->port.read_status_mask &= ~TXX9_SIDISR_RDIS;
-}
-
-static void serial_txx9_enable_ms(struct uart_port *port)
-{
-       /* TXX9-SIO can not control DTR... */
-}
-
-static void serial_txx9_initialize(struct uart_port *port)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-       unsigned int tmout = 10000;
-
-       sio_out(up, TXX9_SIFCR, TXX9_SIFCR_SWRST);
-       /* TX4925 BUG WORKAROUND.  Accessing SIOC register
-        * immediately after soft reset causes bus error. */
-       mmiowb();
-       udelay(1);
-       while ((sio_in(up, TXX9_SIFCR) & TXX9_SIFCR_SWRST) && --tmout)
-               udelay(1);
-       /* TX Int by FIFO Empty, RX Int by Receiving 1 char. */
-       sio_set(up, TXX9_SIFCR,
-               TXX9_SIFCR_TDIL_MAX | TXX9_SIFCR_RDIL_1);
-       /* initial settings */
-       sio_out(up, TXX9_SILCR,
-               TXX9_SILCR_UMODE_8BIT | TXX9_SILCR_USBL_1BIT |
-               ((up->port.flags & UPF_TXX9_USE_SCLK) ?
-                TXX9_SILCR_SCS_SCLK_BG : TXX9_SILCR_SCS_IMCLK_BG));
-       sio_quot_set(up, uart_get_divisor(port, 9600));
-       sio_out(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSTL_MAX /* 15 */);
-       sio_out(up, TXX9_SIDICR, 0);
-}
-
-static inline void
-receive_chars(struct uart_txx9_port *up, unsigned int *status)
-{
-       struct tty_struct *tty = up->port.state->port.tty;
-       unsigned char ch;
-       unsigned int disr = *status;
-       int max_count = 256;
-       char flag;
-       unsigned int next_ignore_status_mask;
-
-       do {
-               ch = sio_in(up, TXX9_SIRFIFO);
-               flag = TTY_NORMAL;
-               up->port.icount.rx++;
-
-               /* mask out RFDN_MASK bit added by previous overrun */
-               next_ignore_status_mask =
-                       up->port.ignore_status_mask & ~TXX9_SIDISR_RFDN_MASK;
-               if (unlikely(disr & (TXX9_SIDISR_UBRK | TXX9_SIDISR_UPER |
-                                    TXX9_SIDISR_UFER | TXX9_SIDISR_UOER))) {
-                       /*
-                        * For statistics only
-                        */
-                       if (disr & TXX9_SIDISR_UBRK) {
-                               disr &= ~(TXX9_SIDISR_UFER | TXX9_SIDISR_UPER);
-                               up->port.icount.brk++;
-                               /*
-                                * We do the SysRQ and SAK checking
-                                * here because otherwise the break
-                                * may get masked by ignore_status_mask
-                                * or read_status_mask.
-                                */
-                               if (uart_handle_break(&up->port))
-                                       goto ignore_char;
-                       } else if (disr & TXX9_SIDISR_UPER)
-                               up->port.icount.parity++;
-                       else if (disr & TXX9_SIDISR_UFER)
-                               up->port.icount.frame++;
-                       if (disr & TXX9_SIDISR_UOER) {
-                               up->port.icount.overrun++;
-                               /*
-                                * The receiver read buffer still hold
-                                * a char which caused overrun.
-                                * Ignore next char by adding RFDN_MASK
-                                * to ignore_status_mask temporarily.
-                                */
-                               next_ignore_status_mask |=
-                                       TXX9_SIDISR_RFDN_MASK;
-                       }
-
-                       /*
-                        * Mask off conditions which should be ingored.
-                        */
-                       disr &= up->port.read_status_mask;
-
-                       if (disr & TXX9_SIDISR_UBRK) {
-                               flag = TTY_BREAK;
-                       } else if (disr & TXX9_SIDISR_UPER)
-                               flag = TTY_PARITY;
-                       else if (disr & TXX9_SIDISR_UFER)
-                               flag = TTY_FRAME;
-               }
-               if (uart_handle_sysrq_char(&up->port, ch))
-                       goto ignore_char;
-
-               uart_insert_char(&up->port, disr, TXX9_SIDISR_UOER, ch, flag);
-
-       ignore_char:
-               up->port.ignore_status_mask = next_ignore_status_mask;
-               disr = sio_in(up, TXX9_SIDISR);
-       } while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0));
-       spin_unlock(&up->port.lock);
-       tty_flip_buffer_push(tty);
-       spin_lock(&up->port.lock);
-       *status = disr;
-}
-
-static inline void transmit_chars(struct uart_txx9_port *up)
-{
-       struct circ_buf *xmit = &up->port.state->xmit;
-       int count;
-
-       if (up->port.x_char) {
-               sio_out(up, TXX9_SITFIFO, up->port.x_char);
-               up->port.icount.tx++;
-               up->port.x_char = 0;
-               return;
-       }
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
-               serial_txx9_stop_tx(&up->port);
-               return;
-       }
-
-       count = TXX9_SIO_TX_FIFO;
-       do {
-               sio_out(up, TXX9_SITFIFO, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               up->port.icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (--count > 0);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&up->port);
-
-       if (uart_circ_empty(xmit))
-               serial_txx9_stop_tx(&up->port);
-}
-
-static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id)
-{
-       int pass_counter = 0;
-       struct uart_txx9_port *up = dev_id;
-       unsigned int status;
-
-       while (1) {
-               spin_lock(&up->port.lock);
-               status = sio_in(up, TXX9_SIDISR);
-               if (!(sio_in(up, TXX9_SIDICR) & TXX9_SIDICR_TIE))
-                       status &= ~TXX9_SIDISR_TDIS;
-               if (!(status & (TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS |
-                               TXX9_SIDISR_TOUT))) {
-                       spin_unlock(&up->port.lock);
-                       break;
-               }
-
-               if (status & TXX9_SIDISR_RDIS)
-                       receive_chars(up, &status);
-               if (status & TXX9_SIDISR_TDIS)
-                       transmit_chars(up);
-               /* Clear TX/RX Int. Status */
-               sio_mask(up, TXX9_SIDISR,
-                        TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS |
-                        TXX9_SIDISR_TOUT);
-               spin_unlock(&up->port.lock);
-
-               if (pass_counter++ > PASS_LIMIT)
-                       break;
-       }
-
-       return pass_counter ? IRQ_HANDLED : IRQ_NONE;
-}
-
-static unsigned int serial_txx9_tx_empty(struct uart_port *port)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-       unsigned long flags;
-       unsigned int ret;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       ret = (sio_in(up, TXX9_SICISR) & TXX9_SICISR_TXALS) ? TIOCSER_TEMT : 0;
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       return ret;
-}
-
-static unsigned int serial_txx9_get_mctrl(struct uart_port *port)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-       unsigned int ret;
-
-       /* no modem control lines */
-       ret = TIOCM_CAR | TIOCM_DSR;
-       ret |= (sio_in(up, TXX9_SIFLCR) & TXX9_SIFLCR_RTSSC) ? 0 : TIOCM_RTS;
-       ret |= (sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS) ? 0 : TIOCM_CTS;
-
-       return ret;
-}
-
-static void serial_txx9_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-
-       if (mctrl & TIOCM_RTS)
-               sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC);
-       else
-               sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC);
-}
-
-static void serial_txx9_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-       unsigned long flags;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       if (break_state == -1)
-               sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK);
-       else
-               sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-#if defined(CONFIG_SERIAL_TXX9_CONSOLE) || (CONFIG_CONSOLE_POLL)
-/*
- *     Wait for transmitter & holding register to empty
- */
-static void wait_for_xmitr(struct uart_txx9_port *up)
-{
-       unsigned int tmout = 10000;
-
-       /* Wait up to 10ms for the character(s) to be sent. */
-       while (--tmout &&
-              !(sio_in(up, TXX9_SICISR) & TXX9_SICISR_TXALS))
-               udelay(1);
-
-       /* Wait up to 1s for flow control if necessary */
-       if (up->port.flags & UPF_CONS_FLOW) {
-               tmout = 1000000;
-               while (--tmout &&
-                      (sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS))
-                       udelay(1);
-       }
-}
-#endif
-
-#ifdef CONFIG_CONSOLE_POLL
-/*
- * Console polling routines for writing and reading from the uart while
- * in an interrupt or debug context.
- */
-
-static int serial_txx9_get_poll_char(struct uart_port *port)
-{
-       unsigned int ier;
-       unsigned char c;
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-
-       /*
-        *      First save the IER then disable the interrupts
-        */
-       ier = sio_in(up, TXX9_SIDICR);
-       sio_out(up, TXX9_SIDICR, 0);
-
-       while (sio_in(up, TXX9_SIDISR) & TXX9_SIDISR_UVALID)
-               ;
-
-       c = sio_in(up, TXX9_SIRFIFO);
-
-       /*
-        *      Finally, clear RX interrupt status
-        *      and restore the IER
-        */
-       sio_mask(up, TXX9_SIDISR, TXX9_SIDISR_RDIS);
-       sio_out(up, TXX9_SIDICR, ier);
-       return c;
-}
-
-
-static void serial_txx9_put_poll_char(struct uart_port *port, unsigned char c)
-{
-       unsigned int ier;
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-
-       /*
-        *      First save the IER then disable the interrupts
-        */
-       ier = sio_in(up, TXX9_SIDICR);
-       sio_out(up, TXX9_SIDICR, 0);
-
-       wait_for_xmitr(up);
-       /*
-        *      Send the character out.
-        *      If a LF, also do CR...
-        */
-       sio_out(up, TXX9_SITFIFO, c);
-       if (c == 10) {
-               wait_for_xmitr(up);
-               sio_out(up, TXX9_SITFIFO, 13);
-       }
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore the IER
-        */
-       wait_for_xmitr(up);
-       sio_out(up, TXX9_SIDICR, ier);
-}
-
-#endif /* CONFIG_CONSOLE_POLL */
-
-static int serial_txx9_startup(struct uart_port *port)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-       unsigned long flags;
-       int retval;
-
-       /*
-        * Clear the FIFO buffers and disable them.
-        * (they will be reenabled in set_termios())
-        */
-       sio_set(up, TXX9_SIFCR,
-               TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE);
-       /* clear reset */
-       sio_mask(up, TXX9_SIFCR,
-                TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE);
-       sio_out(up, TXX9_SIDICR, 0);
-
-       /*
-        * Clear the interrupt registers.
-        */
-       sio_out(up, TXX9_SIDISR, 0);
-
-       retval = request_irq(up->port.irq, serial_txx9_interrupt,
-                            IRQF_SHARED, "serial_txx9", up);
-       if (retval)
-               return retval;
-
-       /*
-        * Now, initialize the UART
-        */
-       spin_lock_irqsave(&up->port.lock, flags);
-       serial_txx9_set_mctrl(&up->port, up->port.mctrl);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       /* Enable RX/TX */
-       sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RSDE | TXX9_SIFLCR_TSDE);
-
-       /*
-        * Finally, enable interrupts.
-        */
-       sio_set(up, TXX9_SIDICR, TXX9_SIDICR_RIE);
-
-       return 0;
-}
-
-static void serial_txx9_shutdown(struct uart_port *port)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-       unsigned long flags;
-
-       /*
-        * Disable interrupts from this port
-        */
-       sio_out(up, TXX9_SIDICR, 0);    /* disable all intrs */
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       serial_txx9_set_mctrl(&up->port, up->port.mctrl);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       /*
-        * Disable break condition
-        */
-       sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK);
-
-#ifdef CONFIG_SERIAL_TXX9_CONSOLE
-       if (up->port.cons && up->port.line == up->port.cons->index) {
-               free_irq(up->port.irq, up);
-               return;
-       }
-#endif
-       /* reset FIFOs */
-       sio_set(up, TXX9_SIFCR,
-               TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE);
-       /* clear reset */
-       sio_mask(up, TXX9_SIFCR,
-                TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE);
-
-       /* Disable RX/TX */
-       sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RSDE | TXX9_SIFLCR_TSDE);
-
-       free_irq(up->port.irq, up);
-}
-
-static void
-serial_txx9_set_termios(struct uart_port *port, struct ktermios *termios,
-                      struct ktermios *old)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-       unsigned int cval, fcr = 0;
-       unsigned long flags;
-       unsigned int baud, quot;
-
-       /*
-        * We don't support modem control lines.
-        */
-       termios->c_cflag &= ~(HUPCL | CMSPAR);
-       termios->c_cflag |= CLOCAL;
-
-       cval = sio_in(up, TXX9_SILCR);
-       /* byte size and parity */
-       cval &= ~TXX9_SILCR_UMODE_MASK;
-       switch (termios->c_cflag & CSIZE) {
-       case CS7:
-               cval |= TXX9_SILCR_UMODE_7BIT;
-               break;
-       default:
-       case CS5:       /* not supported */
-       case CS6:       /* not supported */
-       case CS8:
-               cval |= TXX9_SILCR_UMODE_8BIT;
-               break;
-       }
-
-       cval &= ~TXX9_SILCR_USBL_MASK;
-       if (termios->c_cflag & CSTOPB)
-               cval |= TXX9_SILCR_USBL_2BIT;
-       else
-               cval |= TXX9_SILCR_USBL_1BIT;
-       cval &= ~(TXX9_SILCR_UPEN | TXX9_SILCR_UEPS);
-       if (termios->c_cflag & PARENB)
-               cval |= TXX9_SILCR_UPEN;
-       if (!(termios->c_cflag & PARODD))
-               cval |= TXX9_SILCR_UEPS;
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16/2);
-       quot = uart_get_divisor(port, baud);
-
-       /* Set up FIFOs */
-       /* TX Int by FIFO Empty, RX Int by Receiving 1 char. */
-       fcr = TXX9_SIFCR_TDIL_MAX | TXX9_SIFCR_RDIL_1;
-
-       /*
-        * Ok, we're now changing the port state.  Do it with
-        * interrupts disabled.
-        */
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       up->port.read_status_mask = TXX9_SIDISR_UOER |
-               TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS;
-       if (termios->c_iflag & INPCK)
-               up->port.read_status_mask |= TXX9_SIDISR_UFER | TXX9_SIDISR_UPER;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               up->port.read_status_mask |= TXX9_SIDISR_UBRK;
-
-       /*
-        * Characteres to ignore
-        */
-       up->port.ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               up->port.ignore_status_mask |= TXX9_SIDISR_UPER | TXX9_SIDISR_UFER;
-       if (termios->c_iflag & IGNBRK) {
-               up->port.ignore_status_mask |= TXX9_SIDISR_UBRK;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       up->port.ignore_status_mask |= TXX9_SIDISR_UOER;
-       }
-
-       /*
-        * ignore all characters if CREAD is not set
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               up->port.ignore_status_mask |= TXX9_SIDISR_RDIS;
-
-       /* CTS flow control flag */
-       if ((termios->c_cflag & CRTSCTS) &&
-           (up->port.flags & UPF_TXX9_HAVE_CTS_LINE)) {
-               sio_set(up, TXX9_SIFLCR,
-                       TXX9_SIFLCR_RCS | TXX9_SIFLCR_TES);
-       } else {
-               sio_mask(up, TXX9_SIFLCR,
-                        TXX9_SIFLCR_RCS | TXX9_SIFLCR_TES);
-       }
-
-       sio_out(up, TXX9_SILCR, cval);
-       sio_quot_set(up, quot);
-       sio_out(up, TXX9_SIFCR, fcr);
-
-       serial_txx9_set_mctrl(&up->port, up->port.mctrl);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static void
-serial_txx9_pm(struct uart_port *port, unsigned int state,
-             unsigned int oldstate)
-{
-       /*
-        * If oldstate was -1 this is called from
-        * uart_configure_port().  In this case do not initialize the
-        * port now, because the port was already initialized (for
-        * non-console port) or should not be initialized here (for
-        * console port).  If we initialized the port here we lose
-        * serial console settings.
-        */
-       if (state == 0 && oldstate != -1)
-               serial_txx9_initialize(port);
-}
-
-static int serial_txx9_request_resource(struct uart_txx9_port *up)
-{
-       unsigned int size = TXX9_REGION_SIZE;
-       int ret = 0;
-
-       switch (up->port.iotype) {
-       default:
-               if (!up->port.mapbase)
-                       break;
-
-               if (!request_mem_region(up->port.mapbase, size, "serial_txx9")) {
-                       ret = -EBUSY;
-                       break;
-               }
-
-               if (up->port.flags & UPF_IOREMAP) {
-                       up->port.membase = ioremap(up->port.mapbase, size);
-                       if (!up->port.membase) {
-                               release_mem_region(up->port.mapbase, size);
-                               ret = -ENOMEM;
-                       }
-               }
-               break;
-
-       case UPIO_PORT:
-               if (!request_region(up->port.iobase, size, "serial_txx9"))
-                       ret = -EBUSY;
-               break;
-       }
-       return ret;
-}
-
-static void serial_txx9_release_resource(struct uart_txx9_port *up)
-{
-       unsigned int size = TXX9_REGION_SIZE;
-
-       switch (up->port.iotype) {
-       default:
-               if (!up->port.mapbase)
-                       break;
-
-               if (up->port.flags & UPF_IOREMAP) {
-                       iounmap(up->port.membase);
-                       up->port.membase = NULL;
-               }
-
-               release_mem_region(up->port.mapbase, size);
-               break;
-
-       case UPIO_PORT:
-               release_region(up->port.iobase, size);
-               break;
-       }
-}
-
-static void serial_txx9_release_port(struct uart_port *port)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-       serial_txx9_release_resource(up);
-}
-
-static int serial_txx9_request_port(struct uart_port *port)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-       return serial_txx9_request_resource(up);
-}
-
-static void serial_txx9_config_port(struct uart_port *port, int uflags)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-       int ret;
-
-       /*
-        * Find the region that we can probe for.  This in turn
-        * tells us whether we can probe for the type of port.
-        */
-       ret = serial_txx9_request_resource(up);
-       if (ret < 0)
-               return;
-       port->type = PORT_TXX9;
-       up->port.fifosize = TXX9_SIO_TX_FIFO;
-
-#ifdef CONFIG_SERIAL_TXX9_CONSOLE
-       if (up->port.line == up->port.cons->index)
-               return;
-#endif
-       serial_txx9_initialize(port);
-}
-
-static const char *
-serial_txx9_type(struct uart_port *port)
-{
-       return "txx9";
-}
-
-static struct uart_ops serial_txx9_pops = {
-       .tx_empty       = serial_txx9_tx_empty,
-       .set_mctrl      = serial_txx9_set_mctrl,
-       .get_mctrl      = serial_txx9_get_mctrl,
-       .stop_tx        = serial_txx9_stop_tx,
-       .start_tx       = serial_txx9_start_tx,
-       .stop_rx        = serial_txx9_stop_rx,
-       .enable_ms      = serial_txx9_enable_ms,
-       .break_ctl      = serial_txx9_break_ctl,
-       .startup        = serial_txx9_startup,
-       .shutdown       = serial_txx9_shutdown,
-       .set_termios    = serial_txx9_set_termios,
-       .pm             = serial_txx9_pm,
-       .type           = serial_txx9_type,
-       .release_port   = serial_txx9_release_port,
-       .request_port   = serial_txx9_request_port,
-       .config_port    = serial_txx9_config_port,
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_get_char  = serial_txx9_get_poll_char,
-       .poll_put_char  = serial_txx9_put_poll_char,
-#endif
-};
-
-static struct uart_txx9_port serial_txx9_ports[UART_NR];
-
-static void __init serial_txx9_register_ports(struct uart_driver *drv,
-                                             struct device *dev)
-{
-       int i;
-
-       for (i = 0; i < UART_NR; i++) {
-               struct uart_txx9_port *up = &serial_txx9_ports[i];
-
-               up->port.line = i;
-               up->port.ops = &serial_txx9_pops;
-               up->port.dev = dev;
-               if (up->port.iobase || up->port.mapbase)
-                       uart_add_one_port(drv, &up->port);
-       }
-}
-
-#ifdef CONFIG_SERIAL_TXX9_CONSOLE
-
-static void serial_txx9_console_putchar(struct uart_port *port, int ch)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-
-       wait_for_xmitr(up);
-       sio_out(up, TXX9_SITFIFO, ch);
-}
-
-/*
- *     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.
- */
-static void
-serial_txx9_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct uart_txx9_port *up = &serial_txx9_ports[co->index];
-       unsigned int ier, flcr;
-
-       /*
-        *      First save the UER then disable the interrupts
-        */
-       ier = sio_in(up, TXX9_SIDICR);
-       sio_out(up, TXX9_SIDICR, 0);
-       /*
-        *      Disable flow-control if enabled (and unnecessary)
-        */
-       flcr = sio_in(up, TXX9_SIFLCR);
-       if (!(up->port.flags & UPF_CONS_FLOW) && (flcr & TXX9_SIFLCR_TES))
-               sio_out(up, TXX9_SIFLCR, flcr & ~TXX9_SIFLCR_TES);
-
-       uart_console_write(&up->port, s, count, serial_txx9_console_putchar);
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore the IER
-        */
-       wait_for_xmitr(up);
-       sio_out(up, TXX9_SIFLCR, flcr);
-       sio_out(up, TXX9_SIDICR, ier);
-}
-
-static int __init serial_txx9_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port;
-       struct uart_txx9_port *up;
-       int baud = 9600;
-       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.
-        */
-       if (co->index >= UART_NR)
-               co->index = 0;
-       up = &serial_txx9_ports[co->index];
-       port = &up->port;
-       if (!port->ops)
-               return -ENODEV;
-
-       serial_txx9_initialize(&up->port);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver serial_txx9_reg;
-static struct console serial_txx9_console = {
-       .name           = TXX9_TTY_NAME,
-       .write          = serial_txx9_console_write,
-       .device         = uart_console_device,
-       .setup          = serial_txx9_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &serial_txx9_reg,
-};
-
-static int __init serial_txx9_console_init(void)
-{
-       register_console(&serial_txx9_console);
-       return 0;
-}
-console_initcall(serial_txx9_console_init);
-
-#define SERIAL_TXX9_CONSOLE    &serial_txx9_console
-#else
-#define SERIAL_TXX9_CONSOLE    NULL
-#endif
-
-static struct uart_driver serial_txx9_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "serial_txx9",
-       .dev_name               = TXX9_TTY_NAME,
-       .major                  = TXX9_TTY_MAJOR,
-       .minor                  = TXX9_TTY_MINOR_START,
-       .nr                     = UART_NR,
-       .cons                   = SERIAL_TXX9_CONSOLE,
-};
-
-int __init early_serial_txx9_setup(struct uart_port *port)
-{
-       if (port->line >= ARRAY_SIZE(serial_txx9_ports))
-               return -ENODEV;
-
-       serial_txx9_ports[port->line].port = *port;
-       serial_txx9_ports[port->line].port.ops = &serial_txx9_pops;
-       serial_txx9_ports[port->line].port.flags |=
-               UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
-       return 0;
-}
-
-static DEFINE_MUTEX(serial_txx9_mutex);
-
-/**
- *     serial_txx9_register_port - register a serial port
- *     @port: serial port template
- *
- *     Configure the serial port specified by the request.
- *
- *     The port is then probed and if necessary the IRQ is autodetected
- *     If this fails an error is returned.
- *
- *     On success the port is ready to use and the line number is returned.
- */
-static int __devinit serial_txx9_register_port(struct uart_port *port)
-{
-       int i;
-       struct uart_txx9_port *uart;
-       int ret = -ENOSPC;
-
-       mutex_lock(&serial_txx9_mutex);
-       for (i = 0; i < UART_NR; i++) {
-               uart = &serial_txx9_ports[i];
-               if (uart_match_port(&uart->port, port)) {
-                       uart_remove_one_port(&serial_txx9_reg, &uart->port);
-                       break;
-               }
-       }
-       if (i == UART_NR) {
-               /* Find unused port */
-               for (i = 0; i < UART_NR; i++) {
-                       uart = &serial_txx9_ports[i];
-                       if (!(uart->port.iobase || uart->port.mapbase))
-                               break;
-               }
-       }
-       if (i < UART_NR) {
-               uart->port.iobase = port->iobase;
-               uart->port.membase = port->membase;
-               uart->port.irq      = port->irq;
-               uart->port.uartclk  = port->uartclk;
-               uart->port.iotype   = port->iotype;
-               uart->port.flags    = port->flags
-                       | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
-               uart->port.mapbase  = port->mapbase;
-               if (port->dev)
-                       uart->port.dev = port->dev;
-               ret = uart_add_one_port(&serial_txx9_reg, &uart->port);
-               if (ret == 0)
-                       ret = uart->port.line;
-       }
-       mutex_unlock(&serial_txx9_mutex);
-       return ret;
-}
-
-/**
- *     serial_txx9_unregister_port - remove a txx9 serial port at runtime
- *     @line: serial line number
- *
- *     Remove one serial port.  This may not be called from interrupt
- *     context.  We hand the port back to the our control.
- */
-static void __devexit serial_txx9_unregister_port(int line)
-{
-       struct uart_txx9_port *uart = &serial_txx9_ports[line];
-
-       mutex_lock(&serial_txx9_mutex);
-       uart_remove_one_port(&serial_txx9_reg, &uart->port);
-       uart->port.flags = 0;
-       uart->port.type = PORT_UNKNOWN;
-       uart->port.iobase = 0;
-       uart->port.mapbase = 0;
-       uart->port.membase = NULL;
-       uart->port.dev = NULL;
-       mutex_unlock(&serial_txx9_mutex);
-}
-
-/*
- * Register a set of serial devices attached to a platform device.
- */
-static int __devinit serial_txx9_probe(struct platform_device *dev)
-{
-       struct uart_port *p = dev->dev.platform_data;
-       struct uart_port port;
-       int ret, i;
-
-       memset(&port, 0, sizeof(struct uart_port));
-       for (i = 0; p && p->uartclk != 0; p++, i++) {
-               port.iobase     = p->iobase;
-               port.membase    = p->membase;
-               port.irq        = p->irq;
-               port.uartclk    = p->uartclk;
-               port.iotype     = p->iotype;
-               port.flags      = p->flags;
-               port.mapbase    = p->mapbase;
-               port.dev        = &dev->dev;
-               ret = serial_txx9_register_port(&port);
-               if (ret < 0) {
-                       dev_err(&dev->dev, "unable to register port at index %d "
-                               "(IO%lx MEM%llx IRQ%d): %d\n", i,
-                               p->iobase, (unsigned long long)p->mapbase,
-                               p->irq, ret);
-               }
-       }
-       return 0;
-}
-
-/*
- * Remove serial ports registered against a platform device.
- */
-static int __devexit serial_txx9_remove(struct platform_device *dev)
-{
-       int i;
-
-       for (i = 0; i < UART_NR; i++) {
-               struct uart_txx9_port *up = &serial_txx9_ports[i];
-
-               if (up->port.dev == &dev->dev)
-                       serial_txx9_unregister_port(i);
-       }
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int serial_txx9_suspend(struct platform_device *dev, pm_message_t state)
-{
-       int i;
-
-       for (i = 0; i < UART_NR; i++) {
-               struct uart_txx9_port *up = &serial_txx9_ports[i];
-
-               if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
-                       uart_suspend_port(&serial_txx9_reg, &up->port);
-       }
-
-       return 0;
-}
-
-static int serial_txx9_resume(struct platform_device *dev)
-{
-       int i;
-
-       for (i = 0; i < UART_NR; i++) {
-               struct uart_txx9_port *up = &serial_txx9_ports[i];
-
-               if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
-                       uart_resume_port(&serial_txx9_reg, &up->port);
-       }
-
-       return 0;
-}
-#endif
-
-static struct platform_driver serial_txx9_plat_driver = {
-       .probe          = serial_txx9_probe,
-       .remove         = __devexit_p(serial_txx9_remove),
-#ifdef CONFIG_PM
-       .suspend        = serial_txx9_suspend,
-       .resume         = serial_txx9_resume,
-#endif
-       .driver         = {
-               .name   = "serial_txx9",
-               .owner  = THIS_MODULE,
-       },
-};
-
-#ifdef ENABLE_SERIAL_TXX9_PCI
-/*
- * Probe one serial board.  Unfortunately, there is no rhyme nor reason
- * to the arrangement of serial ports on a PCI card.
- */
-static int __devinit
-pciserial_txx9_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
-{
-       struct uart_port port;
-       int line;
-       int rc;
-
-       rc = pci_enable_device(dev);
-       if (rc)
-               return rc;
-
-       memset(&port, 0, sizeof(port));
-       port.ops = &serial_txx9_pops;
-       port.flags |= UPF_TXX9_HAVE_CTS_LINE;
-       port.uartclk = 66670000;
-       port.irq = dev->irq;
-       port.iotype = UPIO_PORT;
-       port.iobase = pci_resource_start(dev, 1);
-       port.dev = &dev->dev;
-       line = serial_txx9_register_port(&port);
-       if (line < 0) {
-               printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), line);
-               pci_disable_device(dev);
-               return line;
-       }
-       pci_set_drvdata(dev, &serial_txx9_ports[line]);
-
-       return 0;
-}
-
-static void __devexit pciserial_txx9_remove_one(struct pci_dev *dev)
-{
-       struct uart_txx9_port *up = pci_get_drvdata(dev);
-
-       pci_set_drvdata(dev, NULL);
-
-       if (up) {
-               serial_txx9_unregister_port(up->port.line);
-               pci_disable_device(dev);
-       }
-}
-
-#ifdef CONFIG_PM
-static int pciserial_txx9_suspend_one(struct pci_dev *dev, pm_message_t state)
-{
-       struct uart_txx9_port *up = pci_get_drvdata(dev);
-
-       if (up)
-               uart_suspend_port(&serial_txx9_reg, &up->port);
-       pci_save_state(dev);
-       pci_set_power_state(dev, pci_choose_state(dev, state));
-       return 0;
-}
-
-static int pciserial_txx9_resume_one(struct pci_dev *dev)
-{
-       struct uart_txx9_port *up = pci_get_drvdata(dev);
-
-       pci_set_power_state(dev, PCI_D0);
-       pci_restore_state(dev);
-       if (up)
-               uart_resume_port(&serial_txx9_reg, &up->port);
-       return 0;
-}
-#endif
-
-static const struct pci_device_id serial_txx9_pci_tbl[] = {
-       { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC) },
-       { 0, }
-};
-
-static struct pci_driver serial_txx9_pci_driver = {
-       .name           = "serial_txx9",
-       .probe          = pciserial_txx9_init_one,
-       .remove         = __devexit_p(pciserial_txx9_remove_one),
-#ifdef CONFIG_PM
-       .suspend        = pciserial_txx9_suspend_one,
-       .resume         = pciserial_txx9_resume_one,
-#endif
-       .id_table       = serial_txx9_pci_tbl,
-};
-
-MODULE_DEVICE_TABLE(pci, serial_txx9_pci_tbl);
-#endif /* ENABLE_SERIAL_TXX9_PCI */
-
-static struct platform_device *serial_txx9_plat_devs;
-
-static int __init serial_txx9_init(void)
-{
-       int ret;
-
-       printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
-
-       ret = uart_register_driver(&serial_txx9_reg);
-       if (ret)
-               goto out;
-
-       serial_txx9_plat_devs = platform_device_alloc("serial_txx9", -1);
-       if (!serial_txx9_plat_devs) {
-               ret = -ENOMEM;
-               goto unreg_uart_drv;
-       }
-
-       ret = platform_device_add(serial_txx9_plat_devs);
-       if (ret)
-               goto put_dev;
-
-       serial_txx9_register_ports(&serial_txx9_reg,
-                                  &serial_txx9_plat_devs->dev);
-
-       ret = platform_driver_register(&serial_txx9_plat_driver);
-       if (ret)
-               goto del_dev;
-
-#ifdef ENABLE_SERIAL_TXX9_PCI
-       ret = pci_register_driver(&serial_txx9_pci_driver);
-#endif
-       if (ret == 0)
-               goto out;
-
- del_dev:
-       platform_device_del(serial_txx9_plat_devs);
- put_dev:
-       platform_device_put(serial_txx9_plat_devs);
- unreg_uart_drv:
-       uart_unregister_driver(&serial_txx9_reg);
- out:
-       return ret;
-}
-
-static void __exit serial_txx9_exit(void)
-{
-       int i;
-
-#ifdef ENABLE_SERIAL_TXX9_PCI
-       pci_unregister_driver(&serial_txx9_pci_driver);
-#endif
-       platform_driver_unregister(&serial_txx9_plat_driver);
-       platform_device_unregister(serial_txx9_plat_devs);
-       for (i = 0; i < UART_NR; i++) {
-               struct uart_txx9_port *up = &serial_txx9_ports[i];
-               if (up->port.iobase || up->port.mapbase)
-                       uart_remove_one_port(&serial_txx9_reg, &up->port);
-       }
-
-       uart_unregister_driver(&serial_txx9_reg);
-}
-
-module_init(serial_txx9_init);
-module_exit(serial_txx9_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("TX39/49 serial driver");
-
-MODULE_ALIAS_CHARDEV_MAJOR(TXX9_TTY_MAJOR);
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
deleted file mode 100644 (file)
index c291b3a..0000000
+++ /dev/null
@@ -1,2027 +0,0 @@
-/*
- * drivers/serial/sh-sci.c
- *
- * SuperH on-chip serial module support.  (SCI with no FIFO / with FIFO)
- *
- *  Copyright (C) 2002 - 2008  Paul Mundt
- *  Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Jul 2007).
- *
- * based off of the old drivers/char/sh-sci.c by:
- *
- *   Copyright (C) 1999, 2000  Niibe Yutaka
- *   Copyright (C) 2000  Sugioka Toshinobu
- *   Modified to support multiple serial ports. Stuart Menefy (May 2000).
- *   Modified to support SecureEdge. David McCullough (2002)
- *   Modified to support SH7300 SCIF. Takashi Kusuda (Jun 2003).
- *   Removed SH7300 support (Jul 2007).
- *
- * 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.
- */
-#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#undef DEBUG
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/sysrq.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/console.h>
-#include <linux/platform_device.h>
-#include <linux/serial_sci.h>
-#include <linux/notifier.h>
-#include <linux/cpufreq.h>
-#include <linux/clk.h>
-#include <linux/ctype.h>
-#include <linux/err.h>
-#include <linux/list.h>
-#include <linux/dmaengine.h>
-#include <linux/scatterlist.h>
-#include <linux/slab.h>
-
-#ifdef CONFIG_SUPERH
-#include <asm/sh_bios.h>
-#endif
-
-#ifdef CONFIG_H8300
-#include <asm/gpio.h>
-#endif
-
-#include "sh-sci.h"
-
-struct sci_port {
-       struct uart_port        port;
-
-       /* Port type */
-       unsigned int            type;
-
-       /* Port IRQs: ERI, RXI, TXI, BRI (optional) */
-       unsigned int            irqs[SCIx_NR_IRQS];
-
-       /* Port enable callback */
-       void                    (*enable)(struct uart_port *port);
-
-       /* Port disable callback */
-       void                    (*disable)(struct uart_port *port);
-
-       /* Break timer */
-       struct timer_list       break_timer;
-       int                     break_flag;
-
-       /* Interface clock */
-       struct clk              *iclk;
-       /* Function clock */
-       struct clk              *fclk;
-
-       struct list_head        node;
-       struct dma_chan                 *chan_tx;
-       struct dma_chan                 *chan_rx;
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
-       struct device                   *dma_dev;
-       unsigned int                    slave_tx;
-       unsigned int                    slave_rx;
-       struct dma_async_tx_descriptor  *desc_tx;
-       struct dma_async_tx_descriptor  *desc_rx[2];
-       dma_cookie_t                    cookie_tx;
-       dma_cookie_t                    cookie_rx[2];
-       dma_cookie_t                    active_rx;
-       struct scatterlist              sg_tx;
-       unsigned int                    sg_len_tx;
-       struct scatterlist              sg_rx[2];
-       size_t                          buf_len_rx;
-       struct sh_dmae_slave            param_tx;
-       struct sh_dmae_slave            param_rx;
-       struct work_struct              work_tx;
-       struct work_struct              work_rx;
-       struct timer_list               rx_timer;
-       unsigned int                    rx_timeout;
-#endif
-};
-
-struct sh_sci_priv {
-       spinlock_t lock;
-       struct list_head ports;
-       struct notifier_block clk_nb;
-};
-
-/* Function prototypes */
-static void sci_stop_tx(struct uart_port *port);
-
-#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
-
-static struct sci_port sci_ports[SCI_NPORTS];
-static struct uart_driver sci_uart_driver;
-
-static inline struct sci_port *
-to_sci_port(struct uart_port *uart)
-{
-       return container_of(uart, struct sci_port, port);
-}
-
-#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
-
-#ifdef CONFIG_CONSOLE_POLL
-static inline void handle_error(struct uart_port *port)
-{
-       /* Clear error flags */
-       sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
-}
-
-static int sci_poll_get_char(struct uart_port *port)
-{
-       unsigned short status;
-       int c;
-
-       do {
-               status = sci_in(port, SCxSR);
-               if (status & SCxSR_ERRORS(port)) {
-                       handle_error(port);
-                       continue;
-               }
-               break;
-       } while (1);
-
-       if (!(status & SCxSR_RDxF(port)))
-               return NO_POLL_CHAR;
-
-       c = sci_in(port, SCxRDR);
-
-       /* Dummy read */
-       sci_in(port, SCxSR);
-       sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
-
-       return c;
-}
-#endif
-
-static void sci_poll_put_char(struct uart_port *port, unsigned char c)
-{
-       unsigned short status;
-
-       do {
-               status = sci_in(port, SCxSR);
-       } while (!(status & SCxSR_TDxE(port)));
-
-       sci_out(port, SCxTDR, c);
-       sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
-}
-#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */
-
-#if defined(__H8300H__) || defined(__H8300S__)
-static void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       int ch = (port->mapbase - SMR0) >> 3;
-
-       /* set DDR regs */
-       H8300_GPIO_DDR(h8300_sci_pins[ch].port,
-                      h8300_sci_pins[ch].rx,
-                      H8300_GPIO_INPUT);
-       H8300_GPIO_DDR(h8300_sci_pins[ch].port,
-                      h8300_sci_pins[ch].tx,
-                      H8300_GPIO_OUTPUT);
-
-       /* tx mark output*/
-       H8300_SCI_DR(ch) |= h8300_sci_pins[ch].tx;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       if (port->mapbase == 0xA4400000) {
-               __raw_writew(__raw_readw(PACR) & 0xffc0, PACR);
-               __raw_writew(__raw_readw(PBCR) & 0x0fff, PBCR);
-       } else if (port->mapbase == 0xA4410000)
-               __raw_writew(__raw_readw(PBCR) & 0xf003, PBCR);
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || defined(CONFIG_CPU_SUBTYPE_SH7721)
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       unsigned short data;
-
-       if (cflag & CRTSCTS) {
-               /* enable RTS/CTS */
-               if (port->mapbase == 0xa4430000) { /* SCIF0 */
-                       /* Clear PTCR bit 9-2; enable all scif pins but sck */
-                       data = __raw_readw(PORT_PTCR);
-                       __raw_writew((data & 0xfc03), PORT_PTCR);
-               } else if (port->mapbase == 0xa4438000) { /* SCIF1 */
-                       /* Clear PVCR bit 9-2 */
-                       data = __raw_readw(PORT_PVCR);
-                       __raw_writew((data & 0xfc03), PORT_PVCR);
-               }
-       } else {
-               if (port->mapbase == 0xa4430000) { /* SCIF0 */
-                       /* Clear PTCR bit 5-2; enable only tx and rx  */
-                       data = __raw_readw(PORT_PTCR);
-                       __raw_writew((data & 0xffc3), PORT_PTCR);
-               } else if (port->mapbase == 0xa4438000) { /* SCIF1 */
-                       /* Clear PVCR bit 5-2 */
-                       data = __raw_readw(PORT_PVCR);
-                       __raw_writew((data & 0xffc3), PORT_PVCR);
-               }
-       }
-}
-#elif defined(CONFIG_CPU_SH3)
-/* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       unsigned short data;
-
-       /* We need to set SCPCR to enable RTS/CTS */
-       data = __raw_readw(SCPCR);
-       /* Clear out SCP7MD1,0, SCP6MD1,0, SCP4MD1,0*/
-       __raw_writew(data & 0x0fcf, SCPCR);
-
-       if (!(cflag & CRTSCTS)) {
-               /* We need to set SCPCR to enable RTS/CTS */
-               data = __raw_readw(SCPCR);
-               /* Clear out SCP7MD1,0, SCP4MD1,0,
-                  Set SCP6MD1,0 = {01} (output)  */
-               __raw_writew((data & 0x0fcf) | 0x1000, SCPCR);
-
-               data = __raw_readb(SCPDR);
-               /* Set /RTS2 (bit6) = 0 */
-               __raw_writeb(data & 0xbf, SCPDR);
-       }
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       unsigned short data;
-
-       if (port->mapbase == 0xffe00000) {
-               data = __raw_readw(PSCR);
-               data &= ~0x03cf;
-               if (!(cflag & CRTSCTS))
-                       data |= 0x0340;
-
-               __raw_writew(data, PSCR);
-       }
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7757) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7763) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7780) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7785) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7786) || \
-      defined(CONFIG_CPU_SUBTYPE_SHX3)
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       if (!(cflag & CRTSCTS))
-               __raw_writew(0x0080, SCSPTR0); /* Set RTS = 1 */
-}
-#elif defined(CONFIG_CPU_SH4) && !defined(CONFIG_CPU_SH4A)
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       if (!(cflag & CRTSCTS))
-               __raw_writew(0x0080, SCSPTR2); /* Set RTS = 1 */
-}
-#else
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       /* Nothing to do */
-}
-#endif
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7760) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7780) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7785) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7786)
-static int scif_txfill(struct uart_port *port)
-{
-       return sci_in(port, SCTFDR) & 0xff;
-}
-
-static int scif_txroom(struct uart_port *port)
-{
-       return SCIF_TXROOM_MAX - scif_txfill(port);
-}
-
-static int scif_rxfill(struct uart_port *port)
-{
-       return sci_in(port, SCRFDR) & 0xff;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
-static int scif_txfill(struct uart_port *port)
-{
-       if (port->mapbase == 0xffe00000 ||
-           port->mapbase == 0xffe08000)
-               /* SCIF0/1*/
-               return sci_in(port, SCTFDR) & 0xff;
-       else
-               /* SCIF2 */
-               return sci_in(port, SCFDR) >> 8;
-}
-
-static int scif_txroom(struct uart_port *port)
-{
-       if (port->mapbase == 0xffe00000 ||
-           port->mapbase == 0xffe08000)
-               /* SCIF0/1*/
-               return SCIF_TXROOM_MAX - scif_txfill(port);
-       else
-               /* SCIF2 */
-               return SCIF2_TXROOM_MAX - scif_txfill(port);
-}
-
-static int scif_rxfill(struct uart_port *port)
-{
-       if ((port->mapbase == 0xffe00000) ||
-           (port->mapbase == 0xffe08000)) {
-               /* SCIF0/1*/
-               return sci_in(port, SCRFDR) & 0xff;
-       } else {
-               /* SCIF2 */
-               return sci_in(port, SCFDR) & SCIF2_RFDC_MASK;
-       }
-}
-#elif defined(CONFIG_ARCH_SH7372)
-static int scif_txfill(struct uart_port *port)
-{
-       if (port->type == PORT_SCIFA)
-               return sci_in(port, SCFDR) >> 8;
-       else
-               return sci_in(port, SCTFDR);
-}
-
-static int scif_txroom(struct uart_port *port)
-{
-       return port->fifosize - scif_txfill(port);
-}
-
-static int scif_rxfill(struct uart_port *port)
-{
-       if (port->type == PORT_SCIFA)
-               return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
-       else
-               return sci_in(port, SCRFDR);
-}
-#else
-static int scif_txfill(struct uart_port *port)
-{
-       return sci_in(port, SCFDR) >> 8;
-}
-
-static int scif_txroom(struct uart_port *port)
-{
-       return SCIF_TXROOM_MAX - scif_txfill(port);
-}
-
-static int scif_rxfill(struct uart_port *port)
-{
-       return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
-}
-#endif
-
-static int sci_txfill(struct uart_port *port)
-{
-       return !(sci_in(port, SCxSR) & SCI_TDRE);
-}
-
-static int sci_txroom(struct uart_port *port)
-{
-       return !sci_txfill(port);
-}
-
-static int sci_rxfill(struct uart_port *port)
-{
-       return (sci_in(port, SCxSR) & SCxSR_RDxF(port)) != 0;
-}
-
-/* ********************************************************************** *
- *                   the interrupt related routines                       *
- * ********************************************************************** */
-
-static void sci_transmit_chars(struct uart_port *port)
-{
-       struct circ_buf *xmit = &port->state->xmit;
-       unsigned int stopped = uart_tx_stopped(port);
-       unsigned short status;
-       unsigned short ctrl;
-       int count;
-
-       status = sci_in(port, SCxSR);
-       if (!(status & SCxSR_TDxE(port))) {
-               ctrl = sci_in(port, SCSCR);
-               if (uart_circ_empty(xmit))
-                       ctrl &= ~SCI_CTRL_FLAGS_TIE;
-               else
-                       ctrl |= SCI_CTRL_FLAGS_TIE;
-               sci_out(port, SCSCR, ctrl);
-               return;
-       }
-
-       if (port->type == PORT_SCI)
-               count = sci_txroom(port);
-       else
-               count = scif_txroom(port);
-
-       do {
-               unsigned char c;
-
-               if (port->x_char) {
-                       c = port->x_char;
-                       port->x_char = 0;
-               } else if (!uart_circ_empty(xmit) && !stopped) {
-                       c = xmit->buf[xmit->tail];
-                       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               } else {
-                       break;
-               }
-
-               sci_out(port, SCxTDR, c);
-
-               port->icount.tx++;
-       } while (--count > 0);
-
-       sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-       if (uart_circ_empty(xmit)) {
-               sci_stop_tx(port);
-       } else {
-               ctrl = sci_in(port, SCSCR);
-
-               if (port->type != PORT_SCI) {
-                       sci_in(port, SCxSR); /* Dummy read */
-                       sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
-               }
-
-               ctrl |= SCI_CTRL_FLAGS_TIE;
-               sci_out(port, SCSCR, ctrl);
-       }
-}
-
-/* On SH3, SCIF may read end-of-break as a space->mark char */
-#define STEPFN(c)  ({int __c = (c); (((__c-1)|(__c)) == -1); })
-
-static inline void sci_receive_chars(struct uart_port *port)
-{
-       struct sci_port *sci_port = to_sci_port(port);
-       struct tty_struct *tty = port->state->port.tty;
-       int i, count, copied = 0;
-       unsigned short status;
-       unsigned char flag;
-
-       status = sci_in(port, SCxSR);
-       if (!(status & SCxSR_RDxF(port)))
-               return;
-
-       while (1) {
-               if (port->type == PORT_SCI)
-                       count = sci_rxfill(port);
-               else
-                       count = scif_rxfill(port);
-
-               /* Don't copy more bytes than there is room for in the buffer */
-               count = tty_buffer_request_room(tty, count);
-
-               /* If for any reason we can't copy more data, we're done! */
-               if (count == 0)
-                       break;
-
-               if (port->type == PORT_SCI) {
-                       char c = sci_in(port, SCxRDR);
-                       if (uart_handle_sysrq_char(port, c) ||
-                           sci_port->break_flag)
-                               count = 0;
-                       else
-                               tty_insert_flip_char(tty, c, TTY_NORMAL);
-               } else {
-                       for (i = 0; i < count; i++) {
-                               char c = sci_in(port, SCxRDR);
-                               status = sci_in(port, SCxSR);
-#if defined(CONFIG_CPU_SH3)
-                               /* Skip "chars" during break */
-                               if (sci_port->break_flag) {
-                                       if ((c == 0) &&
-                                           (status & SCxSR_FER(port))) {
-                                               count--; i--;
-                                               continue;
-                                       }
-
-                                       /* Nonzero => end-of-break */
-                                       dev_dbg(port->dev, "debounce<%02x>\n", c);
-                                       sci_port->break_flag = 0;
-
-                                       if (STEPFN(c)) {
-                                               count--; i--;
-                                               continue;
-                                       }
-                               }
-#endif /* CONFIG_CPU_SH3 */
-                               if (uart_handle_sysrq_char(port, c)) {
-                                       count--; i--;
-                                       continue;
-                               }
-
-                               /* Store data and status */
-                               if (status & SCxSR_FER(port)) {
-                                       flag = TTY_FRAME;
-                                       dev_notice(port->dev, "frame error\n");
-                               } else if (status & SCxSR_PER(port)) {
-                                       flag = TTY_PARITY;
-                                       dev_notice(port->dev, "parity error\n");
-                               } else
-                                       flag = TTY_NORMAL;
-
-                               tty_insert_flip_char(tty, c, flag);
-                       }
-               }
-
-               sci_in(port, SCxSR); /* dummy read */
-               sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
-
-               copied += count;
-               port->icount.rx += count;
-       }
-
-       if (copied) {
-               /* Tell the rest of the system the news. New characters! */
-               tty_flip_buffer_push(tty);
-       } else {
-               sci_in(port, SCxSR); /* dummy read */
-               sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
-       }
-}
-
-#define SCI_BREAK_JIFFIES (HZ/20)
-/* The sci generates interrupts during the break,
- * 1 per millisecond or so during the break period, for 9600 baud.
- * So dont bother disabling interrupts.
- * But dont want more than 1 break event.
- * Use a kernel timer to periodically poll the rx line until
- * the break is finished.
- */
-static void sci_schedule_break_timer(struct sci_port *port)
-{
-       port->break_timer.expires = jiffies + SCI_BREAK_JIFFIES;
-       add_timer(&port->break_timer);
-}
-/* Ensure that two consecutive samples find the break over. */
-static void sci_break_timer(unsigned long data)
-{
-       struct sci_port *port = (struct sci_port *)data;
-
-       if (sci_rxd_in(&port->port) == 0) {
-               port->break_flag = 1;
-               sci_schedule_break_timer(port);
-       } else if (port->break_flag == 1) {
-               /* break is over. */
-               port->break_flag = 2;
-               sci_schedule_break_timer(port);
-       } else
-               port->break_flag = 0;
-}
-
-static inline int sci_handle_errors(struct uart_port *port)
-{
-       int copied = 0;
-       unsigned short status = sci_in(port, SCxSR);
-       struct tty_struct *tty = port->state->port.tty;
-
-       if (status & SCxSR_ORER(port)) {
-               /* overrun error */
-               if (tty_insert_flip_char(tty, 0, TTY_OVERRUN))
-                       copied++;
-
-               dev_notice(port->dev, "overrun error");
-       }
-
-       if (status & SCxSR_FER(port)) {
-               if (sci_rxd_in(port) == 0) {
-                       /* Notify of BREAK */
-                       struct sci_port *sci_port = to_sci_port(port);
-
-                       if (!sci_port->break_flag) {
-                               sci_port->break_flag = 1;
-                               sci_schedule_break_timer(sci_port);
-
-                               /* Do sysrq handling. */
-                               if (uart_handle_break(port))
-                                       return 0;
-
-                               dev_dbg(port->dev, "BREAK detected\n");
-
-                               if (tty_insert_flip_char(tty, 0, TTY_BREAK))
-                                       copied++;
-                       }
-
-               } else {
-                       /* frame error */
-                       if (tty_insert_flip_char(tty, 0, TTY_FRAME))
-                               copied++;
-
-                       dev_notice(port->dev, "frame error\n");
-               }
-       }
-
-       if (status & SCxSR_PER(port)) {
-               /* parity error */
-               if (tty_insert_flip_char(tty, 0, TTY_PARITY))
-                       copied++;
-
-               dev_notice(port->dev, "parity error");
-       }
-
-       if (copied)
-               tty_flip_buffer_push(tty);
-
-       return copied;
-}
-
-static inline int sci_handle_fifo_overrun(struct uart_port *port)
-{
-       struct tty_struct *tty = port->state->port.tty;
-       int copied = 0;
-
-       if (port->type != PORT_SCIF)
-               return 0;
-
-       if ((sci_in(port, SCLSR) & SCIF_ORER) != 0) {
-               sci_out(port, SCLSR, 0);
-
-               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               tty_flip_buffer_push(tty);
-
-               dev_notice(port->dev, "overrun error\n");
-               copied++;
-       }
-
-       return copied;
-}
-
-static inline int sci_handle_breaks(struct uart_port *port)
-{
-       int copied = 0;
-       unsigned short status = sci_in(port, SCxSR);
-       struct tty_struct *tty = port->state->port.tty;
-       struct sci_port *s = to_sci_port(port);
-
-       if (uart_handle_break(port))
-               return 0;
-
-       if (!s->break_flag && status & SCxSR_BRK(port)) {
-#if defined(CONFIG_CPU_SH3)
-               /* Debounce break */
-               s->break_flag = 1;
-#endif
-               /* Notify of BREAK */
-               if (tty_insert_flip_char(tty, 0, TTY_BREAK))
-                       copied++;
-
-               dev_dbg(port->dev, "BREAK detected\n");
-       }
-
-       if (copied)
-               tty_flip_buffer_push(tty);
-
-       copied += sci_handle_fifo_overrun(port);
-
-       return copied;
-}
-
-static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
-{
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
-       struct uart_port *port = ptr;
-       struct sci_port *s = to_sci_port(port);
-
-       if (s->chan_rx) {
-               u16 scr = sci_in(port, SCSCR);
-               u16 ssr = sci_in(port, SCxSR);
-
-               /* Disable future Rx interrupts */
-               if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
-                       disable_irq_nosync(irq);
-                       scr |= 0x4000;
-               } else {
-                       scr &= ~SCI_CTRL_FLAGS_RIE;
-               }
-               sci_out(port, SCSCR, scr);
-               /* Clear current interrupt */
-               sci_out(port, SCxSR, ssr & ~(1 | SCxSR_RDxF(port)));
-               dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u jiffies\n",
-                       jiffies, s->rx_timeout);
-               mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
-
-               return IRQ_HANDLED;
-       }
-#endif
-
-       /* I think sci_receive_chars has to be called irrespective
-        * of whether the I_IXOFF is set, otherwise, how is the interrupt
-        * to be disabled?
-        */
-       sci_receive_chars(ptr);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t sci_tx_interrupt(int irq, void *ptr)
-{
-       struct uart_port *port = ptr;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       sci_transmit_chars(port);
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t sci_er_interrupt(int irq, void *ptr)
-{
-       struct uart_port *port = ptr;
-
-       /* Handle errors */
-       if (port->type == PORT_SCI) {
-               if (sci_handle_errors(port)) {
-                       /* discard character in rx buffer */
-                       sci_in(port, SCxSR);
-                       sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
-               }
-       } else {
-               sci_handle_fifo_overrun(port);
-               sci_rx_interrupt(irq, ptr);
-       }
-
-       sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
-
-       /* Kick the transmission */
-       sci_tx_interrupt(irq, ptr);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t sci_br_interrupt(int irq, void *ptr)
-{
-       struct uart_port *port = ptr;
-
-       /* Handle BREAKs */
-       sci_handle_breaks(port);
-       sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port));
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
-{
-       unsigned short ssr_status, scr_status, err_enabled;
-       struct uart_port *port = ptr;
-       struct sci_port *s = to_sci_port(port);
-       irqreturn_t ret = IRQ_NONE;
-
-       ssr_status = sci_in(port, SCxSR);
-       scr_status = sci_in(port, SCSCR);
-       err_enabled = scr_status & (SCI_CTRL_FLAGS_REIE | SCI_CTRL_FLAGS_RIE);
-
-       /* Tx Interrupt */
-       if ((ssr_status & SCxSR_TDxE(port)) && (scr_status & SCI_CTRL_FLAGS_TIE) &&
-           !s->chan_tx)
-               ret = sci_tx_interrupt(irq, ptr);
-       /*
-        * Rx Interrupt: if we're using DMA, the DMA controller clears RDF /
-        * DR flags
-        */
-       if (((ssr_status & SCxSR_RDxF(port)) || s->chan_rx) &&
-           (scr_status & SCI_CTRL_FLAGS_RIE))
-               ret = sci_rx_interrupt(irq, ptr);
-       /* Error Interrupt */
-       if ((ssr_status & SCxSR_ERRORS(port)) && err_enabled)
-               ret = sci_er_interrupt(irq, ptr);
-       /* Break Interrupt */
-       if ((ssr_status & SCxSR_BRK(port)) && err_enabled)
-               ret = sci_br_interrupt(irq, ptr);
-
-       return ret;
-}
-
-/*
- * Here we define a transistion notifier so that we can update all of our
- * ports' baud rate when the peripheral clock changes.
- */
-static int sci_notifier(struct notifier_block *self,
-                       unsigned long phase, void *p)
-{
-       struct sh_sci_priv *priv = container_of(self,
-                                               struct sh_sci_priv, clk_nb);
-       struct sci_port *sci_port;
-       unsigned long flags;
-
-       if ((phase == CPUFREQ_POSTCHANGE) ||
-           (phase == CPUFREQ_RESUMECHANGE)) {
-               spin_lock_irqsave(&priv->lock, flags);
-               list_for_each_entry(sci_port, &priv->ports, node)
-                       sci_port->port.uartclk = clk_get_rate(sci_port->iclk);
-               spin_unlock_irqrestore(&priv->lock, flags);
-       }
-
-       return NOTIFY_OK;
-}
-
-static void sci_clk_enable(struct uart_port *port)
-{
-       struct sci_port *sci_port = to_sci_port(port);
-
-       clk_enable(sci_port->iclk);
-       sci_port->port.uartclk = clk_get_rate(sci_port->iclk);
-       clk_enable(sci_port->fclk);
-}
-
-static void sci_clk_disable(struct uart_port *port)
-{
-       struct sci_port *sci_port = to_sci_port(port);
-
-       clk_disable(sci_port->fclk);
-       clk_disable(sci_port->iclk);
-}
-
-static int sci_request_irq(struct sci_port *port)
-{
-       int i;
-       irqreturn_t (*handlers[4])(int irq, void *ptr) = {
-               sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt,
-               sci_br_interrupt,
-       };
-       const char *desc[] = { "SCI Receive Error", "SCI Receive Data Full",
-                              "SCI Transmit Data Empty", "SCI Break" };
-
-       if (port->irqs[0] == port->irqs[1]) {
-               if (unlikely(!port->irqs[0]))
-                       return -ENODEV;
-
-               if (request_irq(port->irqs[0], sci_mpxed_interrupt,
-                               IRQF_DISABLED, "sci", port)) {
-                       dev_err(port->port.dev, "Can't allocate IRQ\n");
-                       return -ENODEV;
-               }
-       } else {
-               for (i = 0; i < ARRAY_SIZE(handlers); i++) {
-                       if (unlikely(!port->irqs[i]))
-                               continue;
-
-                       if (request_irq(port->irqs[i], handlers[i],
-                                       IRQF_DISABLED, desc[i], port)) {
-                               dev_err(port->port.dev, "Can't allocate IRQ\n");
-                               return -ENODEV;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-static void sci_free_irq(struct sci_port *port)
-{
-       int i;
-
-       if (port->irqs[0] == port->irqs[1])
-               free_irq(port->irqs[0], port);
-       else {
-               for (i = 0; i < ARRAY_SIZE(port->irqs); i++) {
-                       if (!port->irqs[i])
-                               continue;
-
-                       free_irq(port->irqs[i], port);
-               }
-       }
-}
-
-static unsigned int sci_tx_empty(struct uart_port *port)
-{
-       unsigned short status = sci_in(port, SCxSR);
-       unsigned short in_tx_fifo = scif_txfill(port);
-
-       return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0;
-}
-
-static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       /* This routine is used for seting signals of: DTR, DCD, CTS/RTS */
-       /* We use SCIF's hardware for CTS/RTS, so don't need any for that. */
-       /* If you have signals for DTR and DCD, please implement here. */
-}
-
-static unsigned int sci_get_mctrl(struct uart_port *port)
-{
-       /* This routine is used for getting signals of: DTR, DCD, DSR, RI,
-          and CTS/RTS */
-
-       return TIOCM_DTR | TIOCM_RTS | TIOCM_DSR;
-}
-
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
-static void sci_dma_tx_complete(void *arg)
-{
-       struct sci_port *s = arg;
-       struct uart_port *port = &s->port;
-       struct circ_buf *xmit = &port->state->xmit;
-       unsigned long flags;
-
-       dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       xmit->tail += sg_dma_len(&s->sg_tx);
-       xmit->tail &= UART_XMIT_SIZE - 1;
-
-       port->icount.tx += sg_dma_len(&s->sg_tx);
-
-       async_tx_ack(s->desc_tx);
-       s->cookie_tx = -EINVAL;
-       s->desc_tx = NULL;
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (!uart_circ_empty(xmit)) {
-               schedule_work(&s->work_tx);
-       } else if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
-               u16 ctrl = sci_in(port, SCSCR);
-               sci_out(port, SCSCR, ctrl & ~SCI_CTRL_FLAGS_TIE);
-       }
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/* Locking: called with port lock held */
-static int sci_dma_rx_push(struct sci_port *s, struct tty_struct *tty,
-                          size_t count)
-{
-       struct uart_port *port = &s->port;
-       int i, active, room;
-
-       room = tty_buffer_request_room(tty, count);
-
-       if (s->active_rx == s->cookie_rx[0]) {
-               active = 0;
-       } else if (s->active_rx == s->cookie_rx[1]) {
-               active = 1;
-       } else {
-               dev_err(port->dev, "cookie %d not found!\n", s->active_rx);
-               return 0;
-       }
-
-       if (room < count)
-               dev_warn(port->dev, "Rx overrun: dropping %u bytes\n",
-                        count - room);
-       if (!room)
-               return room;
-
-       for (i = 0; i < room; i++)
-               tty_insert_flip_char(tty, ((u8 *)sg_virt(&s->sg_rx[active]))[i],
-                                    TTY_NORMAL);
-
-       port->icount.rx += room;
-
-       return room;
-}
-
-static void sci_dma_rx_complete(void *arg)
-{
-       struct sci_port *s = arg;
-       struct uart_port *port = &s->port;
-       struct tty_struct *tty = port->state->port.tty;
-       unsigned long flags;
-       int count;
-
-       dev_dbg(port->dev, "%s(%d) active #%d\n", __func__, port->line, s->active_rx);
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       count = sci_dma_rx_push(s, tty, s->buf_len_rx);
-
-       mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       if (count)
-               tty_flip_buffer_push(tty);
-
-       schedule_work(&s->work_rx);
-}
-
-static void sci_start_rx(struct uart_port *port);
-static void sci_start_tx(struct uart_port *port);
-
-static void sci_rx_dma_release(struct sci_port *s, bool enable_pio)
-{
-       struct dma_chan *chan = s->chan_rx;
-       struct uart_port *port = &s->port;
-
-       s->chan_rx = NULL;
-       s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL;
-       dma_release_channel(chan);
-       if (sg_dma_address(&s->sg_rx[0]))
-               dma_free_coherent(port->dev, s->buf_len_rx * 2,
-                                 sg_virt(&s->sg_rx[0]), sg_dma_address(&s->sg_rx[0]));
-       if (enable_pio)
-               sci_start_rx(port);
-}
-
-static void sci_tx_dma_release(struct sci_port *s, bool enable_pio)
-{
-       struct dma_chan *chan = s->chan_tx;
-       struct uart_port *port = &s->port;
-
-       s->chan_tx = NULL;
-       s->cookie_tx = -EINVAL;
-       dma_release_channel(chan);
-       if (enable_pio)
-               sci_start_tx(port);
-}
-
-static void sci_submit_rx(struct sci_port *s)
-{
-       struct dma_chan *chan = s->chan_rx;
-       int i;
-
-       for (i = 0; i < 2; i++) {
-               struct scatterlist *sg = &s->sg_rx[i];
-               struct dma_async_tx_descriptor *desc;
-
-               desc = chan->device->device_prep_slave_sg(chan,
-                       sg, 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT);
-
-               if (desc) {
-                       s->desc_rx[i] = desc;
-                       desc->callback = sci_dma_rx_complete;
-                       desc->callback_param = s;
-                       s->cookie_rx[i] = desc->tx_submit(desc);
-               }
-
-               if (!desc || s->cookie_rx[i] < 0) {
-                       if (i) {
-                               async_tx_ack(s->desc_rx[0]);
-                               s->cookie_rx[0] = -EINVAL;
-                       }
-                       if (desc) {
-                               async_tx_ack(desc);
-                               s->cookie_rx[i] = -EINVAL;
-                       }
-                       dev_warn(s->port.dev,
-                                "failed to re-start DMA, using PIO\n");
-                       sci_rx_dma_release(s, true);
-                       return;
-               }
-               dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", __func__,
-                       s->cookie_rx[i], i);
-       }
-
-       s->active_rx = s->cookie_rx[0];
-
-       dma_async_issue_pending(chan);
-}
-
-static void work_fn_rx(struct work_struct *work)
-{
-       struct sci_port *s = container_of(work, struct sci_port, work_rx);
-       struct uart_port *port = &s->port;
-       struct dma_async_tx_descriptor *desc;
-       int new;
-
-       if (s->active_rx == s->cookie_rx[0]) {
-               new = 0;
-       } else if (s->active_rx == s->cookie_rx[1]) {
-               new = 1;
-       } else {
-               dev_err(port->dev, "cookie %d not found!\n", s->active_rx);
-               return;
-       }
-       desc = s->desc_rx[new];
-
-       if (dma_async_is_tx_complete(s->chan_rx, s->active_rx, NULL, NULL) !=
-           DMA_SUCCESS) {
-               /* Handle incomplete DMA receive */
-               struct tty_struct *tty = port->state->port.tty;
-               struct dma_chan *chan = s->chan_rx;
-               struct sh_desc *sh_desc = container_of(desc, struct sh_desc,
-                                                      async_tx);
-               unsigned long flags;
-               int count;
-
-               chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
-               dev_dbg(port->dev, "Read %u bytes with cookie %d\n",
-                       sh_desc->partial, sh_desc->cookie);
-
-               spin_lock_irqsave(&port->lock, flags);
-               count = sci_dma_rx_push(s, tty, sh_desc->partial);
-               spin_unlock_irqrestore(&port->lock, flags);
-
-               if (count)
-                       tty_flip_buffer_push(tty);
-
-               sci_submit_rx(s);
-
-               return;
-       }
-
-       s->cookie_rx[new] = desc->tx_submit(desc);
-       if (s->cookie_rx[new] < 0) {
-               dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n");
-               sci_rx_dma_release(s, true);
-               return;
-       }
-
-       s->active_rx = s->cookie_rx[!new];
-
-       dev_dbg(port->dev, "%s: cookie %d #%d, new active #%d\n", __func__,
-               s->cookie_rx[new], new, s->active_rx);
-}
-
-static void work_fn_tx(struct work_struct *work)
-{
-       struct sci_port *s = container_of(work, struct sci_port, work_tx);
-       struct dma_async_tx_descriptor *desc;
-       struct dma_chan *chan = s->chan_tx;
-       struct uart_port *port = &s->port;
-       struct circ_buf *xmit = &port->state->xmit;
-       struct scatterlist *sg = &s->sg_tx;
-
-       /*
-        * DMA is idle now.
-        * Port xmit buffer is already mapped, and it is one page... Just adjust
-        * offsets and lengths. Since it is a circular buffer, we have to
-        * transmit till the end, and then the rest. Take the port lock to get a
-        * consistent xmit buffer state.
-        */
-       spin_lock_irq(&port->lock);
-       sg->offset = xmit->tail & (UART_XMIT_SIZE - 1);
-       sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) +
-               sg->offset;
-       sg_dma_len(sg) = min((int)CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE),
-               CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE));
-       spin_unlock_irq(&port->lock);
-
-       BUG_ON(!sg_dma_len(sg));
-
-       desc = chan->device->device_prep_slave_sg(chan,
-                       sg, s->sg_len_tx, DMA_TO_DEVICE,
-                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-       if (!desc) {
-               /* switch to PIO */
-               sci_tx_dma_release(s, true);
-               return;
-       }
-
-       dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE);
-
-       spin_lock_irq(&port->lock);
-       s->desc_tx = desc;
-       desc->callback = sci_dma_tx_complete;
-       desc->callback_param = s;
-       spin_unlock_irq(&port->lock);
-       s->cookie_tx = desc->tx_submit(desc);
-       if (s->cookie_tx < 0) {
-               dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n");
-               /* switch to PIO */
-               sci_tx_dma_release(s, true);
-               return;
-       }
-
-       dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", __func__,
-               xmit->buf, xmit->tail, xmit->head, s->cookie_tx);
-
-       dma_async_issue_pending(chan);
-}
-#endif
-
-static void sci_start_tx(struct uart_port *port)
-{
-       struct sci_port *s = to_sci_port(port);
-       unsigned short ctrl;
-
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
-       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
-               u16 new, scr = sci_in(port, SCSCR);
-               if (s->chan_tx)
-                       new = scr | 0x8000;
-               else
-                       new = scr & ~0x8000;
-               if (new != scr)
-                       sci_out(port, SCSCR, new);
-       }
-       if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) &&
-           s->cookie_tx < 0)
-               schedule_work(&s->work_tx);
-#endif
-       if (!s->chan_tx || port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
-               /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
-               ctrl = sci_in(port, SCSCR);
-               sci_out(port, SCSCR, ctrl | SCI_CTRL_FLAGS_TIE);
-       }
-}
-
-static void sci_stop_tx(struct uart_port *port)
-{
-       unsigned short ctrl;
-
-       /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */
-       ctrl = sci_in(port, SCSCR);
-       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
-               ctrl &= ~0x8000;
-       ctrl &= ~SCI_CTRL_FLAGS_TIE;
-       sci_out(port, SCSCR, ctrl);
-}
-
-static void sci_start_rx(struct uart_port *port)
-{
-       unsigned short ctrl = SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE;
-
-       /* Set RIE (Receive Interrupt Enable) bit in SCSCR */
-       ctrl |= sci_in(port, SCSCR);
-       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
-               ctrl &= ~0x4000;
-       sci_out(port, SCSCR, ctrl);
-}
-
-static void sci_stop_rx(struct uart_port *port)
-{
-       unsigned short ctrl;
-
-       /* Clear RIE (Receive Interrupt Enable) bit in SCSCR */
-       ctrl = sci_in(port, SCSCR);
-       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
-               ctrl &= ~0x4000;
-       ctrl &= ~(SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE);
-       sci_out(port, SCSCR, ctrl);
-}
-
-static void sci_enable_ms(struct uart_port *port)
-{
-       /* Nothing here yet .. */
-}
-
-static void sci_break_ctl(struct uart_port *port, int break_state)
-{
-       /* Nothing here yet .. */
-}
-
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
-static bool filter(struct dma_chan *chan, void *slave)
-{
-       struct sh_dmae_slave *param = slave;
-
-       dev_dbg(chan->device->dev, "%s: slave ID %d\n", __func__,
-               param->slave_id);
-
-       if (param->dma_dev == chan->device->dev) {
-               chan->private = param;
-               return true;
-       } else {
-               return false;
-       }
-}
-
-static void rx_timer_fn(unsigned long arg)
-{
-       struct sci_port *s = (struct sci_port *)arg;
-       struct uart_port *port = &s->port;
-       u16 scr = sci_in(port, SCSCR);
-
-       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
-               scr &= ~0x4000;
-               enable_irq(s->irqs[1]);
-       }
-       sci_out(port, SCSCR, scr | SCI_CTRL_FLAGS_RIE);
-       dev_dbg(port->dev, "DMA Rx timed out\n");
-       schedule_work(&s->work_rx);
-}
-
-static void sci_request_dma(struct uart_port *port)
-{
-       struct sci_port *s = to_sci_port(port);
-       struct sh_dmae_slave *param;
-       struct dma_chan *chan;
-       dma_cap_mask_t mask;
-       int nent;
-
-       dev_dbg(port->dev, "%s: port %d DMA %p\n", __func__,
-               port->line, s->dma_dev);
-
-       if (!s->dma_dev)
-               return;
-
-       dma_cap_zero(mask);
-       dma_cap_set(DMA_SLAVE, mask);
-
-       param = &s->param_tx;
-
-       /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_TX */
-       param->slave_id = s->slave_tx;
-       param->dma_dev = s->dma_dev;
-
-       s->cookie_tx = -EINVAL;
-       chan = dma_request_channel(mask, filter, param);
-       dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan);
-       if (chan) {
-               s->chan_tx = chan;
-               sg_init_table(&s->sg_tx, 1);
-               /* UART circular tx buffer is an aligned page. */
-               BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK);
-               sg_set_page(&s->sg_tx, virt_to_page(port->state->xmit.buf),
-                           UART_XMIT_SIZE, (int)port->state->xmit.buf & ~PAGE_MASK);
-               nent = dma_map_sg(port->dev, &s->sg_tx, 1, DMA_TO_DEVICE);
-               if (!nent)
-                       sci_tx_dma_release(s, false);
-               else
-                       dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__,
-                               sg_dma_len(&s->sg_tx),
-                               port->state->xmit.buf, sg_dma_address(&s->sg_tx));
-
-               s->sg_len_tx = nent;
-
-               INIT_WORK(&s->work_tx, work_fn_tx);
-       }
-
-       param = &s->param_rx;
-
-       /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_RX */
-       param->slave_id = s->slave_rx;
-       param->dma_dev = s->dma_dev;
-
-       chan = dma_request_channel(mask, filter, param);
-       dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan);
-       if (chan) {
-               dma_addr_t dma[2];
-               void *buf[2];
-               int i;
-
-               s->chan_rx = chan;
-
-               s->buf_len_rx = 2 * max(16, (int)port->fifosize);
-               buf[0] = dma_alloc_coherent(port->dev, s->buf_len_rx * 2,
-                                           &dma[0], GFP_KERNEL);
-
-               if (!buf[0]) {
-                       dev_warn(port->dev,
-                                "failed to allocate dma buffer, using PIO\n");
-                       sci_rx_dma_release(s, true);
-                       return;
-               }
-
-               buf[1] = buf[0] + s->buf_len_rx;
-               dma[1] = dma[0] + s->buf_len_rx;
-
-               for (i = 0; i < 2; i++) {
-                       struct scatterlist *sg = &s->sg_rx[i];
-
-                       sg_init_table(sg, 1);
-                       sg_set_page(sg, virt_to_page(buf[i]), s->buf_len_rx,
-                                   (int)buf[i] & ~PAGE_MASK);
-                       sg_dma_address(sg) = dma[i];
-               }
-
-               INIT_WORK(&s->work_rx, work_fn_rx);
-               setup_timer(&s->rx_timer, rx_timer_fn, (unsigned long)s);
-
-               sci_submit_rx(s);
-       }
-}
-
-static void sci_free_dma(struct uart_port *port)
-{
-       struct sci_port *s = to_sci_port(port);
-
-       if (!s->dma_dev)
-               return;
-
-       if (s->chan_tx)
-               sci_tx_dma_release(s, false);
-       if (s->chan_rx)
-               sci_rx_dma_release(s, false);
-}
-#endif
-
-static int sci_startup(struct uart_port *port)
-{
-       struct sci_port *s = to_sci_port(port);
-
-       dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
-
-       if (s->enable)
-               s->enable(port);
-
-       sci_request_irq(s);
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
-       sci_request_dma(port);
-#endif
-       sci_start_tx(port);
-       sci_start_rx(port);
-
-       return 0;
-}
-
-static void sci_shutdown(struct uart_port *port)
-{
-       struct sci_port *s = to_sci_port(port);
-
-       dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
-
-       sci_stop_rx(port);
-       sci_stop_tx(port);
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
-       sci_free_dma(port);
-#endif
-       sci_free_irq(s);
-
-       if (s->disable)
-               s->disable(port);
-}
-
-static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
-                           struct ktermios *old)
-{
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
-       struct sci_port *s = to_sci_port(port);
-#endif
-       unsigned int status, baud, smr_val, max_baud;
-       int t = -1;
-       u16 scfcr = 0;
-
-       /*
-        * earlyprintk comes here early on with port->uartclk set to zero.
-        * the clock framework is not up and running at this point so here
-        * we assume that 115200 is the maximum baud rate. please note that
-        * the baud rate is not programmed during earlyprintk - it is assumed
-        * that the previous boot loader has enabled required clocks and
-        * setup the baud rate generator hardware for us already.
-        */
-       max_baud = port->uartclk ? port->uartclk / 16 : 115200;
-
-       baud = uart_get_baud_rate(port, termios, old, 0, max_baud);
-       if (likely(baud && port->uartclk))
-               t = SCBRR_VALUE(baud, port->uartclk);
-
-       do {
-               status = sci_in(port, SCxSR);
-       } while (!(status & SCxSR_TEND(port)));
-
-       sci_out(port, SCSCR, 0x00);     /* TE=0, RE=0, CKE1=0 */
-
-       if (port->type != PORT_SCI)
-               sci_out(port, SCFCR, scfcr | SCFCR_RFRST | SCFCR_TFRST);
-
-       smr_val = sci_in(port, SCSMR) & 3;
-       if ((termios->c_cflag & CSIZE) == CS7)
-               smr_val |= 0x40;
-       if (termios->c_cflag & PARENB)
-               smr_val |= 0x20;
-       if (termios->c_cflag & PARODD)
-               smr_val |= 0x30;
-       if (termios->c_cflag & CSTOPB)
-               smr_val |= 0x08;
-
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       sci_out(port, SCSMR, smr_val);
-
-       dev_dbg(port->dev, "%s: SMR %x, t %x, SCSCR %x\n", __func__, smr_val, t,
-               SCSCR_INIT(port));
-
-       if (t > 0) {
-               if (t >= 256) {
-                       sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1);
-                       t >>= 2;
-               } else
-                       sci_out(port, SCSMR, sci_in(port, SCSMR) & ~3);
-
-               sci_out(port, SCBRR, t);
-               udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */
-       }
-
-       sci_init_pins(port, termios->c_cflag);
-       sci_out(port, SCFCR, scfcr | ((termios->c_cflag & CRTSCTS) ? SCFCR_MCE : 0));
-
-       sci_out(port, SCSCR, SCSCR_INIT(port));
-
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
-       /*
-        * Calculate delay for 1.5 DMA buffers: see
-        * drivers/serial/serial_core.c::uart_update_timeout(). With 10 bits
-        * (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above function
-        * calculates 1 jiffie for the data plus 5 jiffies for the "slop(e)."
-        * Then below we calculate 3 jiffies (12ms) for 1.5 DMA buffers (3 FIFO
-        * sizes), but it has been found out experimentally, that this is not
-        * enough: the driver too often needlessly runs on a DMA timeout. 20ms
-        * as a minimum seem to work perfectly.
-        */
-       if (s->chan_rx) {
-               s->rx_timeout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 /
-                       port->fifosize / 2;
-               dev_dbg(port->dev,
-                       "DMA Rx t-out %ums, tty t-out %u jiffies\n",
-                       s->rx_timeout * 1000 / HZ, port->timeout);
-               if (s->rx_timeout < msecs_to_jiffies(20))
-                       s->rx_timeout = msecs_to_jiffies(20);
-       }
-#endif
-
-       if ((termios->c_cflag & CREAD) != 0)
-               sci_start_rx(port);
-}
-
-static const char *sci_type(struct uart_port *port)
-{
-       switch (port->type) {
-       case PORT_IRDA:
-               return "irda";
-       case PORT_SCI:
-               return "sci";
-       case PORT_SCIF:
-               return "scif";
-       case PORT_SCIFA:
-               return "scifa";
-       case PORT_SCIFB:
-               return "scifb";
-       }
-
-       return NULL;
-}
-
-static void sci_release_port(struct uart_port *port)
-{
-       /* Nothing here yet .. */
-}
-
-static int sci_request_port(struct uart_port *port)
-{
-       /* Nothing here yet .. */
-       return 0;
-}
-
-static void sci_config_port(struct uart_port *port, int flags)
-{
-       struct sci_port *s = to_sci_port(port);
-
-       port->type = s->type;
-
-       if (port->membase)
-               return;
-
-       if (port->flags & UPF_IOREMAP) {
-               port->membase = ioremap_nocache(port->mapbase, 0x40);
-
-               if (IS_ERR(port->membase))
-                       dev_err(port->dev, "can't remap port#%d\n", port->line);
-       } else {
-               /*
-                * For the simple (and majority of) cases where we don't
-                * need to do any remapping, just cast the cookie
-                * directly.
-                */
-               port->membase = (void __iomem *)port->mapbase;
-       }
-}
-
-static int sci_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       struct sci_port *s = to_sci_port(port);
-
-       if (ser->irq != s->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs)
-               return -EINVAL;
-       if (ser->baud_base < 2400)
-               /* No paper tape reader for Mitch.. */
-               return -EINVAL;
-
-       return 0;
-}
-
-static struct uart_ops sci_uart_ops = {
-       .tx_empty       = sci_tx_empty,
-       .set_mctrl      = sci_set_mctrl,
-       .get_mctrl      = sci_get_mctrl,
-       .start_tx       = sci_start_tx,
-       .stop_tx        = sci_stop_tx,
-       .stop_rx        = sci_stop_rx,
-       .enable_ms      = sci_enable_ms,
-       .break_ctl      = sci_break_ctl,
-       .startup        = sci_startup,
-       .shutdown       = sci_shutdown,
-       .set_termios    = sci_set_termios,
-       .type           = sci_type,
-       .release_port   = sci_release_port,
-       .request_port   = sci_request_port,
-       .config_port    = sci_config_port,
-       .verify_port    = sci_verify_port,
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_get_char  = sci_poll_get_char,
-       .poll_put_char  = sci_poll_put_char,
-#endif
-};
-
-static int __devinit sci_init_single(struct platform_device *dev,
-                                    struct sci_port *sci_port,
-                                    unsigned int index,
-                                    struct plat_sci_port *p)
-{
-       struct uart_port *port = &sci_port->port;
-
-       port->ops       = &sci_uart_ops;
-       port->iotype    = UPIO_MEM;
-       port->line      = index;
-
-       switch (p->type) {
-       case PORT_SCIFB:
-               port->fifosize = 256;
-               break;
-       case PORT_SCIFA:
-               port->fifosize = 64;
-               break;
-       case PORT_SCIF:
-               port->fifosize = 16;
-               break;
-       default:
-               port->fifosize = 1;
-               break;
-       }
-
-       if (dev) {
-               sci_port->iclk = clk_get(&dev->dev, "sci_ick");
-               if (IS_ERR(sci_port->iclk)) {
-                       sci_port->iclk = clk_get(&dev->dev, "peripheral_clk");
-                       if (IS_ERR(sci_port->iclk)) {
-                               dev_err(&dev->dev, "can't get iclk\n");
-                               return PTR_ERR(sci_port->iclk);
-                       }
-               }
-
-               /*
-                * The function clock is optional, ignore it if we can't
-                * find it.
-                */
-               sci_port->fclk = clk_get(&dev->dev, "sci_fck");
-               if (IS_ERR(sci_port->fclk))
-                       sci_port->fclk = NULL;
-
-               sci_port->enable = sci_clk_enable;
-               sci_port->disable = sci_clk_disable;
-               port->dev = &dev->dev;
-       }
-
-       sci_port->break_timer.data = (unsigned long)sci_port;
-       sci_port->break_timer.function = sci_break_timer;
-       init_timer(&sci_port->break_timer);
-
-       port->mapbase   = p->mapbase;
-       port->membase   = p->membase;
-
-       port->irq       = p->irqs[SCIx_TXI_IRQ];
-       port->flags     = p->flags;
-       sci_port->type  = port->type = p->type;
-
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
-       sci_port->dma_dev       = p->dma_dev;
-       sci_port->slave_tx      = p->dma_slave_tx;
-       sci_port->slave_rx      = p->dma_slave_rx;
-
-       dev_dbg(port->dev, "%s: DMA device %p, tx %d, rx %d\n", __func__,
-               p->dma_dev, p->dma_slave_tx, p->dma_slave_rx);
-#endif
-
-       memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs));
-       return 0;
-}
-
-#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
-static struct tty_driver *serial_console_device(struct console *co, int *index)
-{
-       struct uart_driver *p = &sci_uart_driver;
-       *index = co->index;
-       return p->tty_driver;
-}
-
-static void serial_console_putchar(struct uart_port *port, int ch)
-{
-       sci_poll_put_char(port, ch);
-}
-
-/*
- *     Print a string to the serial port trying not to disturb
- *     any possible real use of the port...
- */
-static void serial_console_write(struct console *co, const char *s,
-                                unsigned count)
-{
-       struct uart_port *port = co->data;
-       struct sci_port *sci_port = to_sci_port(port);
-       unsigned short bits;
-
-       if (sci_port->enable)
-               sci_port->enable(port);
-
-       uart_console_write(port, s, count, serial_console_putchar);
-
-       /* wait until fifo is empty and last bit has been transmitted */
-       bits = SCxSR_TDxE(port) | SCxSR_TEND(port);
-       while ((sci_in(port, SCxSR) & bits) != bits)
-               cpu_relax();
-
-       if (sci_port->disable)
-               sci_port->disable(port);
-}
-
-static int __devinit serial_console_setup(struct console *co, char *options)
-{
-       struct sci_port *sci_port;
-       struct uart_port *port;
-       int baud = 115200;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-       int ret;
-
-       /*
-        * Check whether an invalid uart number has been specified, and
-        * if so, search for the first available port that does have
-        * console support.
-        */
-       if (co->index >= SCI_NPORTS)
-               co->index = 0;
-
-       if (co->data) {
-               port = co->data;
-               sci_port = to_sci_port(port);
-       } else {
-               sci_port = &sci_ports[co->index];
-               port = &sci_port->port;
-               co->data = port;
-       }
-
-       /*
-        * Also need to check port->type, we don't actually have any
-        * UPIO_PORT ports, but uart_report_port() handily misreports
-        * it anyways if we don't have a port available by the time this is
-        * called.
-        */
-       if (!port->type)
-               return -ENODEV;
-
-       sci_config_port(port, 0);
-
-       if (sci_port->enable)
-               sci_port->enable(port);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       ret = uart_set_options(port, co, baud, parity, bits, flow);
-#if defined(__H8300H__) || defined(__H8300S__)
-       /* disable rx interrupt */
-       if (ret == 0)
-               sci_stop_rx(port);
-#endif
-       /* TODO: disable clock */
-       return ret;
-}
-
-static struct console serial_console = {
-       .name           = "ttySC",
-       .device         = serial_console_device,
-       .write          = serial_console_write,
-       .setup          = serial_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-};
-
-static int __init sci_console_init(void)
-{
-       register_console(&serial_console);
-       return 0;
-}
-console_initcall(sci_console_init);
-
-static struct sci_port early_serial_port;
-static struct console early_serial_console = {
-       .name           = "early_ttySC",
-       .write          = serial_console_write,
-       .flags          = CON_PRINTBUFFER,
-};
-static char early_serial_buf[32];
-
-#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
-
-#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
-#define SCI_CONSOLE    (&serial_console)
-#else
-#define SCI_CONSOLE    0
-#endif
-
-static char banner[] __initdata =
-       KERN_INFO "SuperH SCI(F) driver initialized\n";
-
-static struct uart_driver sci_uart_driver = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "sci",
-       .dev_name       = "ttySC",
-       .major          = SCI_MAJOR,
-       .minor          = SCI_MINOR_START,
-       .nr             = SCI_NPORTS,
-       .cons           = SCI_CONSOLE,
-};
-
-
-static int sci_remove(struct platform_device *dev)
-{
-       struct sh_sci_priv *priv = platform_get_drvdata(dev);
-       struct sci_port *p;
-       unsigned long flags;
-
-       cpufreq_unregister_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER);
-
-       spin_lock_irqsave(&priv->lock, flags);
-       list_for_each_entry(p, &priv->ports, node) {
-               uart_remove_one_port(&sci_uart_driver, &p->port);
-               clk_put(p->iclk);
-               clk_put(p->fclk);
-       }
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       kfree(priv);
-       return 0;
-}
-
-static int __devinit sci_probe_single(struct platform_device *dev,
-                                     unsigned int index,
-                                     struct plat_sci_port *p,
-                                     struct sci_port *sciport)
-{
-       struct sh_sci_priv *priv = platform_get_drvdata(dev);
-       unsigned long flags;
-       int ret;
-
-       /* Sanity check */
-       if (unlikely(index >= SCI_NPORTS)) {
-               dev_notice(&dev->dev, "Attempting to register port "
-                          "%d when only %d are available.\n",
-                          index+1, SCI_NPORTS);
-               dev_notice(&dev->dev, "Consider bumping "
-                          "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n");
-               return 0;
-       }
-
-       ret = sci_init_single(dev, sciport, index, p);
-       if (ret)
-               return ret;
-
-       ret = uart_add_one_port(&sci_uart_driver, &sciport->port);
-       if (ret)
-               return ret;
-
-       INIT_LIST_HEAD(&sciport->node);
-
-       spin_lock_irqsave(&priv->lock, flags);
-       list_add(&sciport->node, &priv->ports);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       return 0;
-}
-
-/*
- * Register a set of serial devices attached to a platform device.  The
- * list is terminated with a zero flags entry, which means we expect
- * all entries to have at least UPF_BOOT_AUTOCONF set. Platforms that need
- * remapping (such as sh64) should also set UPF_IOREMAP.
- */
-static int __devinit sci_probe(struct platform_device *dev)
-{
-       struct plat_sci_port *p = dev->dev.platform_data;
-       struct sh_sci_priv *priv;
-       int i, ret = -EINVAL;
-
-#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
-       if (is_early_platform_device(dev)) {
-               if (dev->id == -1)
-                       return -ENOTSUPP;
-               early_serial_console.index = dev->id;
-               early_serial_console.data = &early_serial_port.port;
-               sci_init_single(NULL, &early_serial_port, dev->id, p);
-               serial_console_setup(&early_serial_console, early_serial_buf);
-               if (!strstr(early_serial_buf, "keep"))
-                       early_serial_console.flags |= CON_BOOT;
-               register_console(&early_serial_console);
-               return 0;
-       }
-#endif
-
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       INIT_LIST_HEAD(&priv->ports);
-       spin_lock_init(&priv->lock);
-       platform_set_drvdata(dev, priv);
-
-       priv->clk_nb.notifier_call = sci_notifier;
-       cpufreq_register_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER);
-
-       if (dev->id != -1) {
-               ret = sci_probe_single(dev, dev->id, p, &sci_ports[dev->id]);
-               if (ret)
-                       goto err_unreg;
-       } else {
-               for (i = 0; p && p->flags != 0; p++, i++) {
-                       ret = sci_probe_single(dev, i, p, &sci_ports[i]);
-                       if (ret)
-                               goto err_unreg;
-               }
-       }
-
-#ifdef CONFIG_SH_STANDARD_BIOS
-       sh_bios_gdb_detach();
-#endif
-
-       return 0;
-
-err_unreg:
-       sci_remove(dev);
-       return ret;
-}
-
-static int sci_suspend(struct device *dev)
-{
-       struct sh_sci_priv *priv = dev_get_drvdata(dev);
-       struct sci_port *p;
-       unsigned long flags;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       list_for_each_entry(p, &priv->ports, node)
-               uart_suspend_port(&sci_uart_driver, &p->port);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       return 0;
-}
-
-static int sci_resume(struct device *dev)
-{
-       struct sh_sci_priv *priv = dev_get_drvdata(dev);
-       struct sci_port *p;
-       unsigned long flags;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       list_for_each_entry(p, &priv->ports, node)
-               uart_resume_port(&sci_uart_driver, &p->port);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       return 0;
-}
-
-static const struct dev_pm_ops sci_dev_pm_ops = {
-       .suspend        = sci_suspend,
-       .resume         = sci_resume,
-};
-
-static struct platform_driver sci_driver = {
-       .probe          = sci_probe,
-       .remove         = sci_remove,
-       .driver         = {
-               .name   = "sh-sci",
-               .owner  = THIS_MODULE,
-               .pm     = &sci_dev_pm_ops,
-       },
-};
-
-static int __init sci_init(void)
-{
-       int ret;
-
-       printk(banner);
-
-       ret = uart_register_driver(&sci_uart_driver);
-       if (likely(ret == 0)) {
-               ret = platform_driver_register(&sci_driver);
-               if (unlikely(ret))
-                       uart_unregister_driver(&sci_uart_driver);
-       }
-
-       return ret;
-}
-
-static void __exit sci_exit(void)
-{
-       platform_driver_unregister(&sci_driver);
-       uart_unregister_driver(&sci_uart_driver);
-}
-
-#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
-early_platform_init_buffer("earlyprintk", &sci_driver,
-                          early_serial_buf, ARRAY_SIZE(early_serial_buf));
-#endif
-module_init(sci_init);
-module_exit(sci_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:sh-sci");
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
deleted file mode 100644 (file)
index 4bc614e..0000000
+++ /dev/null
@@ -1,660 +0,0 @@
-#include <linux/serial_core.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-
-#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
-#include <asm/regs306x.h>
-#endif
-#if defined(CONFIG_H8S2678)
-#include <asm/regs267x.h>
-#endif
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7707) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7708) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7709)
-# define SCPCR  0xA4000116 /* 16 bit SCI and SCIF */
-# define SCPDR  0xA4000136 /* 8  bit SCI and SCIF */
-# define SCSCR_INIT(port)          0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
-# define SCIF0         0xA4400000
-# define SCIF2         0xA4410000
-# define SCSMR_Ir      0xA44A0000
-# define IRDA_SCIF     SCIF0
-# define SCPCR 0xA4000116
-# define SCPDR 0xA4000136
-
-/* Set the clock source,
- * SCIF2 (0xA4410000) -> External clock, SCK pin used as clock input
- * SCIF0 (0xA4400000) -> Internal clock, SCK pin as serial clock output
- */
-# define SCSCR_INIT(port) (port->mapbase == SCIF2) ? 0xF3 : 0xF0
-#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7721) || \
-      defined(CONFIG_ARCH_SH73A0) || \
-      defined(CONFIG_ARCH_SH7367) || \
-      defined(CONFIG_ARCH_SH7377) || \
-      defined(CONFIG_ARCH_SH7372)
-# define SCSCR_INIT(port)  0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */
-# define PORT_PTCR        0xA405011EUL
-# define PORT_PVCR        0xA4050122UL
-# define SCIF_ORER        0x0200   /* overrun error bit */
-#elif defined(CONFIG_SH_RTS7751R2D)
-# define SCSPTR1 0xFFE0001C /* 8 bit SCIF */
-# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001   /* overrun error bit */
-# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7750)  || \
-      defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7091)  || \
-      defined(CONFIG_CPU_SUBTYPE_SH7751)  || \
-      defined(CONFIG_CPU_SUBTYPE_SH7751R)
-# define SCSPTR1 0xffe0001c /* 8  bit SCI */
-# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001   /* overrun error bit */
-# define SCSCR_INIT(port) (((port)->type == PORT_SCI) ? \
-       0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \
-       0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ )
-#elif defined(CONFIG_CPU_SUBTYPE_SH7760)
-# define SCSPTR0 0xfe600024 /* 16 bit SCIF */
-# define SCSPTR1 0xfe610024 /* 16 bit SCIF */
-# define SCSPTR2 0xfe620024 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001  /* overrun error bit */
-# define SCSCR_INIT(port)          0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
-# define SCSPTR0 0xA4400000      /* 16 bit SCIF */
-# define SCIF_ORER 0x0001   /* overrun error bit */
-# define PACR 0xa4050100
-# define PBCR 0xa4050102
-# define SCSCR_INIT(port)          0x3B
-#elif defined(CONFIG_CPU_SUBTYPE_SH7343)
-# define SCSPTR0 0xffe00010    /* 16 bit SCIF */
-# define SCSPTR1 0xffe10010    /* 16 bit SCIF */
-# define SCSPTR2 0xffe20010    /* 16 bit SCIF */
-# define SCSPTR3 0xffe30010    /* 16 bit SCIF */
-# define SCSCR_INIT(port) 0x32 /* TIE=0,RIE=0,TE=1,RE=1,REIE=0,CKE=1 */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
-# define PADR                  0xA4050120
-# define PSDR                  0xA405013e
-# define PWDR                  0xA4050166
-# define PSCR                  0xA405011E
-# define SCIF_ORER             0x0001  /* overrun error bit */
-# define SCSCR_INIT(port)      0x0038  /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7366)
-# define SCPDR0                        0xA405013E      /* 16 bit SCIF0 PSDR */
-# define SCSPTR0               SCPDR0
-# define SCIF_ORER             0x0001  /* overrun error bit */
-# define SCSCR_INIT(port)      0x0038  /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7723)
-# define SCSPTR0                0xa4050160
-# define SCSPTR1                0xa405013e
-# define SCSPTR2                0xa4050160
-# define SCSPTR3                0xa405013e
-# define SCSPTR4                0xa4050128
-# define SCSPTR5                0xa4050128
-# define SCIF_ORER              0x0001  /* overrun error bit */
-# define SCSCR_INIT(port)       0x0038  /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7724)
-# define SCIF_ORER              0x0001  /* overrun error bit */
-# define SCSCR_INIT(port) ((port)->type == PORT_SCIFA ? \
-       0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \
-       0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ )
-#elif defined(CONFIG_CPU_SUBTYPE_SH4_202)
-# define SCSPTR2 0xffe80020 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001   /* overrun error bit */
-# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
-#elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103)
-# define SCIF_BASE_ADDR    0x01030000
-# define SCIF_ADDR_SH5     PHYS_PERIPHERAL_BLOCK+SCIF_BASE_ADDR
-# define SCIF_PTR2_OFFS    0x0000020
-# define SCIF_LSR2_OFFS    0x0000024
-# define SCSPTR2           ((port->mapbase)+SCIF_PTR2_OFFS) /* 16 bit SCIF */
-# define SCLSR2            ((port->mapbase)+SCIF_LSR2_OFFS) /* 16 bit SCIF */
-# define SCSCR_INIT(port)  0x38                /* TIE=0,RIE=0, TE=1,RE=1,REIE=1 */
-#elif defined(CONFIG_H83007) || defined(CONFIG_H83068)
-# define SCSCR_INIT(port)          0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
-# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
-#elif defined(CONFIG_H8S2678)
-# define SCSCR_INIT(port)          0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
-# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7757)
-# define SCSPTR0 0xfe4b0020
-# define SCSPTR1 0xfe4b0020
-# define SCSPTR2 0xfe4b0020
-# define SCIF_ORER 0x0001
-# define SCSCR_INIT(port)      0x38
-# define SCIF_ONLY
-#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
-# define SCSPTR0 0xffe00024 /* 16 bit SCIF */
-# define SCSPTR1 0xffe08024 /* 16 bit SCIF */
-# define SCSPTR2 0xffe10020 /* 16 bit SCIF/IRDA */
-# define SCIF_ORER 0x0001  /* overrun error bit */
-# define SCSCR_INIT(port)      0x38    /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7770)
-# define SCSPTR0 0xff923020 /* 16 bit SCIF */
-# define SCSPTR1 0xff924020 /* 16 bit SCIF */
-# define SCSPTR2 0xff925020 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001  /* overrun error bit */
-# define SCSCR_INIT(port)      0x3c /* TIE=0,RIE=0,TE=1,RE=1,REIE=1,cke=2 */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
-# define SCSPTR0       0xffe00024      /* 16 bit SCIF */
-# define SCSPTR1       0xffe10024      /* 16 bit SCIF */
-# define SCIF_ORER     0x0001          /* Overrun error bit */
-
-#if defined(CONFIG_SH_SH2007)
-/* TIE=0,RIE=0,TE=1,RE=1,REIE=1,CKE1=0 */
-# define SCSCR_INIT(port)      0x38
-#else
-/* TIE=0,RIE=0,TE=1,RE=1,REIE=1,CKE1=1 */
-# define SCSCR_INIT(port)      0x3a
-#endif
-
-#elif defined(CONFIG_CPU_SUBTYPE_SH7785) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7786)
-# define SCSPTR0       0xffea0024      /* 16 bit SCIF */
-# define SCSPTR1       0xffeb0024      /* 16 bit SCIF */
-# define SCSPTR2       0xffec0024      /* 16 bit SCIF */
-# define SCSPTR3       0xffed0024      /* 16 bit SCIF */
-# define SCSPTR4       0xffee0024      /* 16 bit SCIF */
-# define SCSPTR5       0xffef0024      /* 16 bit SCIF */
-# define SCIF_ORER     0x0001          /* Overrun error bit */
-# define SCSCR_INIT(port)      0x3a    /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7201) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7203) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7206) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7263)
-# define SCSPTR0 0xfffe8020 /* 16 bit SCIF */
-# define SCSPTR1 0xfffe8820 /* 16 bit SCIF */
-# define SCSPTR2 0xfffe9020 /* 16 bit SCIF */
-# define SCSPTR3 0xfffe9820 /* 16 bit SCIF */
-# if defined(CONFIG_CPU_SUBTYPE_SH7201)
-#  define SCSPTR4 0xfffeA020 /* 16 bit SCIF */
-#  define SCSPTR5 0xfffeA820 /* 16 bit SCIF */
-#  define SCSPTR6 0xfffeB020 /* 16 bit SCIF */
-#  define SCSPTR7 0xfffeB820 /* 16 bit SCIF */
-# endif
-# define SCSCR_INIT(port)      0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7619)
-# define SCSPTR0 0xf8400020 /* 16 bit SCIF */
-# define SCSPTR1 0xf8410020 /* 16 bit SCIF */
-# define SCSPTR2 0xf8420020 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001  /* overrun error bit */
-# define SCSCR_INIT(port)      0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
-#elif defined(CONFIG_CPU_SUBTYPE_SHX3)
-# define SCSPTR0 0xffc30020            /* 16 bit SCIF */
-# define SCSPTR1 0xffc40020            /* 16 bit SCIF */
-# define SCSPTR2 0xffc50020            /* 16 bit SCIF */
-# define SCSPTR3 0xffc60020            /* 16 bit SCIF */
-# define SCIF_ORER 0x0001              /* Overrun error bit */
-# define SCSCR_INIT(port)      0x38    /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
-#else
-# error CPU subtype not defined
-#endif
-
-/* SCSCR */
-#define SCI_CTRL_FLAGS_TIE  0x80 /* all */
-#define SCI_CTRL_FLAGS_RIE  0x40 /* all */
-#define SCI_CTRL_FLAGS_TE   0x20 /* all */
-#define SCI_CTRL_FLAGS_RE   0x10 /* all */
-#if defined(CONFIG_CPU_SUBTYPE_SH7750)  || \
-    defined(CONFIG_CPU_SUBTYPE_SH7091)  || \
-    defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7722)  || \
-    defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7751)  || \
-    defined(CONFIG_CPU_SUBTYPE_SH7751R) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7763)  || \
-    defined(CONFIG_CPU_SUBTYPE_SH7780)  || \
-    defined(CONFIG_CPU_SUBTYPE_SH7785)  || \
-    defined(CONFIG_CPU_SUBTYPE_SH7786)  || \
-    defined(CONFIG_CPU_SUBTYPE_SHX3)
-#define SCI_CTRL_FLAGS_REIE 0x08 /* 7750 SCIF */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7724)
-#define SCI_CTRL_FLAGS_REIE ((port)->type == PORT_SCIFA ? 0 : 8)
-#else
-#define SCI_CTRL_FLAGS_REIE 0
-#endif
-/*      SCI_CTRL_FLAGS_MPIE 0x08  * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-/*      SCI_CTRL_FLAGS_TEIE 0x04  * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-/*      SCI_CTRL_FLAGS_CKE1 0x02  * all */
-/*      SCI_CTRL_FLAGS_CKE0 0x01  * 7707 SCI/SCIF, 7708 SCI, 7709 SCI/SCIF, 7750 SCI */
-
-/* SCxSR SCI */
-#define SCI_TDRE  0x80 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-#define SCI_RDRF  0x40 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-#define SCI_ORER  0x20 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-#define SCI_FER   0x10 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-#define SCI_PER   0x08 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-#define SCI_TEND  0x04 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-/*      SCI_MPB   0x02  * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-/*      SCI_MPBT  0x01  * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-
-#define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ORER)
-
-/* SCxSR SCIF */
-#define SCIF_ER    0x0080 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_TEND  0x0040 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_TDFE  0x0020 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_BRK   0x0010 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_FER   0x0008 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_PER   0x0004 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_RDF   0x0002 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_DR    0x0001 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7721) || \
-    defined(CONFIG_ARCH_SH73A0) || \
-    defined(CONFIG_ARCH_SH7367) || \
-    defined(CONFIG_ARCH_SH7377) || \
-    defined(CONFIG_ARCH_SH7372)
-# define SCIF_ORER    0x0200
-# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK | SCIF_ORER)
-# define SCIF_RFDC_MASK 0x007f
-# define SCIF_TXROOM_MAX 64
-#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
-# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK )
-# define SCIF_RFDC_MASK 0x007f
-# define SCIF_TXROOM_MAX 64
-/* SH7763 SCIF2 support */
-# define SCIF2_RFDC_MASK 0x001f
-# define SCIF2_TXROOM_MAX 16
-#else
-# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK)
-# define SCIF_RFDC_MASK 0x001f
-# define SCIF_TXROOM_MAX 16
-#endif
-
-#ifndef SCIF_ORER
-#define SCIF_ORER      0x0000
-#endif
-
-#define SCxSR_TEND(port)       (((port)->type == PORT_SCI) ? SCI_TEND   : SCIF_TEND)
-#define SCxSR_ERRORS(port)     (((port)->type == PORT_SCI) ? SCI_ERRORS : SCIF_ERRORS)
-#define SCxSR_RDxF(port)       (((port)->type == PORT_SCI) ? SCI_RDRF   : SCIF_RDF)
-#define SCxSR_TDxE(port)       (((port)->type == PORT_SCI) ? SCI_TDRE   : SCIF_TDFE)
-#define SCxSR_FER(port)                (((port)->type == PORT_SCI) ? SCI_FER    : SCIF_FER)
-#define SCxSR_PER(port)                (((port)->type == PORT_SCI) ? SCI_PER    : SCIF_PER)
-#define SCxSR_BRK(port)                (((port)->type == PORT_SCI) ? 0x00       : SCIF_BRK)
-#define SCxSR_ORER(port)       (((port)->type == PORT_SCI) ? SCI_ORER   : SCIF_ORER)
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7721) || \
-    defined(CONFIG_ARCH_SH73A0) || \
-    defined(CONFIG_ARCH_SH7367) || \
-    defined(CONFIG_ARCH_SH7377) || \
-    defined(CONFIG_ARCH_SH7372)
-# define SCxSR_RDxF_CLEAR(port)         (sci_in(port, SCxSR) & 0xfffc)
-# define SCxSR_ERROR_CLEAR(port) (sci_in(port, SCxSR) & 0xfd73)
-# define SCxSR_TDxE_CLEAR(port)         (sci_in(port, SCxSR) & 0xffdf)
-# define SCxSR_BREAK_CLEAR(port) (sci_in(port, SCxSR) & 0xffe3)
-#else
-# define SCxSR_RDxF_CLEAR(port)         (((port)->type == PORT_SCI) ? 0xbc : 0x00fc)
-# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0073)
-# define SCxSR_TDxE_CLEAR(port)  (((port)->type == PORT_SCI) ? 0x78 : 0x00df)
-# define SCxSR_BREAK_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x00e3)
-#endif
-
-/* SCFCR */
-#define SCFCR_RFRST 0x0002
-#define SCFCR_TFRST 0x0004
-#define SCFCR_TCRST 0x4000
-#define SCFCR_MCE   0x0008
-
-#define SCI_MAJOR              204
-#define SCI_MINOR_START                8
-
-/* Generic serial flags */
-#define SCI_RX_THROTTLE                0x0000001
-
-#define SCI_MAGIC 0xbabeface
-
-/*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at rs interrupt time.
- */
-#define SCI_EVENT_WRITE_WAKEUP 0
-
-#define SCI_IN(size, offset)                                   \
-  if ((size) == 8) {                                           \
-    return ioread8(port->membase + (offset));                  \
-  } else {                                                     \
-    return ioread16(port->membase + (offset));                 \
-  }
-#define SCI_OUT(size, offset, value)                           \
-  if ((size) == 8) {                                           \
-    iowrite8(value, port->membase + (offset));                 \
-  } else if ((size) == 16) {                                   \
-    iowrite16(value, port->membase + (offset));                        \
-  }
-
-#define CPU_SCIx_FNS(name, sci_offset, sci_size, scif_offset, scif_size)\
-  static inline unsigned int sci_##name##_in(struct uart_port *port)   \
-  {                                                                    \
-    if (port->type == PORT_SCIF || port->type == PORT_SCIFB) {         \
-      SCI_IN(scif_size, scif_offset)                                   \
-    } else {   /* PORT_SCI or PORT_SCIFA */                            \
-      SCI_IN(sci_size, sci_offset);                                    \
-    }                                                                  \
-  }                                                                    \
-  static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
-  {                                                                    \
-    if (port->type == PORT_SCIF || port->type == PORT_SCIFB) {         \
-      SCI_OUT(scif_size, scif_offset, value)                           \
-    } else {   /* PORT_SCI or PORT_SCIFA */                            \
-      SCI_OUT(sci_size, sci_offset, value);                            \
-    }                                                                  \
-  }
-
-#ifdef CONFIG_H8300
-/* h8300 don't have SCIF */
-#define CPU_SCIF_FNS(name)                                             \
-  static inline unsigned int sci_##name##_in(struct uart_port *port)   \
-  {                                                                    \
-    return 0;                                                          \
-  }                                                                    \
-  static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
-  {                                                                    \
-  }
-#else
-#define CPU_SCIF_FNS(name, scif_offset, scif_size)                     \
-  static inline unsigned int sci_##name##_in(struct uart_port *port)   \
-  {                                                                    \
-    SCI_IN(scif_size, scif_offset);                                    \
-  }                                                                    \
-  static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
-  {                                                                    \
-    SCI_OUT(scif_size, scif_offset, value);                            \
-  }
-#endif
-
-#define CPU_SCI_FNS(name, sci_offset, sci_size)                                \
-  static inline unsigned int sci_##name##_in(struct uart_port* port)   \
-  {                                                                    \
-    SCI_IN(sci_size, sci_offset);                                      \
-  }                                                                    \
-  static inline void sci_##name##_out(struct uart_port* port, unsigned int value) \
-  {                                                                    \
-    SCI_OUT(sci_size, sci_offset, value);                              \
-  }
-
-#if defined(CONFIG_CPU_SH3) || \
-    defined(CONFIG_ARCH_SH73A0) || \
-    defined(CONFIG_ARCH_SH7367) || \
-    defined(CONFIG_ARCH_SH7377) || \
-    defined(CONFIG_ARCH_SH7372)
-#if defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
-#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
-                               sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
-                                h8_sci_offset, h8_sci_size) \
-  CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
-#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
-         CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7720) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7721) || \
-      defined(CONFIG_ARCH_SH73A0) || \
-      defined(CONFIG_ARCH_SH7367) || \
-      defined(CONFIG_ARCH_SH7377)
-#define SCIF_FNS(name, scif_offset, scif_size) \
-  CPU_SCIF_FNS(name, scif_offset, scif_size)
-#elif defined(CONFIG_ARCH_SH7372)
-#define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scifb_offset, sh4_scifb_size) \
-  CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scifb_offset, sh4_scifb_size)
-#define SCIF_FNS(name, scif_offset, scif_size) \
-  CPU_SCIF_FNS(name, scif_offset, scif_size)
-#else
-#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
-                sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
-                 h8_sci_offset, h8_sci_size) \
-  CPU_SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh3_scif_offset, sh3_scif_size)
-#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
-  CPU_SCIF_FNS(name, sh3_scif_offset, sh3_scif_size)
-#endif
-#elif defined(__H8300H__) || defined(__H8300S__)
-#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
-                sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
-                 h8_sci_offset, h8_sci_size) \
-  CPU_SCI_FNS(name, h8_sci_offset, h8_sci_size)
-#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
-  CPU_SCIF_FNS(name)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\
-      defined(CONFIG_CPU_SUBTYPE_SH7724)
-        #define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size) \
-                CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size)
-        #define SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) \
-                CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
-#else
-#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
-                sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
-                h8_sci_offset, h8_sci_size) \
-  CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
-#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
-  CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
-#endif
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7721) || \
-    defined(CONFIG_ARCH_SH73A0) || \
-    defined(CONFIG_ARCH_SH7367) || \
-    defined(CONFIG_ARCH_SH7377)
-
-SCIF_FNS(SCSMR,  0x00, 16)
-SCIF_FNS(SCBRR,  0x04,  8)
-SCIF_FNS(SCSCR,  0x08, 16)
-SCIF_FNS(SCTDSR, 0x0c,  8)
-SCIF_FNS(SCFER,  0x10, 16)
-SCIF_FNS(SCxSR,  0x14, 16)
-SCIF_FNS(SCFCR,  0x18, 16)
-SCIF_FNS(SCFDR,  0x1c, 16)
-SCIF_FNS(SCxTDR, 0x20,  8)
-SCIF_FNS(SCxRDR, 0x24,  8)
-SCIF_FNS(SCLSR,  0x00,  0)
-#elif defined(CONFIG_ARCH_SH7372)
-SCIF_FNS(SCSMR,  0x00, 16)
-SCIF_FNS(SCBRR,  0x04,  8)
-SCIF_FNS(SCSCR,  0x08, 16)
-SCIF_FNS(SCTDSR, 0x0c, 16)
-SCIF_FNS(SCFER,  0x10, 16)
-SCIF_FNS(SCxSR,  0x14, 16)
-SCIF_FNS(SCFCR,  0x18, 16)
-SCIF_FNS(SCFDR,  0x1c, 16)
-SCIF_FNS(SCTFDR, 0x38, 16)
-SCIF_FNS(SCRFDR, 0x3c, 16)
-SCIx_FNS(SCxTDR, 0x20,  8, 0x40,  8)
-SCIx_FNS(SCxRDR, 0x24,  8, 0x60,  8)
-SCIF_FNS(SCLSR,  0x00,  0)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\
-      defined(CONFIG_CPU_SUBTYPE_SH7724)
-SCIx_FNS(SCSMR,  0x00, 16, 0x00, 16)
-SCIx_FNS(SCBRR,  0x04,  8, 0x04,  8)
-SCIx_FNS(SCSCR,  0x08, 16, 0x08, 16)
-SCIx_FNS(SCxTDR, 0x20,  8, 0x0c,  8)
-SCIx_FNS(SCxSR,  0x14, 16, 0x10, 16)
-SCIx_FNS(SCxRDR, 0x24,  8, 0x14,  8)
-SCIx_FNS(SCSPTR, 0,     0,    0,  0)
-SCIF_FNS(SCTDSR, 0x0c,  8)
-SCIF_FNS(SCFER,  0x10, 16)
-SCIF_FNS(SCFCR,  0x18, 16)
-SCIF_FNS(SCFDR,  0x1c, 16)
-SCIF_FNS(SCLSR,  0x24, 16)
-#else
-/*      reg      SCI/SH3   SCI/SH4  SCIF/SH3   SCIF/SH4  SCI/H8*/
-/*      name     off  sz   off  sz   off  sz   off  sz   off  sz*/
-SCIx_FNS(SCSMR,  0x00,  8, 0x00,  8, 0x00,  8, 0x00, 16, 0x00,  8)
-SCIx_FNS(SCBRR,  0x02,  8, 0x04,  8, 0x02,  8, 0x04,  8, 0x01,  8)
-SCIx_FNS(SCSCR,  0x04,  8, 0x08,  8, 0x04,  8, 0x08, 16, 0x02,  8)
-SCIx_FNS(SCxTDR, 0x06,  8, 0x0c,  8, 0x06,  8, 0x0C,  8, 0x03,  8)
-SCIx_FNS(SCxSR,  0x08,  8, 0x10,  8, 0x08, 16, 0x10, 16, 0x04,  8)
-SCIx_FNS(SCxRDR, 0x0a,  8, 0x14,  8, 0x0A,  8, 0x14,  8, 0x05,  8)
-SCIF_FNS(SCFCR,                      0x0c,  8, 0x18, 16)
-#if defined(CONFIG_CPU_SUBTYPE_SH7760) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7780) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7785) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7786)
-SCIF_FNS(SCFDR,                             0x0e, 16, 0x1C, 16)
-SCIF_FNS(SCTFDR,                    0x0e, 16, 0x1C, 16)
-SCIF_FNS(SCRFDR,                    0x0e, 16, 0x20, 16)
-SCIF_FNS(SCSPTR,                       0,  0, 0x24, 16)
-SCIF_FNS(SCLSR,                                0,  0, 0x28, 16)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
-SCIF_FNS(SCFDR,                                0,  0, 0x1C, 16)
-SCIF_FNS(SCSPTR2,                      0,  0, 0x20, 16)
-SCIF_FNS(SCLSR2,                       0,  0, 0x24, 16)
-SCIF_FNS(SCTFDR,                    0x0e, 16, 0x1C, 16)
-SCIF_FNS(SCRFDR,                    0x0e, 16, 0x20, 16)
-SCIF_FNS(SCSPTR,                       0,  0, 0x24, 16)
-SCIF_FNS(SCLSR,                                0,  0, 0x28, 16)
-#else
-SCIF_FNS(SCFDR,                      0x0e, 16, 0x1C, 16)
-#if defined(CONFIG_CPU_SUBTYPE_SH7722)
-SCIF_FNS(SCSPTR,                        0,  0, 0, 0)
-#else
-SCIF_FNS(SCSPTR,                        0,  0, 0x20, 16)
-#endif
-SCIF_FNS(SCLSR,                         0,  0, 0x24, 16)
-#endif
-#endif
-#define sci_in(port, reg) sci_##reg##_in(port)
-#define sci_out(port, reg, value) sci_##reg##_out(port, value)
-
-/* H8/300 series SCI pins assignment */
-#if defined(__H8300H__) || defined(__H8300S__)
-static const struct __attribute__((packed)) {
-       int port;             /* GPIO port no */
-       unsigned short rx,tx; /* GPIO bit no */
-} h8300_sci_pins[] = {
-#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
-       {    /* SCI0 */
-               .port = H8300_GPIO_P9,
-               .rx   = H8300_GPIO_B2,
-               .tx   = H8300_GPIO_B0,
-       },
-       {    /* SCI1 */
-               .port = H8300_GPIO_P9,
-               .rx   = H8300_GPIO_B3,
-               .tx   = H8300_GPIO_B1,
-       },
-       {    /* SCI2 */
-               .port = H8300_GPIO_PB,
-               .rx   = H8300_GPIO_B7,
-               .tx   = H8300_GPIO_B6,
-       }
-#elif defined(CONFIG_H8S2678)
-       {    /* SCI0 */
-               .port = H8300_GPIO_P3,
-               .rx   = H8300_GPIO_B2,
-               .tx   = H8300_GPIO_B0,
-       },
-       {    /* SCI1 */
-               .port = H8300_GPIO_P3,
-               .rx   = H8300_GPIO_B3,
-               .tx   = H8300_GPIO_B1,
-       },
-       {    /* SCI2 */
-               .port = H8300_GPIO_P5,
-               .rx   = H8300_GPIO_B1,
-               .tx   = H8300_GPIO_B0,
-       }
-#endif
-};
-#endif
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7707) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7708) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7709)
-static inline int sci_rxd_in(struct uart_port *port)
-{
-       if (port->mapbase == 0xfffffe80)
-               return __raw_readb(SCPDR)&0x01 ? 1 : 0; /* SCI */
-       return 1;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7750)  || \
-      defined(CONFIG_CPU_SUBTYPE_SH7751)  || \
-      defined(CONFIG_CPU_SUBTYPE_SH7751R) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7091)
-static inline int sci_rxd_in(struct uart_port *port)
-{
-       if (port->mapbase == 0xffe00000)
-               return __raw_readb(SCSPTR1)&0x01 ? 1 : 0; /* SCI */
-       return 1;
-}
-#elif defined(__H8300H__) || defined(__H8300S__)
-static inline int sci_rxd_in(struct uart_port *port)
-{
-       int ch = (port->mapbase - SMR0) >> 3;
-       return (H8300_SCI_DR(ch) & h8300_sci_pins[ch].rx) ? 1 : 0;
-}
-#else /* default case for non-SCI processors */
-static inline int sci_rxd_in(struct uart_port *port)
-{
-       return 1;
-}
-#endif
-
-/*
- * Values for the BitRate Register (SCBRR)
- *
- * The values are actually divisors for a frequency which can
- * be internal to the SH3 (14.7456MHz) or derived from an external
- * clock source.  This driver assumes the internal clock is used;
- * to support using an external clock source, config options or
- * possibly command-line options would need to be added.
- *
- * Also, to support speeds below 2400 (why?) the lower 2 bits of
- * the SCSMR register would also need to be set to non-zero values.
- *
- * -- Greg Banks 27Feb2000
- *
- * Answer: The SCBRR register is only eight bits, and the value in
- * it gets larger with lower baud rates. At around 2400 (depending on
- * the peripherial module clock) you run out of bits. However the
- * lower two bits of SCSMR allow the module clock to be divided down,
- * scaling the value which is needed in SCBRR.
- *
- * -- Stuart Menefy - 23 May 2000
- *
- * I meant, why would anyone bother with bitrates below 2400.
- *
- * -- Greg Banks - 7Jul2000
- *
- * You "speedist"!  How will I use my 110bps ASR-33 teletype with paper
- * tape reader as a console!
- *
- * -- Mitch Davis - 15 Jul 2000
- */
-
-#if (defined(CONFIG_CPU_SUBTYPE_SH7780)  || \
-     defined(CONFIG_CPU_SUBTYPE_SH7785)  || \
-     defined(CONFIG_CPU_SUBTYPE_SH7786)) && \
-    !defined(CONFIG_SH_SH2007)
-#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7720) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7721) || \
-      defined(CONFIG_ARCH_SH73A0) || \
-      defined(CONFIG_ARCH_SH7367) || \
-      defined(CONFIG_ARCH_SH7377) || \
-      defined(CONFIG_ARCH_SH7372)
-#define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\
-      defined(CONFIG_CPU_SUBTYPE_SH7724)
-static inline int scbrr_calc(struct uart_port *port, int bps, int clk)
-{
-       if (port->type == PORT_SCIF)
-               return (clk+16*bps)/(32*bps)-1;
-       else
-               return ((clk*2)+16*bps)/(16*bps)-1;
-}
-#define SCBRR_VALUE(bps, clk) scbrr_calc(port, bps, clk)
-#elif defined(__H8300H__) || defined(__H8300S__)
-#define SCBRR_VALUE(bps, clk) (((clk*1000/32)/bps)-1)
-#else /* Generic SH */
-#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(32*bps)-1)
-#endif
diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c
deleted file mode 100644 (file)
index cff9a30..0000000
+++ /dev/null
@@ -1,1085 +0,0 @@
-/*
- * C-Brick Serial Port (and console) driver for SGI Altix machines.
- *
- * This driver is NOT suitable for talking to the l1-controller for
- * anything other than 'console activities' --- please use the l1
- * driver for that.
- *
- *
- * Copyright (c) 2004-2006 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.  Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information:  Silicon Graphics, Inc., 1500 Crittenden Lane,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/NoticeExplan
- */
-
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/serial.h>
-#include <linux/console.h>
-#include <linux/module.h>
-#include <linux/sysrq.h>
-#include <linux/circ_buf.h>
-#include <linux/serial_reg.h>
-#include <linux/delay.h> /* for mdelay */
-#include <linux/miscdevice.h>
-#include <linux/serial_core.h>
-
-#include <asm/io.h>
-#include <asm/sn/simulator.h>
-#include <asm/sn/sn_sal.h>
-
-/* number of characters we can transmit to the SAL console at a time */
-#define SN_SAL_MAX_CHARS 120
-
-/* 64K, when we're asynch, it must be at least printk's LOG_BUF_LEN to
- * avoid losing chars, (always has to be a power of 2) */
-#define SN_SAL_BUFFER_SIZE (64 * (1 << 10))
-
-#define SN_SAL_UART_FIFO_DEPTH 16
-#define SN_SAL_UART_FIFO_SPEED_CPS (9600/10)
-
-/* sn_transmit_chars() calling args */
-#define TRANSMIT_BUFFERED      0
-#define TRANSMIT_RAW           1
-
-/* To use dynamic numbers only and not use the assigned major and minor,
- * define the following.. */
-                                 /* #define USE_DYNAMIC_MINOR 1 *//* use dynamic minor number */
-#define USE_DYNAMIC_MINOR 0    /* Don't rely on misc_register dynamic minor */
-
-/* Device name we're using */
-#define DEVICE_NAME "ttySG"
-#define DEVICE_NAME_DYNAMIC "ttySG0"   /* need full name for misc_register */
-/* The major/minor we are using, ignored for USE_DYNAMIC_MINOR */
-#define DEVICE_MAJOR 204
-#define DEVICE_MINOR 40
-
-#ifdef CONFIG_MAGIC_SYSRQ
-static char sysrq_serial_str[] = "\eSYS";
-static char *sysrq_serial_ptr = sysrq_serial_str;
-static unsigned long sysrq_requested;
-#endif /* CONFIG_MAGIC_SYSRQ */
-
-/*
- * Port definition - this kinda drives it all
- */
-struct sn_cons_port {
-       struct timer_list sc_timer;
-       struct uart_port sc_port;
-       struct sn_sal_ops {
-               int (*sal_puts_raw) (const char *s, int len);
-               int (*sal_puts) (const char *s, int len);
-               int (*sal_getc) (void);
-               int (*sal_input_pending) (void);
-               void (*sal_wakeup_transmit) (struct sn_cons_port *, int);
-       } *sc_ops;
-       unsigned long sc_interrupt_timeout;
-       int sc_is_asynch;
-};
-
-static struct sn_cons_port sal_console_port;
-static int sn_process_input;
-
-/* Only used if USE_DYNAMIC_MINOR is set to 1 */
-static struct miscdevice misc; /* used with misc_register for dynamic */
-
-extern void early_sn_setup(void);
-
-#undef DEBUG
-#ifdef DEBUG
-static int sn_debug_printf(const char *fmt, ...);
-#define DPRINTF(x...) sn_debug_printf(x)
-#else
-#define DPRINTF(x...) do { } while (0)
-#endif
-
-/* Prototypes */
-static int snt_hw_puts_raw(const char *, int);
-static int snt_hw_puts_buffered(const char *, int);
-static int snt_poll_getc(void);
-static int snt_poll_input_pending(void);
-static int snt_intr_getc(void);
-static int snt_intr_input_pending(void);
-static void sn_transmit_chars(struct sn_cons_port *, int);
-
-/* A table for polling:
- */
-static struct sn_sal_ops poll_ops = {
-       .sal_puts_raw = snt_hw_puts_raw,
-       .sal_puts = snt_hw_puts_raw,
-       .sal_getc = snt_poll_getc,
-       .sal_input_pending = snt_poll_input_pending
-};
-
-/* A table for interrupts enabled */
-static struct sn_sal_ops intr_ops = {
-       .sal_puts_raw = snt_hw_puts_raw,
-       .sal_puts = snt_hw_puts_buffered,
-       .sal_getc = snt_intr_getc,
-       .sal_input_pending = snt_intr_input_pending,
-       .sal_wakeup_transmit = sn_transmit_chars
-};
-
-/* the console does output in two distinctly different ways:
- * synchronous (raw) and asynchronous (buffered).  initally, early_printk
- * does synchronous output.  any data written goes directly to the SAL
- * to be output (incidentally, it is internally buffered by the SAL)
- * after interrupts and timers are initialized and available for use,
- * the console init code switches to asynchronous output.  this is
- * also the earliest opportunity to begin polling for console input.
- * after console initialization, console output and tty (serial port)
- * output is buffered and sent to the SAL asynchronously (either by
- * timer callback or by UART interrupt) */
-
-/* routines for running the console in polling mode */
-
-/**
- * snt_poll_getc - Get a character from the console in polling mode
- *
- */
-static int snt_poll_getc(void)
-{
-       int ch;
-
-       ia64_sn_console_getc(&ch);
-       return ch;
-}
-
-/**
- * snt_poll_input_pending - Check if any input is waiting - polling mode.
- *
- */
-static int snt_poll_input_pending(void)
-{
-       int status, input;
-
-       status = ia64_sn_console_check(&input);
-       return !status && input;
-}
-
-/* routines for an interrupt driven console (normal) */
-
-/**
- * snt_intr_getc - Get a character from the console, interrupt mode
- *
- */
-static int snt_intr_getc(void)
-{
-       return ia64_sn_console_readc();
-}
-
-/**
- * snt_intr_input_pending - Check if input is pending, interrupt mode
- *
- */
-static int snt_intr_input_pending(void)
-{
-       return ia64_sn_console_intr_status() & SAL_CONSOLE_INTR_RECV;
-}
-
-/* these functions are polled and interrupt */
-
-/**
- * snt_hw_puts_raw - Send raw string to the console, polled or interrupt mode
- * @s: String
- * @len: Length
- *
- */
-static int snt_hw_puts_raw(const char *s, int len)
-{
-       /* this will call the PROM and not return until this is done */
-       return ia64_sn_console_putb(s, len);
-}
-
-/**
- * snt_hw_puts_buffered - Send string to console, polled or interrupt mode
- * @s: String
- * @len: Length
- *
- */
-static int snt_hw_puts_buffered(const char *s, int len)
-{
-       /* queue data to the PROM */
-       return ia64_sn_console_xmit_chars((char *)s, len);
-}
-
-/* uart interface structs
- * These functions are associated with the uart_port that the serial core
- * infrastructure calls.
- *
- * Note: Due to how the console works, many routines are no-ops.
- */
-
-/**
- * snp_type - What type of console are we?
- * @port: Port to operate with (we ignore since we only have one port)
- *
- */
-static const char *snp_type(struct uart_port *port)
-{
-       return ("SGI SN L1");
-}
-
-/**
- * snp_tx_empty - Is the transmitter empty?  We pretend we're always empty
- * @port: Port to operate on (we ignore since we only have one port)
- *
- */
-static unsigned int snp_tx_empty(struct uart_port *port)
-{
-       return 1;
-}
-
-/**
- * snp_stop_tx - stop the transmitter - no-op for us
- * @port: Port to operat eon - we ignore - no-op function
- *
- */
-static void snp_stop_tx(struct uart_port *port)
-{
-}
-
-/**
- * snp_release_port - Free i/o and resources for port - no-op for us
- * @port: Port to operate on - we ignore - no-op function
- *
- */
-static void snp_release_port(struct uart_port *port)
-{
-}
-
-/**
- * snp_enable_ms - Force modem status interrupts on - no-op for us
- * @port: Port to operate on - we ignore - no-op function
- *
- */
-static void snp_enable_ms(struct uart_port *port)
-{
-}
-
-/**
- * snp_shutdown - shut down the port - free irq and disable - no-op for us
- * @port: Port to shut down - we ignore
- *
- */
-static void snp_shutdown(struct uart_port *port)
-{
-}
-
-/**
- * snp_set_mctrl - set control lines (dtr, rts, etc) - no-op for our console
- * @port: Port to operate on - we ignore
- * @mctrl: Lines to set/unset - we ignore
- *
- */
-static void snp_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-}
-
-/**
- * snp_get_mctrl - get contorl line info, we just return a static value
- * @port: port to operate on - we only have one port so we ignore this
- *
- */
-static unsigned int snp_get_mctrl(struct uart_port *port)
-{
-       return TIOCM_CAR | TIOCM_RNG | TIOCM_DSR | TIOCM_CTS;
-}
-
-/**
- * snp_stop_rx - Stop the receiver - we ignor ethis
- * @port: Port to operate on - we ignore
- *
- */
-static void snp_stop_rx(struct uart_port *port)
-{
-}
-
-/**
- * snp_start_tx - Start transmitter
- * @port: Port to operate on
- *
- */
-static void snp_start_tx(struct uart_port *port)
-{
-       if (sal_console_port.sc_ops->sal_wakeup_transmit)
-               sal_console_port.sc_ops->sal_wakeup_transmit(&sal_console_port,
-                                                            TRANSMIT_BUFFERED);
-
-}
-
-/**
- * snp_break_ctl - handle breaks - ignored by us
- * @port: Port to operate on
- * @break_state: Break state
- *
- */
-static void snp_break_ctl(struct uart_port *port, int break_state)
-{
-}
-
-/**
- * snp_startup - Start up the serial port - always return 0 (We're always on)
- * @port: Port to operate on
- *
- */
-static int snp_startup(struct uart_port *port)
-{
-       return 0;
-}
-
-/**
- * snp_set_termios - set termios stuff - we ignore these
- * @port: port to operate on
- * @termios: New settings
- * @termios: Old
- *
- */
-static void
-snp_set_termios(struct uart_port *port, struct ktermios *termios,
-               struct ktermios *old)
-{
-}
-
-/**
- * snp_request_port - allocate resources for port - ignored by us
- * @port: port to operate on
- *
- */
-static int snp_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-/**
- * snp_config_port - allocate resources, set up - we ignore,  we're always on
- * @port: Port to operate on
- * @flags: flags used for port setup
- *
- */
-static void snp_config_port(struct uart_port *port, int flags)
-{
-}
-
-/* Associate the uart functions above - given to serial core */
-
-static struct uart_ops sn_console_ops = {
-       .tx_empty = snp_tx_empty,
-       .set_mctrl = snp_set_mctrl,
-       .get_mctrl = snp_get_mctrl,
-       .stop_tx = snp_stop_tx,
-       .start_tx = snp_start_tx,
-       .stop_rx = snp_stop_rx,
-       .enable_ms = snp_enable_ms,
-       .break_ctl = snp_break_ctl,
-       .startup = snp_startup,
-       .shutdown = snp_shutdown,
-       .set_termios = snp_set_termios,
-       .pm = NULL,
-       .type = snp_type,
-       .release_port = snp_release_port,
-       .request_port = snp_request_port,
-       .config_port = snp_config_port,
-       .verify_port = NULL,
-};
-
-/* End of uart struct functions and defines */
-
-#ifdef DEBUG
-
-/**
- * sn_debug_printf - close to hardware debugging printf
- * @fmt: printf format
- *
- * This is as "close to the metal" as we can get, used when the driver
- * itself may be broken.
- *
- */
-static int sn_debug_printf(const char *fmt, ...)
-{
-       static char printk_buf[1024];
-       int printed_len;
-       va_list args;
-
-       va_start(args, fmt);
-       printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
-
-       if (!sal_console_port.sc_ops) {
-               sal_console_port.sc_ops = &poll_ops;
-               early_sn_setup();
-       }
-       sal_console_port.sc_ops->sal_puts_raw(printk_buf, printed_len);
-
-       va_end(args);
-       return printed_len;
-}
-#endif                         /* DEBUG */
-
-/*
- * Interrupt handling routines.
- */
-
-/**
- * sn_receive_chars - Grab characters, pass them to tty layer
- * @port: Port to operate on
- * @flags: irq flags
- *
- * Note: If we're not registered with the serial core infrastructure yet,
- * we don't try to send characters to it...
- *
- */
-static void
-sn_receive_chars(struct sn_cons_port *port, unsigned long flags)
-{
-       int ch;
-       struct tty_struct *tty;
-
-       if (!port) {
-               printk(KERN_ERR "sn_receive_chars - port NULL so can't receieve\n");
-               return;
-       }
-
-       if (!port->sc_ops) {
-               printk(KERN_ERR "sn_receive_chars - port->sc_ops  NULL so can't receieve\n");
-               return;
-       }
-
-       if (port->sc_port.state) {
-               /* The serial_core stuffs are initialized, use them */
-               tty = port->sc_port.state->port.tty;
-       }
-       else {
-               /* Not registered yet - can't pass to tty layer.  */
-               tty = NULL;
-       }
-
-       while (port->sc_ops->sal_input_pending()) {
-               ch = port->sc_ops->sal_getc();
-               if (ch < 0) {
-                       printk(KERN_ERR "sn_console: An error occured while "
-                              "obtaining data from the console (0x%0x)\n", ch);
-                       break;
-               }
-#ifdef CONFIG_MAGIC_SYSRQ
-                if (sysrq_requested) {
-                        unsigned long sysrq_timeout = sysrq_requested + HZ*5;
-
-                        sysrq_requested = 0;
-                        if (ch && time_before(jiffies, sysrq_timeout)) {
-                                spin_unlock_irqrestore(&port->sc_port.lock, flags);
-                                handle_sysrq(ch);
-                                spin_lock_irqsave(&port->sc_port.lock, flags);
-                                /* ignore actual sysrq command char */
-                                continue;
-                        }
-                }
-                if (ch == *sysrq_serial_ptr) {
-                        if (!(*++sysrq_serial_ptr)) {
-                                sysrq_requested = jiffies;
-                                sysrq_serial_ptr = sysrq_serial_str;
-                        }
-                       /*
-                        * ignore the whole sysrq string except for the
-                        * leading escape
-                        */
-                       if (ch != '\e')
-                               continue;
-                }
-                else
-                       sysrq_serial_ptr = sysrq_serial_str;
-#endif /* CONFIG_MAGIC_SYSRQ */
-
-               /* record the character to pass up to the tty layer */
-               if (tty) {
-                       if(tty_insert_flip_char(tty, ch, TTY_NORMAL) == 0)
-                               break;
-               }
-               port->sc_port.icount.rx++;
-       }
-
-       if (tty)
-               tty_flip_buffer_push(tty);
-}
-
-/**
- * sn_transmit_chars - grab characters from serial core, send off
- * @port: Port to operate on
- * @raw: Transmit raw or buffered
- *
- * Note: If we're early, before we're registered with serial core, the
- * writes are going through sn_sal_console_write because that's how
- * register_console has been set up.  We currently could have asynch
- * polls calling this function due to sn_sal_switch_to_asynch but we can
- * ignore them until we register with the serial core stuffs.
- *
- */
-static void sn_transmit_chars(struct sn_cons_port *port, int raw)
-{
-       int xmit_count, tail, head, loops, ii;
-       int result;
-       char *start;
-       struct circ_buf *xmit;
-
-       if (!port)
-               return;
-
-       BUG_ON(!port->sc_is_asynch);
-
-       if (port->sc_port.state) {
-               /* We're initialized, using serial core infrastructure */
-               xmit = &port->sc_port.state->xmit;
-       } else {
-               /* Probably sn_sal_switch_to_asynch has been run but serial core isn't
-                * initialized yet.  Just return.  Writes are going through
-                * sn_sal_console_write (due to register_console) at this time.
-                */
-               return;
-       }
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&port->sc_port)) {
-               /* Nothing to do. */
-               ia64_sn_console_intr_disable(SAL_CONSOLE_INTR_XMIT);
-               return;
-       }
-
-       head = xmit->head;
-       tail = xmit->tail;
-       start = &xmit->buf[tail];
-
-       /* twice around gets the tail to the end of the buffer and
-        * then to the head, if needed */
-       loops = (head < tail) ? 2 : 1;
-
-       for (ii = 0; ii < loops; ii++) {
-               xmit_count = (head < tail) ?
-                   (UART_XMIT_SIZE - tail) : (head - tail);
-
-               if (xmit_count > 0) {
-                       if (raw == TRANSMIT_RAW)
-                               result =
-                                   port->sc_ops->sal_puts_raw(start,
-                                                              xmit_count);
-                       else
-                               result =
-                                   port->sc_ops->sal_puts(start, xmit_count);
-#ifdef DEBUG
-                       if (!result)
-                               DPRINTF("`");
-#endif
-                       if (result > 0) {
-                               xmit_count -= result;
-                               port->sc_port.icount.tx += result;
-                               tail += result;
-                               tail &= UART_XMIT_SIZE - 1;
-                               xmit->tail = tail;
-                               start = &xmit->buf[tail];
-                       }
-               }
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&port->sc_port);
-
-       if (uart_circ_empty(xmit))
-               snp_stop_tx(&port->sc_port);    /* no-op for us */
-}
-
-/**
- * sn_sal_interrupt - Handle console interrupts
- * @irq: irq #, useful for debug statements
- * @dev_id: our pointer to our port (sn_cons_port which contains the uart port)
- *
- */
-static irqreturn_t sn_sal_interrupt(int irq, void *dev_id)
-{
-       struct sn_cons_port *port = (struct sn_cons_port *)dev_id;
-       unsigned long flags;
-       int status = ia64_sn_console_intr_status();
-
-       if (!port)
-               return IRQ_NONE;
-
-       spin_lock_irqsave(&port->sc_port.lock, flags);
-       if (status & SAL_CONSOLE_INTR_RECV) {
-               sn_receive_chars(port, flags);
-       }
-       if (status & SAL_CONSOLE_INTR_XMIT) {
-               sn_transmit_chars(port, TRANSMIT_BUFFERED);
-       }
-       spin_unlock_irqrestore(&port->sc_port.lock, flags);
-       return IRQ_HANDLED;
-}
-
-/**
- * sn_sal_timer_poll - this function handles polled console mode
- * @data: A pointer to our sn_cons_port (which contains the uart port)
- *
- * data is the pointer that init_timer will store for us.  This function is
- * associated with init_timer to see if there is any console traffic.
- * Obviously not used in interrupt mode
- *
- */
-static void sn_sal_timer_poll(unsigned long data)
-{
-       struct sn_cons_port *port = (struct sn_cons_port *)data;
-       unsigned long flags;
-
-       if (!port)
-               return;
-
-       if (!port->sc_port.irq) {
-               spin_lock_irqsave(&port->sc_port.lock, flags);
-               if (sn_process_input)
-                       sn_receive_chars(port, flags);
-               sn_transmit_chars(port, TRANSMIT_RAW);
-               spin_unlock_irqrestore(&port->sc_port.lock, flags);
-               mod_timer(&port->sc_timer,
-                         jiffies + port->sc_interrupt_timeout);
-       }
-}
-
-/*
- * Boot-time initialization code
- */
-
-/**
- * sn_sal_switch_to_asynch - Switch to async mode (as opposed to synch)
- * @port: Our sn_cons_port (which contains the uart port)
- *
- * So this is used by sn_sal_serial_console_init (early on, before we're
- * registered with serial core).  It's also used by sn_sal_module_init
- * right after we've registered with serial core.  The later only happens
- * if we didn't already come through here via sn_sal_serial_console_init.
- *
- */
-static void __init sn_sal_switch_to_asynch(struct sn_cons_port *port)
-{
-       unsigned long flags;
-
-       if (!port)
-               return;
-
-       DPRINTF("sn_console: about to switch to asynchronous console\n");
-
-       /* without early_printk, we may be invoked late enough to race
-        * with other cpus doing console IO at this point, however
-        * console interrupts will never be enabled */
-       spin_lock_irqsave(&port->sc_port.lock, flags);
-
-       /* early_printk invocation may have done this for us */
-       if (!port->sc_ops)
-               port->sc_ops = &poll_ops;
-
-       /* we can't turn on the console interrupt (as request_irq
-        * calls kmalloc, which isn't set up yet), so we rely on a
-        * timer to poll for input and push data from the console
-        * buffer.
-        */
-       init_timer(&port->sc_timer);
-       port->sc_timer.function = sn_sal_timer_poll;
-       port->sc_timer.data = (unsigned long)port;
-
-       if (IS_RUNNING_ON_SIMULATOR())
-               port->sc_interrupt_timeout = 6;
-       else {
-               /* 960cps / 16 char FIFO = 60HZ
-                * HZ / (SN_SAL_FIFO_SPEED_CPS / SN_SAL_FIFO_DEPTH) */
-               port->sc_interrupt_timeout =
-                   HZ * SN_SAL_UART_FIFO_DEPTH / SN_SAL_UART_FIFO_SPEED_CPS;
-       }
-       mod_timer(&port->sc_timer, jiffies + port->sc_interrupt_timeout);
-
-       port->sc_is_asynch = 1;
-       spin_unlock_irqrestore(&port->sc_port.lock, flags);
-}
-
-/**
- * sn_sal_switch_to_interrupts - Switch to interrupt driven mode
- * @port: Our sn_cons_port (which contains the uart port)
- *
- * In sn_sal_module_init, after we're registered with serial core and
- * the port is added, this function is called to switch us to interrupt
- * mode.  We were previously in asynch/polling mode (using init_timer).
- *
- * We attempt to switch to interrupt mode here by calling
- * request_irq.  If that works out, we enable receive interrupts.
- */
-static void __init sn_sal_switch_to_interrupts(struct sn_cons_port *port)
-{
-       unsigned long flags;
-
-       if (port) {
-               DPRINTF("sn_console: switching to interrupt driven console\n");
-
-               if (request_irq(SGI_UART_VECTOR, sn_sal_interrupt,
-                               IRQF_DISABLED | IRQF_SHARED,
-                               "SAL console driver", port) >= 0) {
-                       spin_lock_irqsave(&port->sc_port.lock, flags);
-                       port->sc_port.irq = SGI_UART_VECTOR;
-                       port->sc_ops = &intr_ops;
-
-                       /* turn on receive interrupts */
-                       ia64_sn_console_intr_enable(SAL_CONSOLE_INTR_RECV);
-                       spin_unlock_irqrestore(&port->sc_port.lock, flags);
-               }
-               else {
-                       printk(KERN_INFO
-                           "sn_console: console proceeding in polled mode\n");
-               }
-       }
-}
-
-/*
- * Kernel console definitions
- */
-
-static void sn_sal_console_write(struct console *, const char *, unsigned);
-static int sn_sal_console_setup(struct console *, char *);
-static struct uart_driver sal_console_uart;
-extern struct tty_driver *uart_console_device(struct console *, int *);
-
-static struct console sal_console = {
-       .name = DEVICE_NAME,
-       .write = sn_sal_console_write,
-       .device = uart_console_device,
-       .setup = sn_sal_console_setup,
-       .index = -1,            /* unspecified */
-       .data = &sal_console_uart,
-};
-
-#define SAL_CONSOLE    &sal_console
-
-static struct uart_driver sal_console_uart = {
-       .owner = THIS_MODULE,
-       .driver_name = "sn_console",
-       .dev_name = DEVICE_NAME,
-       .major = 0,             /* major/minor set at registration time per USE_DYNAMIC_MINOR */
-       .minor = 0,
-       .nr = 1,                /* one port */
-       .cons = SAL_CONSOLE,
-};
-
-/**
- * sn_sal_module_init - When the kernel loads us, get us rolling w/ serial core
- *
- * Before this is called, we've been printing kernel messages in a special
- * early mode not making use of the serial core infrastructure.  When our
- * driver is loaded for real, we register the driver and port with serial
- * core and try to enable interrupt driven mode.
- *
- */
-static int __init sn_sal_module_init(void)
-{
-       int retval;
-
-       if (!ia64_platform_is("sn2"))
-               return 0;
-
-       printk(KERN_INFO "sn_console: Console driver init\n");
-
-       if (USE_DYNAMIC_MINOR == 1) {
-               misc.minor = MISC_DYNAMIC_MINOR;
-               misc.name = DEVICE_NAME_DYNAMIC;
-               retval = misc_register(&misc);
-               if (retval != 0) {
-                       printk(KERN_WARNING "Failed to register console "
-                              "device using misc_register.\n");
-                       return -ENODEV;
-               }
-               sal_console_uart.major = MISC_MAJOR;
-               sal_console_uart.minor = misc.minor;
-       } else {
-               sal_console_uart.major = DEVICE_MAJOR;
-               sal_console_uart.minor = DEVICE_MINOR;
-       }
-
-       /* We register the driver and the port before switching to interrupts
-        * or async above so the proper uart structures are populated */
-
-       if (uart_register_driver(&sal_console_uart) < 0) {
-               printk
-                   ("ERROR sn_sal_module_init failed uart_register_driver, line %d\n",
-                    __LINE__);
-               return -ENODEV;
-       }
-
-       spin_lock_init(&sal_console_port.sc_port.lock);
-
-       /* Setup the port struct with the minimum needed */
-       sal_console_port.sc_port.membase = (char *)1;   /* just needs to be non-zero */
-       sal_console_port.sc_port.type = PORT_16550A;
-       sal_console_port.sc_port.fifosize = SN_SAL_MAX_CHARS;
-       sal_console_port.sc_port.ops = &sn_console_ops;
-       sal_console_port.sc_port.line = 0;
-
-       if (uart_add_one_port(&sal_console_uart, &sal_console_port.sc_port) < 0) {
-               /* error - not sure what I'd do - so I'll do nothing */
-               printk(KERN_ERR "%s: unable to add port\n", __func__);
-       }
-
-       /* when this driver is compiled in, the console initialization
-        * will have already switched us into asynchronous operation
-        * before we get here through the module initcalls */
-       if (!sal_console_port.sc_is_asynch) {
-               sn_sal_switch_to_asynch(&sal_console_port);
-       }
-
-       /* at this point (module_init) we can try to turn on interrupts */
-       if (!IS_RUNNING_ON_SIMULATOR()) {
-               sn_sal_switch_to_interrupts(&sal_console_port);
-       }
-       sn_process_input = 1;
-       return 0;
-}
-
-/**
- * sn_sal_module_exit - When we're unloaded, remove the driver/port
- *
- */
-static void __exit sn_sal_module_exit(void)
-{
-       del_timer_sync(&sal_console_port.sc_timer);
-       uart_remove_one_port(&sal_console_uart, &sal_console_port.sc_port);
-       uart_unregister_driver(&sal_console_uart);
-       misc_deregister(&misc);
-}
-
-module_init(sn_sal_module_init);
-module_exit(sn_sal_module_exit);
-
-/**
- * puts_raw_fixed - sn_sal_console_write helper for adding \r's as required
- * @puts_raw : puts function to do the writing
- * @s: input string
- * @count: length
- *
- * We need a \r ahead of every \n for direct writes through
- * ia64_sn_console_putb (what sal_puts_raw below actually does).
- *
- */
-
-static void puts_raw_fixed(int (*puts_raw) (const char *s, int len),
-                          const char *s, int count)
-{
-       const char *s1;
-
-       /* Output '\r' before each '\n' */
-       while ((s1 = memchr(s, '\n', count)) != NULL) {
-               puts_raw(s, s1 - s);
-               puts_raw("\r\n", 2);
-               count -= s1 + 1 - s;
-               s = s1 + 1;
-       }
-       puts_raw(s, count);
-}
-
-/**
- * sn_sal_console_write - Print statements before serial core available
- * @console: Console to operate on - we ignore since we have just one
- * @s: String to send
- * @count: length
- *
- * This is referenced in the console struct.  It is used for early
- * console printing before we register with serial core and for things
- * such as kdb.  The console_lock must be held when we get here.
- *
- * This function has some code for trying to print output even if the lock
- * is held.  We try to cover the case where a lock holder could have died.
- * We don't use this special case code if we're not registered with serial
- * core yet.  After we're registered with serial core, the only time this
- * function would be used is for high level kernel output like magic sys req,
- * kdb, and printk's.
- */
-static void
-sn_sal_console_write(struct console *co, const char *s, unsigned count)
-{
-       unsigned long flags = 0;
-       struct sn_cons_port *port = &sal_console_port;
-       static int stole_lock = 0;
-
-       BUG_ON(!port->sc_is_asynch);
-
-       /* We can't look at the xmit buffer if we're not registered with serial core
-        *  yet.  So only do the fancy recovery after registering
-        */
-       if (!port->sc_port.state) {
-               /* Not yet registered with serial core - simple case */
-               puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
-               return;
-       }
-
-       /* somebody really wants this output, might be an
-        * oops, kdb, panic, etc.  make sure they get it. */
-       if (spin_is_locked(&port->sc_port.lock)) {
-               int lhead = port->sc_port.state->xmit.head;
-               int ltail = port->sc_port.state->xmit.tail;
-               int counter, got_lock = 0;
-
-               /*
-                * We attempt to determine if someone has died with the
-                * lock. We wait ~20 secs after the head and tail ptrs
-                * stop moving and assume the lock holder is not functional
-                * and plow ahead. If the lock is freed within the time out
-                * period we re-get the lock and go ahead normally. We also
-                * remember if we have plowed ahead so that we don't have
-                * to wait out the time out period again - the asumption
-                * is that we will time out again.
-                */
-
-               for (counter = 0; counter < 150; mdelay(125), counter++) {
-                       if (!spin_is_locked(&port->sc_port.lock)
-                           || stole_lock) {
-                               if (!stole_lock) {
-                                       spin_lock_irqsave(&port->sc_port.lock,
-                                                         flags);
-                                       got_lock = 1;
-                               }
-                               break;
-                       } else {
-                               /* still locked */
-                               if ((lhead != port->sc_port.state->xmit.head)
-                                   || (ltail !=
-                                       port->sc_port.state->xmit.tail)) {
-                                       lhead =
-                                               port->sc_port.state->xmit.head;
-                                       ltail =
-                                               port->sc_port.state->xmit.tail;
-                                       counter = 0;
-                               }
-                       }
-               }
-               /* flush anything in the serial core xmit buffer, raw */
-               sn_transmit_chars(port, 1);
-               if (got_lock) {
-                       spin_unlock_irqrestore(&port->sc_port.lock, flags);
-                       stole_lock = 0;
-               } else {
-                       /* fell thru */
-                       stole_lock = 1;
-               }
-               puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
-       } else {
-               stole_lock = 0;
-               spin_lock_irqsave(&port->sc_port.lock, flags);
-               sn_transmit_chars(port, 1);
-               spin_unlock_irqrestore(&port->sc_port.lock, flags);
-
-               puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
-       }
-}
-
-
-/**
- * sn_sal_console_setup - Set up console for early printing
- * @co: Console to work with
- * @options: Options to set
- *
- * Altix console doesn't do anything with baud rates, etc, anyway.
- *
- * This isn't required since not providing the setup function in the
- * console struct is ok.  However, other patches like KDB plop something
- * here so providing it is easier.
- *
- */
-static int sn_sal_console_setup(struct console *co, char *options)
-{
-       return 0;
-}
-
-/**
- * sn_sal_console_write_early - simple early output routine
- * @co - console struct
- * @s - string to print
- * @count - count
- *
- * Simple function to provide early output, before even
- * sn_sal_serial_console_init is called.  Referenced in the
- * console struct registerd in sn_serial_console_early_setup.
- *
- */
-static void __init
-sn_sal_console_write_early(struct console *co, const char *s, unsigned count)
-{
-       puts_raw_fixed(sal_console_port.sc_ops->sal_puts_raw, s, count);
-}
-
-/* Used for very early console printing - again, before
- * sn_sal_serial_console_init is run */
-static struct console sal_console_early __initdata = {
-       .name = "sn_sal",
-       .write = sn_sal_console_write_early,
-       .flags = CON_PRINTBUFFER,
-       .index = -1,
-};
-
-/**
- * sn_serial_console_early_setup - Sets up early console output support
- *
- * Register a console early on...  This is for output before even
- * sn_sal_serial_cosnole_init is called.  This function is called from
- * setup.c.  This allows us to do really early polled writes. When
- * sn_sal_serial_console_init is called, this console is unregistered
- * and a new one registered.
- */
-int __init sn_serial_console_early_setup(void)
-{
-       if (!ia64_platform_is("sn2"))
-               return -1;
-
-       sal_console_port.sc_ops = &poll_ops;
-       spin_lock_init(&sal_console_port.sc_port.lock);
-       early_sn_setup();       /* Find SAL entry points */
-       register_console(&sal_console_early);
-
-       return 0;
-}
-
-/**
- * sn_sal_serial_console_init - Early console output - set up for register
- *
- * This function is called when regular console init happens.  Because we
- * support even earlier console output with sn_serial_console_early_setup
- * (called from setup.c directly), this function unregisters the really
- * early console.
- *
- * Note: Even if setup.c doesn't register sal_console_early, unregistering
- * it here doesn't hurt anything.
- *
- */
-static int __init sn_sal_serial_console_init(void)
-{
-       if (ia64_platform_is("sn2")) {
-               sn_sal_switch_to_asynch(&sal_console_port);
-               DPRINTF("sn_sal_serial_console_init : register console\n");
-               register_console(&sal_console);
-               unregister_console(&sal_console_early);
-       }
-       return 0;
-}
-
-console_initcall(sn_sal_serial_console_init);
diff --git a/drivers/serial/suncore.c b/drivers/serial/suncore.c
deleted file mode 100644 (file)
index 6381a02..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-/* suncore.c
- *
- * Common SUN serial routines.  Based entirely
- * upon drivers/sbus/char/sunserial.c which is:
- *
- * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
- *
- * Adaptation to new UART layer is:
- *
- * Copyright (C) 2002 David S. Miller (davem@redhat.com)
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/console.h>
-#include <linux/tty.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/serial_core.h>
-#include <linux/init.h>
-
-#include <asm/prom.h>
-
-#include "suncore.h"
-
-static int sunserial_current_minor = 64;
-
-int sunserial_register_minors(struct uart_driver *drv, int count)
-{
-       int err = 0;
-
-       drv->minor = sunserial_current_minor;
-       drv->nr += count;
-       /* Register the driver on the first call */
-       if (drv->nr == count)
-               err = uart_register_driver(drv);
-       if (err == 0) {
-               sunserial_current_minor += count;
-               drv->tty_driver->name_base = drv->minor - 64;
-       }
-       return err;
-}
-EXPORT_SYMBOL(sunserial_register_minors);
-
-void sunserial_unregister_minors(struct uart_driver *drv, int count)
-{
-       drv->nr -= count;
-       sunserial_current_minor -= count;
-
-       if (drv->nr == 0)
-               uart_unregister_driver(drv);
-}
-EXPORT_SYMBOL(sunserial_unregister_minors);
-
-int sunserial_console_match(struct console *con, struct device_node *dp,
-                           struct uart_driver *drv, int line, bool ignore_line)
-{
-       if (!con)
-               return 0;
-
-       drv->cons = con;
-
-       if (of_console_device != dp)
-               return 0;
-
-       if (!ignore_line) {
-               int off = 0;
-
-               if (of_console_options &&
-                   *of_console_options == 'b')
-                       off = 1;
-
-               if ((line & 1) != off)
-                       return 0;
-       }
-
-       if (!console_set_on_cmdline) {
-               con->index = line;
-               add_preferred_console(con->name, line, NULL);
-       }
-       return 1;
-}
-EXPORT_SYMBOL(sunserial_console_match);
-
-void sunserial_console_termios(struct console *con, struct device_node *uart_dp)
-{
-       const char *mode, *s;
-       char mode_prop[] = "ttyX-mode";
-       int baud, bits, stop, cflag;
-       char parity;
-
-       if (!strcmp(uart_dp->name, "rsc") ||
-           !strcmp(uart_dp->name, "rsc-console") ||
-           !strcmp(uart_dp->name, "rsc-control")) {
-               mode = of_get_property(uart_dp,
-                                      "ssp-console-modes", NULL);
-               if (!mode)
-                       mode = "115200,8,n,1,-";
-       } else if (!strcmp(uart_dp->name, "lom-console")) {
-               mode = "9600,8,n,1,-";
-       } else {
-               struct device_node *dp;
-               char c;
-
-               c = 'a';
-               if (of_console_options)
-                       c = *of_console_options;
-
-               mode_prop[3] = c;
-
-               dp = of_find_node_by_path("/options");
-               mode = of_get_property(dp, mode_prop, NULL);
-               if (!mode)
-                       mode = "9600,8,n,1,-";
-       }
-
-       cflag = CREAD | HUPCL | CLOCAL;
-
-       s = mode;
-       baud = simple_strtoul(s, NULL, 0);
-       s = strchr(s, ',');
-       bits = simple_strtoul(++s, NULL, 0);
-       s = strchr(s, ',');
-       parity = *(++s);
-       s = strchr(s, ',');
-       stop = simple_strtoul(++s, NULL, 0);
-       s = strchr(s, ',');
-       /* XXX handshake is not handled here. */
-
-       switch (baud) {
-               case 150: cflag |= B150; break;
-               case 300: cflag |= B300; break;
-               case 600: cflag |= B600; break;
-               case 1200: cflag |= B1200; break;
-               case 2400: cflag |= B2400; break;
-               case 4800: cflag |= B4800; break;
-               case 9600: cflag |= B9600; break;
-               case 19200: cflag |= B19200; break;
-               case 38400: cflag |= B38400; break;
-               case 57600: cflag |= B57600; break;
-               case 115200: cflag |= B115200; break;
-               case 230400: cflag |= B230400; break;
-               case 460800: cflag |= B460800; break;
-               default: baud = 9600; cflag |= B9600; break;
-       }
-
-       switch (bits) {
-               case 5: cflag |= CS5; break;
-               case 6: cflag |= CS6; break;
-               case 7: cflag |= CS7; break;
-               case 8: cflag |= CS8; break;
-               default: cflag |= CS8; break;
-       }
-
-       switch (parity) {
-               case 'o': cflag |= (PARENB | PARODD); break;
-               case 'e': cflag |= PARENB; break;
-               case 'n': default: break;
-       }
-
-       switch (stop) {
-               case 2: cflag |= CSTOPB; break;
-               case 1: default: break;
-       }
-
-       con->cflag = cflag;
-}
-
-/* Sun serial MOUSE auto baud rate detection.  */
-static struct mouse_baud_cflag {
-       int baud;
-       unsigned int cflag;
-} mouse_baud_table[] = {
-       { 1200, B1200 },
-       { 2400, B2400 },
-       { 4800, B4800 },
-       { 9600, B9600 },
-       { -1, ~0 },
-       { -1, ~0 },
-};
-
-unsigned int suncore_mouse_baud_cflag_next(unsigned int cflag, int *new_baud)
-{
-       int i;
-
-       for (i = 0; mouse_baud_table[i].baud != -1; i++)
-               if (mouse_baud_table[i].cflag == (cflag & CBAUD))
-                       break;
-
-       i += 1;
-       if (mouse_baud_table[i].baud == -1)
-               i = 0;
-
-       *new_baud = mouse_baud_table[i].baud;
-       return mouse_baud_table[i].cflag;
-}
-
-EXPORT_SYMBOL(suncore_mouse_baud_cflag_next);
-
-/* Basically, when the baud rate is wrong the mouse spits out
- * breaks to us.
- */
-int suncore_mouse_baud_detection(unsigned char ch, int is_break)
-{
-       static int mouse_got_break = 0;
-       static int ctr = 0;
-
-       if (is_break) {
-               /* Let a few normal bytes go by before we jump the gun
-                * and say we need to try another baud rate.
-                */
-               if (mouse_got_break && ctr < 8)
-                       return 1;
-
-               /* Ok, we need to try another baud. */
-               ctr = 0;
-               mouse_got_break = 1;
-               return 2;
-       }
-       if (mouse_got_break) {
-               ctr++;
-               if (ch == 0x87) {
-                       /* Correct baud rate determined. */
-                       mouse_got_break = 0;
-               }
-               return 1;
-       }
-       return 0;
-}
-
-EXPORT_SYMBOL(suncore_mouse_baud_detection);
-
-static int __init suncore_init(void)
-{
-       return 0;
-}
-
-static void __exit suncore_exit(void)
-{
-}
-
-module_init(suncore_init);
-module_exit(suncore_exit);
-
-MODULE_AUTHOR("Eddie C. Dost, David S. Miller");
-MODULE_DESCRIPTION("Sun serial common layer");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/suncore.h b/drivers/serial/suncore.h
deleted file mode 100644 (file)
index db20579..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/* suncore.h
- *
- * Generic SUN serial/kbd/ms layer.  Based entirely
- * upon drivers/sbus/char/sunserial.h which is:
- *
- * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
- *
- * Port to new UART layer is:
- *
- * Copyright (C) 2002 David S. Miller (davem@redhat.com)
- */
-
-#ifndef _SERIAL_SUN_H
-#define _SERIAL_SUN_H
-
-/* Serial keyboard defines for L1-A processing... */
-#define SUNKBD_RESET           0xff
-#define SUNKBD_L1              0x01
-#define SUNKBD_UP              0x80
-#define SUNKBD_A               0x4d
-
-extern unsigned int suncore_mouse_baud_cflag_next(unsigned int, int *);
-extern int suncore_mouse_baud_detection(unsigned char, int);
-
-extern int sunserial_register_minors(struct uart_driver *, int);
-extern void sunserial_unregister_minors(struct uart_driver *, int);
-
-extern int sunserial_console_match(struct console *, struct device_node *,
-                                  struct uart_driver *, int, bool);
-extern void sunserial_console_termios(struct console *,
-                                     struct device_node *);
-
-#endif /* !(_SERIAL_SUN_H) */
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
deleted file mode 100644 (file)
index c901486..0000000
+++ /dev/null
@@ -1,661 +0,0 @@
-/* sunhv.c: Serial driver for SUN4V hypervisor console.
- *
- * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net)
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/circ_buf.h>
-#include <linux/serial.h>
-#include <linux/sysrq.h>
-#include <linux/console.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/of_device.h>
-
-#include <asm/hypervisor.h>
-#include <asm/spitfire.h>
-#include <asm/prom.h>
-#include <asm/irq.h>
-
-#if defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
-#include "suncore.h"
-
-#define CON_BREAK      ((long)-1)
-#define CON_HUP                ((long)-2)
-
-#define IGNORE_BREAK   0x1
-#define IGNORE_ALL     0x2
-
-static char *con_write_page;
-static char *con_read_page;
-
-static int hung_up = 0;
-
-static void transmit_chars_putchar(struct uart_port *port, struct circ_buf *xmit)
-{
-       while (!uart_circ_empty(xmit)) {
-               long status = sun4v_con_putchar(xmit->buf[xmit->tail]);
-
-               if (status != HV_EOK)
-                       break;
-
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-       }
-}
-
-static void transmit_chars_write(struct uart_port *port, struct circ_buf *xmit)
-{
-       while (!uart_circ_empty(xmit)) {
-               unsigned long ra = __pa(xmit->buf + xmit->tail);
-               unsigned long len, status, sent;
-
-               len = CIRC_CNT_TO_END(xmit->head, xmit->tail,
-                                     UART_XMIT_SIZE);
-               status = sun4v_con_write(ra, len, &sent);
-               if (status != HV_EOK)
-                       break;
-               xmit->tail = (xmit->tail + sent) & (UART_XMIT_SIZE - 1);
-               port->icount.tx += sent;
-       }
-}
-
-static int receive_chars_getchar(struct uart_port *port, struct tty_struct *tty)
-{
-       int saw_console_brk = 0;
-       int limit = 10000;
-
-       while (limit-- > 0) {
-               long status;
-               long c = sun4v_con_getchar(&status);
-
-               if (status == HV_EWOULDBLOCK)
-                       break;
-
-               if (c == CON_BREAK) {
-                       if (uart_handle_break(port))
-                               continue;
-                       saw_console_brk = 1;
-                       c = 0;
-               }
-
-               if (c == CON_HUP) {
-                       hung_up = 1;
-                       uart_handle_dcd_change(port, 0);
-               } else if (hung_up) {
-                       hung_up = 0;
-                       uart_handle_dcd_change(port, 1);
-               }
-
-               if (tty == NULL) {
-                       uart_handle_sysrq_char(port, c);
-                       continue;
-               }
-
-               port->icount.rx++;
-
-               if (uart_handle_sysrq_char(port, c))
-                       continue;
-
-               tty_insert_flip_char(tty, c, TTY_NORMAL);
-       }
-
-       return saw_console_brk;
-}
-
-static int receive_chars_read(struct uart_port *port, struct tty_struct *tty)
-{
-       int saw_console_brk = 0;
-       int limit = 10000;
-
-       while (limit-- > 0) {
-               unsigned long ra = __pa(con_read_page);
-               unsigned long bytes_read, i;
-               long stat = sun4v_con_read(ra, PAGE_SIZE, &bytes_read);
-
-               if (stat != HV_EOK) {
-                       bytes_read = 0;
-
-                       if (stat == CON_BREAK) {
-                               if (uart_handle_break(port))
-                                       continue;
-                               saw_console_brk = 1;
-                               *con_read_page = 0;
-                               bytes_read = 1;
-                       } else if (stat == CON_HUP) {
-                               hung_up = 1;
-                               uart_handle_dcd_change(port, 0);
-                               continue;
-                       } else {
-                               /* HV_EWOULDBLOCK, etc.  */
-                               break;
-                       }
-               }
-
-               if (hung_up) {
-                       hung_up = 0;
-                       uart_handle_dcd_change(port, 1);
-               }
-
-               for (i = 0; i < bytes_read; i++)
-                       uart_handle_sysrq_char(port, con_read_page[i]);
-
-               if (tty == NULL)
-                       continue;
-
-               port->icount.rx += bytes_read;
-
-               tty_insert_flip_string(tty, con_read_page, bytes_read);
-       }
-
-       return saw_console_brk;
-}
-
-struct sunhv_ops {
-       void (*transmit_chars)(struct uart_port *port, struct circ_buf *xmit);
-       int (*receive_chars)(struct uart_port *port, struct tty_struct *tty);
-};
-
-static struct sunhv_ops bychar_ops = {
-       .transmit_chars = transmit_chars_putchar,
-       .receive_chars = receive_chars_getchar,
-};
-
-static struct sunhv_ops bywrite_ops = {
-       .transmit_chars = transmit_chars_write,
-       .receive_chars = receive_chars_read,
-};
-
-static struct sunhv_ops *sunhv_ops = &bychar_ops;
-
-static struct tty_struct *receive_chars(struct uart_port *port)
-{
-       struct tty_struct *tty = NULL;
-
-       if (port->state != NULL)                /* Unopened serial console */
-               tty = port->state->port.tty;
-
-       if (sunhv_ops->receive_chars(port, tty))
-               sun_do_break();
-
-       return tty;
-}
-
-static void transmit_chars(struct uart_port *port)
-{
-       struct circ_buf *xmit;
-
-       if (!port->state)
-               return;
-
-       xmit = &port->state->xmit;
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port))
-               return;
-
-       sunhv_ops->transmit_chars(port, xmit);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-}
-
-static irqreturn_t sunhv_interrupt(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       struct tty_struct *tty;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       tty = receive_chars(port);
-       transmit_chars(port);
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       if (tty)
-               tty_flip_buffer_push(tty);
-
-       return IRQ_HANDLED;
-}
-
-/* port->lock is not held.  */
-static unsigned int sunhv_tx_empty(struct uart_port *port)
-{
-       /* Transmitter is always empty for us.  If the circ buffer
-        * is non-empty or there is an x_char pending, our caller
-        * will do the right thing and ignore what we return here.
-        */
-       return TIOCSER_TEMT;
-}
-
-/* port->lock held by caller.  */
-static void sunhv_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       return;
-}
-
-/* port->lock is held by caller and interrupts are disabled.  */
-static unsigned int sunhv_get_mctrl(struct uart_port *port)
-{
-       return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS;
-}
-
-/* port->lock held by caller.  */
-static void sunhv_stop_tx(struct uart_port *port)
-{
-       return;
-}
-
-/* port->lock held by caller.  */
-static void sunhv_start_tx(struct uart_port *port)
-{
-       transmit_chars(port);
-}
-
-/* port->lock is not held.  */
-static void sunhv_send_xchar(struct uart_port *port, char ch)
-{
-       unsigned long flags;
-       int limit = 10000;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       while (limit-- > 0) {
-               long status = sun4v_con_putchar(ch);
-               if (status == HV_EOK)
-                       break;
-               udelay(1);
-       }
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/* port->lock held by caller.  */
-static void sunhv_stop_rx(struct uart_port *port)
-{
-}
-
-/* port->lock held by caller.  */
-static void sunhv_enable_ms(struct uart_port *port)
-{
-}
-
-/* port->lock is not held.  */
-static void sunhv_break_ctl(struct uart_port *port, int break_state)
-{
-       if (break_state) {
-               unsigned long flags;
-               int limit = 10000;
-
-               spin_lock_irqsave(&port->lock, flags);
-
-               while (limit-- > 0) {
-                       long status = sun4v_con_putchar(CON_BREAK);
-                       if (status == HV_EOK)
-                               break;
-                       udelay(1);
-               }
-
-               spin_unlock_irqrestore(&port->lock, flags);
-       }
-}
-
-/* port->lock is not held.  */
-static int sunhv_startup(struct uart_port *port)
-{
-       return 0;
-}
-
-/* port->lock is not held.  */
-static void sunhv_shutdown(struct uart_port *port)
-{
-}
-
-/* port->lock is not held.  */
-static void sunhv_set_termios(struct uart_port *port, struct ktermios *termios,
-                             struct ktermios *old)
-{
-       unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
-       unsigned int quot = uart_get_divisor(port, baud);
-       unsigned int iflag, cflag;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       iflag = termios->c_iflag;
-       cflag = termios->c_cflag;
-
-       port->ignore_status_mask = 0;
-       if (iflag & IGNBRK)
-               port->ignore_status_mask |= IGNORE_BREAK;
-       if ((cflag & CREAD) == 0)
-               port->ignore_status_mask |= IGNORE_ALL;
-
-       /* XXX */
-       uart_update_timeout(port, cflag,
-                           (port->uartclk / (16 * quot)));
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *sunhv_type(struct uart_port *port)
-{
-       return "SUN4V HCONS";
-}
-
-static void sunhv_release_port(struct uart_port *port)
-{
-}
-
-static int sunhv_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-static void sunhv_config_port(struct uart_port *port, int flags)
-{
-}
-
-static int sunhv_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       return -EINVAL;
-}
-
-static struct uart_ops sunhv_pops = {
-       .tx_empty       = sunhv_tx_empty,
-       .set_mctrl      = sunhv_set_mctrl,
-       .get_mctrl      = sunhv_get_mctrl,
-       .stop_tx        = sunhv_stop_tx,
-       .start_tx       = sunhv_start_tx,
-       .send_xchar     = sunhv_send_xchar,
-       .stop_rx        = sunhv_stop_rx,
-       .enable_ms      = sunhv_enable_ms,
-       .break_ctl      = sunhv_break_ctl,
-       .startup        = sunhv_startup,
-       .shutdown       = sunhv_shutdown,
-       .set_termios    = sunhv_set_termios,
-       .type           = sunhv_type,
-       .release_port   = sunhv_release_port,
-       .request_port   = sunhv_request_port,
-       .config_port    = sunhv_config_port,
-       .verify_port    = sunhv_verify_port,
-};
-
-static struct uart_driver sunhv_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "sunhv",
-       .dev_name               = "ttyS",
-       .major                  = TTY_MAJOR,
-};
-
-static struct uart_port *sunhv_port;
-
-/* Copy 's' into the con_write_page, decoding "\n" into
- * "\r\n" along the way.  We have to return two lengths
- * because the caller needs to know how much to advance
- * 's' and also how many bytes to output via con_write_page.
- */
-static int fill_con_write_page(const char *s, unsigned int n,
-                              unsigned long *page_bytes)
-{
-       const char *orig_s = s;
-       char *p = con_write_page;
-       int left = PAGE_SIZE;
-
-       while (n--) {
-               if (*s == '\n') {
-                       if (left < 2)
-                               break;
-                       *p++ = '\r';
-                       left--;
-               } else if (left < 1)
-                       break;
-               *p++ = *s++;
-               left--;
-       }
-       *page_bytes = p - con_write_page;
-       return s - orig_s;
-}
-
-static void sunhv_console_write_paged(struct console *con, const char *s, unsigned n)
-{
-       struct uart_port *port = sunhv_port;
-       unsigned long flags;
-       int locked = 1;
-
-       local_irq_save(flags);
-       if (port->sysrq) {
-               locked = 0;
-       } else if (oops_in_progress) {
-               locked = spin_trylock(&port->lock);
-       } else
-               spin_lock(&port->lock);
-
-       while (n > 0) {
-               unsigned long ra = __pa(con_write_page);
-               unsigned long page_bytes;
-               unsigned int cpy = fill_con_write_page(s, n,
-                                                      &page_bytes);
-
-               n -= cpy;
-               s += cpy;
-               while (page_bytes > 0) {
-                       unsigned long written;
-                       int limit = 1000000;
-
-                       while (limit--) {
-                               unsigned long stat;
-
-                               stat = sun4v_con_write(ra, page_bytes,
-                                                      &written);
-                               if (stat == HV_EOK)
-                                       break;
-                               udelay(1);
-                       }
-                       if (limit < 0)
-                               break;
-                       page_bytes -= written;
-                       ra += written;
-               }
-       }
-
-       if (locked)
-               spin_unlock(&port->lock);
-       local_irq_restore(flags);
-}
-
-static inline void sunhv_console_putchar(struct uart_port *port, char c)
-{
-       int limit = 1000000;
-
-       while (limit-- > 0) {
-               long status = sun4v_con_putchar(c);
-               if (status == HV_EOK)
-                       break;
-               udelay(1);
-       }
-}
-
-static void sunhv_console_write_bychar(struct console *con, const char *s, unsigned n)
-{
-       struct uart_port *port = sunhv_port;
-       unsigned long flags;
-       int i, locked = 1;
-
-       local_irq_save(flags);
-       if (port->sysrq) {
-               locked = 0;
-       } else if (oops_in_progress) {
-               locked = spin_trylock(&port->lock);
-       } else
-               spin_lock(&port->lock);
-
-       for (i = 0; i < n; i++) {
-               if (*s == '\n')
-                       sunhv_console_putchar(port, '\r');
-               sunhv_console_putchar(port, *s++);
-       }
-
-       if (locked)
-               spin_unlock(&port->lock);
-       local_irq_restore(flags);
-}
-
-static struct console sunhv_console = {
-       .name   =       "ttyHV",
-       .write  =       sunhv_console_write_bychar,
-       .device =       uart_console_device,
-       .flags  =       CON_PRINTBUFFER,
-       .index  =       -1,
-       .data   =       &sunhv_reg,
-};
-
-static int __devinit hv_probe(struct platform_device *op, const struct of_device_id *match)
-{
-       struct uart_port *port;
-       unsigned long minor;
-       int err;
-
-       if (op->archdata.irqs[0] == 0xffffffff)
-               return -ENODEV;
-
-       port = kzalloc(sizeof(struct uart_port), GFP_KERNEL);
-       if (unlikely(!port))
-               return -ENOMEM;
-
-       minor = 1;
-       if (sun4v_hvapi_register(HV_GRP_CORE, 1, &minor) == 0 &&
-           minor >= 1) {
-               err = -ENOMEM;
-               con_write_page = kzalloc(PAGE_SIZE, GFP_KERNEL);
-               if (!con_write_page)
-                       goto out_free_port;
-
-               con_read_page = kzalloc(PAGE_SIZE, GFP_KERNEL);
-               if (!con_read_page)
-                       goto out_free_con_write_page;
-
-               sunhv_console.write = sunhv_console_write_paged;
-               sunhv_ops = &bywrite_ops;
-       }
-
-       sunhv_port = port;
-
-       port->line = 0;
-       port->ops = &sunhv_pops;
-       port->type = PORT_SUNHV;
-       port->uartclk = ( 29491200 / 16 ); /* arbitrary */
-
-       port->membase = (unsigned char __iomem *) __pa(port);
-
-       port->irq = op->archdata.irqs[0];
-
-       port->dev = &op->dev;
-
-       err = sunserial_register_minors(&sunhv_reg, 1);
-       if (err)
-               goto out_free_con_read_page;
-
-       sunserial_console_match(&sunhv_console, op->dev.of_node,
-                               &sunhv_reg, port->line, false);
-
-       err = uart_add_one_port(&sunhv_reg, port);
-       if (err)
-               goto out_unregister_driver;
-
-       err = request_irq(port->irq, sunhv_interrupt, 0, "hvcons", port);
-       if (err)
-               goto out_remove_port;
-
-       dev_set_drvdata(&op->dev, port);
-
-       return 0;
-
-out_remove_port:
-       uart_remove_one_port(&sunhv_reg, port);
-
-out_unregister_driver:
-       sunserial_unregister_minors(&sunhv_reg, 1);
-
-out_free_con_read_page:
-       kfree(con_read_page);
-
-out_free_con_write_page:
-       kfree(con_write_page);
-
-out_free_port:
-       kfree(port);
-       sunhv_port = NULL;
-       return err;
-}
-
-static int __devexit hv_remove(struct platform_device *dev)
-{
-       struct uart_port *port = dev_get_drvdata(&dev->dev);
-
-       free_irq(port->irq, port);
-
-       uart_remove_one_port(&sunhv_reg, port);
-
-       sunserial_unregister_minors(&sunhv_reg, 1);
-
-       kfree(port);
-       sunhv_port = NULL;
-
-       dev_set_drvdata(&dev->dev, NULL);
-
-       return 0;
-}
-
-static const struct of_device_id hv_match[] = {
-       {
-               .name = "console",
-               .compatible = "qcn",
-       },
-       {
-               .name = "console",
-               .compatible = "SUNW,sun4v-console",
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(of, hv_match);
-
-static struct of_platform_driver hv_driver = {
-       .driver = {
-               .name = "hv",
-               .owner = THIS_MODULE,
-               .of_match_table = hv_match,
-       },
-       .probe          = hv_probe,
-       .remove         = __devexit_p(hv_remove),
-};
-
-static int __init sunhv_init(void)
-{
-       if (tlb_type != hypervisor)
-               return -ENODEV;
-
-       return of_register_platform_driver(&hv_driver);
-}
-
-static void __exit sunhv_exit(void)
-{
-       of_unregister_platform_driver(&hv_driver);
-}
-
-module_init(sunhv_init);
-module_exit(sunhv_exit);
-
-MODULE_AUTHOR("David S. Miller");
-MODULE_DESCRIPTION("SUN4V Hypervisor console driver");
-MODULE_VERSION("2.0");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
deleted file mode 100644 (file)
index 5b246b1..0000000
+++ /dev/null
@@ -1,1152 +0,0 @@
-/* sunsab.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
- *
- * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
- * Copyright (C) 2002, 2006  David S. Miller (davem@davemloft.net)
- *
- * Rewrote buffer handling to use CIRC(Circular Buffer) macros.
- *   Maxim Krasnyanskiy <maxk@qualcomm.com>
- *
- * Fixed to use tty_get_baud_rate, and to allow for arbitrary baud
- * rates to be programmed into the UART.  Also eliminated a lot of
- * duplicated code in the console setup.
- *   Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12
- *
- * Ported to new 2.5.x UART layer.
- *   David S. Miller <davem@davemloft.net>
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/circ_buf.h>
-#include <linux/serial.h>
-#include <linux/sysrq.h>
-#include <linux/console.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/of_device.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/prom.h>
-
-#if defined(CONFIG_SERIAL_SUNSAB_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
-#include "suncore.h"
-#include "sunsab.h"
-
-struct uart_sunsab_port {
-       struct uart_port                port;           /* Generic UART port    */
-       union sab82532_async_regs       __iomem *regs;  /* Chip registers       */
-       unsigned long                   irqflags;       /* IRQ state flags      */
-       int                             dsr;            /* Current DSR state    */
-       unsigned int                    cec_timeout;    /* Chip poll timeout... */
-       unsigned int                    tec_timeout;    /* likewise             */
-       unsigned char                   interrupt_mask0;/* ISR0 masking         */
-       unsigned char                   interrupt_mask1;/* ISR1 masking         */
-       unsigned char                   pvr_dtr_bit;    /* Which PVR bit is DTR */
-       unsigned char                   pvr_dsr_bit;    /* Which PVR bit is DSR */
-       unsigned int                    gis_shift;
-       int                             type;           /* SAB82532 version     */
-
-       /* Setting configuration bits while the transmitter is active
-        * can cause garbage characters to get emitted by the chip.
-        * Therefore, we cache such writes here and do the real register
-        * write the next time the transmitter becomes idle.
-        */
-       unsigned int                    cached_ebrg;
-       unsigned char                   cached_mode;
-       unsigned char                   cached_pvr;
-       unsigned char                   cached_dafo;
-};
-
-/*
- * This assumes you have a 29.4912 MHz clock for your UART.
- */
-#define SAB_BASE_BAUD ( 29491200 / 16 )
-
-static char *sab82532_version[16] = {
-       "V1.0", "V2.0", "V3.2", "V(0x03)",
-       "V(0x04)", "V(0x05)", "V(0x06)", "V(0x07)",
-       "V(0x08)", "V(0x09)", "V(0x0a)", "V(0x0b)",
-       "V(0x0c)", "V(0x0d)", "V(0x0e)", "V(0x0f)"
-};
-
-#define SAB82532_MAX_TEC_TIMEOUT 200000        /* 1 character time (at 50 baud) */
-#define SAB82532_MAX_CEC_TIMEOUT  50000        /* 2.5 TX CLKs (at 50 baud) */
-
-#define SAB82532_RECV_FIFO_SIZE        32      /* Standard async fifo sizes */
-#define SAB82532_XMIT_FIFO_SIZE        32
-
-static __inline__ void sunsab_tec_wait(struct uart_sunsab_port *up)
-{
-       int timeout = up->tec_timeout;
-
-       while ((readb(&up->regs->r.star) & SAB82532_STAR_TEC) && --timeout)
-               udelay(1);
-}
-
-static __inline__ void sunsab_cec_wait(struct uart_sunsab_port *up)
-{
-       int timeout = up->cec_timeout;
-
-       while ((readb(&up->regs->r.star) & SAB82532_STAR_CEC) && --timeout)
-               udelay(1);
-}
-
-static struct tty_struct *
-receive_chars(struct uart_sunsab_port *up,
-             union sab82532_irq_status *stat)
-{
-       struct tty_struct *tty = NULL;
-       unsigned char buf[32];
-       int saw_console_brk = 0;
-       int free_fifo = 0;
-       int count = 0;
-       int i;
-
-       if (up->port.state != NULL)             /* Unopened serial console */
-               tty = up->port.state->port.tty;
-
-       /* Read number of BYTES (Character + Status) available. */
-       if (stat->sreg.isr0 & SAB82532_ISR0_RPF) {
-               count = SAB82532_RECV_FIFO_SIZE;
-               free_fifo++;
-       }
-
-       if (stat->sreg.isr0 & SAB82532_ISR0_TCD) {
-               count = readb(&up->regs->r.rbcl) & (SAB82532_RECV_FIFO_SIZE - 1);
-               free_fifo++;
-       }
-
-       /* Issue a FIFO read command in case we where idle. */
-       if (stat->sreg.isr0 & SAB82532_ISR0_TIME) {
-               sunsab_cec_wait(up);
-               writeb(SAB82532_CMDR_RFRD, &up->regs->w.cmdr);
-               return tty;
-       }
-
-       if (stat->sreg.isr0 & SAB82532_ISR0_RFO)
-               free_fifo++;
-
-       /* Read the FIFO. */
-       for (i = 0; i < count; i++)
-               buf[i] = readb(&up->regs->r.rfifo[i]);
-
-       /* Issue Receive Message Complete command. */
-       if (free_fifo) {
-               sunsab_cec_wait(up);
-               writeb(SAB82532_CMDR_RMC, &up->regs->w.cmdr);
-       }
-
-       /* Count may be zero for BRK, so we check for it here */
-       if ((stat->sreg.isr1 & SAB82532_ISR1_BRK) &&
-           (up->port.line == up->port.cons->index))
-               saw_console_brk = 1;
-
-       for (i = 0; i < count; i++) {
-               unsigned char ch = buf[i], flag;
-
-               if (tty == NULL) {
-                       uart_handle_sysrq_char(&up->port, ch);
-                       continue;
-               }
-
-               flag = TTY_NORMAL;
-               up->port.icount.rx++;
-
-               if (unlikely(stat->sreg.isr0 & (SAB82532_ISR0_PERR |
-                                               SAB82532_ISR0_FERR |
-                                               SAB82532_ISR0_RFO)) ||
-                   unlikely(stat->sreg.isr1 & SAB82532_ISR1_BRK)) {
-                       /*
-                        * For statistics only
-                        */
-                       if (stat->sreg.isr1 & SAB82532_ISR1_BRK) {
-                               stat->sreg.isr0 &= ~(SAB82532_ISR0_PERR |
-                                                    SAB82532_ISR0_FERR);
-                               up->port.icount.brk++;
-                               /*
-                                * We do the SysRQ and SAK checking
-                                * here because otherwise the break
-                                * may get masked by ignore_status_mask
-                                * or read_status_mask.
-                                */
-                               if (uart_handle_break(&up->port))
-                                       continue;
-                       } else if (stat->sreg.isr0 & SAB82532_ISR0_PERR)
-                               up->port.icount.parity++;
-                       else if (stat->sreg.isr0 & SAB82532_ISR0_FERR)
-                               up->port.icount.frame++;
-                       if (stat->sreg.isr0 & SAB82532_ISR0_RFO)
-                               up->port.icount.overrun++;
-
-                       /*
-                        * Mask off conditions which should be ingored.
-                        */
-                       stat->sreg.isr0 &= (up->port.read_status_mask & 0xff);
-                       stat->sreg.isr1 &= ((up->port.read_status_mask >> 8) & 0xff);
-
-                       if (stat->sreg.isr1 & SAB82532_ISR1_BRK) {
-                               flag = TTY_BREAK;
-                       } else if (stat->sreg.isr0 & SAB82532_ISR0_PERR)
-                               flag = TTY_PARITY;
-                       else if (stat->sreg.isr0 & SAB82532_ISR0_FERR)
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(&up->port, ch))
-                       continue;
-
-               if ((stat->sreg.isr0 & (up->port.ignore_status_mask & 0xff)) == 0 &&
-                   (stat->sreg.isr1 & ((up->port.ignore_status_mask >> 8) & 0xff)) == 0)
-                       tty_insert_flip_char(tty, ch, flag);
-               if (stat->sreg.isr0 & SAB82532_ISR0_RFO)
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-       }
-
-       if (saw_console_brk)
-               sun_do_break();
-
-       return tty;
-}
-
-static void sunsab_stop_tx(struct uart_port *);
-static void sunsab_tx_idle(struct uart_sunsab_port *);
-
-static void transmit_chars(struct uart_sunsab_port *up,
-                          union sab82532_irq_status *stat)
-{
-       struct circ_buf *xmit = &up->port.state->xmit;
-       int i;
-
-       if (stat->sreg.isr1 & SAB82532_ISR1_ALLS) {
-               up->interrupt_mask1 |= SAB82532_IMR1_ALLS;
-               writeb(up->interrupt_mask1, &up->regs->w.imr1);
-               set_bit(SAB82532_ALLS, &up->irqflags);
-       }
-
-#if 0 /* bde@nwlink.com says this check causes problems */
-       if (!(stat->sreg.isr1 & SAB82532_ISR1_XPR))
-               return;
-#endif
-
-       if (!(readb(&up->regs->r.star) & SAB82532_STAR_XFW))
-               return;
-
-       set_bit(SAB82532_XPR, &up->irqflags);
-       sunsab_tx_idle(up);
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
-               up->interrupt_mask1 |= SAB82532_IMR1_XPR;
-               writeb(up->interrupt_mask1, &up->regs->w.imr1);
-               return;
-       }
-
-       up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR);
-       writeb(up->interrupt_mask1, &up->regs->w.imr1);
-       clear_bit(SAB82532_ALLS, &up->irqflags);
-
-       /* Stuff 32 bytes into Transmit FIFO. */
-       clear_bit(SAB82532_XPR, &up->irqflags);
-       for (i = 0; i < up->port.fifosize; i++) {
-               writeb(xmit->buf[xmit->tail],
-                      &up->regs->w.xfifo[i]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               up->port.icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       }
-
-       /* Issue a Transmit Frame command. */
-       sunsab_cec_wait(up);
-       writeb(SAB82532_CMDR_XF, &up->regs->w.cmdr);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&up->port);
-
-       if (uart_circ_empty(xmit))
-               sunsab_stop_tx(&up->port);
-}
-
-static void check_status(struct uart_sunsab_port *up,
-                        union sab82532_irq_status *stat)
-{
-       if (stat->sreg.isr0 & SAB82532_ISR0_CDSC)
-               uart_handle_dcd_change(&up->port,
-                                      !(readb(&up->regs->r.vstr) & SAB82532_VSTR_CD));
-
-       if (stat->sreg.isr1 & SAB82532_ISR1_CSC)
-               uart_handle_cts_change(&up->port,
-                                      (readb(&up->regs->r.star) & SAB82532_STAR_CTS));
-
-       if ((readb(&up->regs->r.pvr) & up->pvr_dsr_bit) ^ up->dsr) {
-               up->dsr = (readb(&up->regs->r.pvr) & up->pvr_dsr_bit) ? 0 : 1;
-               up->port.icount.dsr++;
-       }
-
-       wake_up_interruptible(&up->port.state->port.delta_msr_wait);
-}
-
-static irqreturn_t sunsab_interrupt(int irq, void *dev_id)
-{
-       struct uart_sunsab_port *up = dev_id;
-       struct tty_struct *tty;
-       union sab82532_irq_status status;
-       unsigned long flags;
-       unsigned char gis;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       status.stat = 0;
-       gis = readb(&up->regs->r.gis) >> up->gis_shift;
-       if (gis & 1)
-               status.sreg.isr0 = readb(&up->regs->r.isr0);
-       if (gis & 2)
-               status.sreg.isr1 = readb(&up->regs->r.isr1);
-
-       tty = NULL;
-       if (status.stat) {
-               if ((status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME |
-                                        SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) ||
-                   (status.sreg.isr1 & SAB82532_ISR1_BRK))
-                       tty = receive_chars(up, &status);
-               if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) ||
-                   (status.sreg.isr1 & SAB82532_ISR1_CSC))
-                       check_status(up, &status);
-               if (status.sreg.isr1 & (SAB82532_ISR1_ALLS | SAB82532_ISR1_XPR))
-                       transmit_chars(up, &status);
-       }
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       if (tty)
-               tty_flip_buffer_push(tty);
-
-       return IRQ_HANDLED;
-}
-
-/* port->lock is not held.  */
-static unsigned int sunsab_tx_empty(struct uart_port *port)
-{
-       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
-       int ret;
-
-       /* Do not need a lock for a state test like this.  */
-       if (test_bit(SAB82532_ALLS, &up->irqflags))
-               ret = TIOCSER_TEMT;
-       else
-               ret = 0;
-
-       return ret;
-}
-
-/* port->lock held by caller.  */
-static void sunsab_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
-
-       if (mctrl & TIOCM_RTS) {
-               up->cached_mode &= ~SAB82532_MODE_FRTS;
-               up->cached_mode |= SAB82532_MODE_RTS;
-       } else {
-               up->cached_mode |= (SAB82532_MODE_FRTS |
-                                   SAB82532_MODE_RTS);
-       }
-       if (mctrl & TIOCM_DTR) {
-               up->cached_pvr &= ~(up->pvr_dtr_bit);
-       } else {
-               up->cached_pvr |= up->pvr_dtr_bit;
-       }
-
-       set_bit(SAB82532_REGS_PENDING, &up->irqflags);
-       if (test_bit(SAB82532_XPR, &up->irqflags))
-               sunsab_tx_idle(up);
-}
-
-/* port->lock is held by caller and interrupts are disabled.  */
-static unsigned int sunsab_get_mctrl(struct uart_port *port)
-{
-       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
-       unsigned char val;
-       unsigned int result;
-
-       result = 0;
-
-       val = readb(&up->regs->r.pvr);
-       result |= (val & up->pvr_dsr_bit) ? 0 : TIOCM_DSR;
-
-       val = readb(&up->regs->r.vstr);
-       result |= (val & SAB82532_VSTR_CD) ? 0 : TIOCM_CAR;
-
-       val = readb(&up->regs->r.star);
-       result |= (val & SAB82532_STAR_CTS) ? TIOCM_CTS : 0;
-
-       return result;
-}
-
-/* port->lock held by caller.  */
-static void sunsab_stop_tx(struct uart_port *port)
-{
-       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
-
-       up->interrupt_mask1 |= SAB82532_IMR1_XPR;
-       writeb(up->interrupt_mask1, &up->regs->w.imr1);
-}
-
-/* port->lock held by caller.  */
-static void sunsab_tx_idle(struct uart_sunsab_port *up)
-{
-       if (test_bit(SAB82532_REGS_PENDING, &up->irqflags)) {
-               u8 tmp;
-
-               clear_bit(SAB82532_REGS_PENDING, &up->irqflags);
-               writeb(up->cached_mode, &up->regs->rw.mode);
-               writeb(up->cached_pvr, &up->regs->rw.pvr);
-               writeb(up->cached_dafo, &up->regs->w.dafo);
-
-               writeb(up->cached_ebrg & 0xff, &up->regs->w.bgr);
-               tmp = readb(&up->regs->rw.ccr2);
-               tmp &= ~0xc0;
-               tmp |= (up->cached_ebrg >> 2) & 0xc0;
-               writeb(tmp, &up->regs->rw.ccr2);
-       }
-}
-
-/* port->lock held by caller.  */
-static void sunsab_start_tx(struct uart_port *port)
-{
-       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
-       struct circ_buf *xmit = &up->port.state->xmit;
-       int i;
-
-       up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR);
-       writeb(up->interrupt_mask1, &up->regs->w.imr1);
-       
-       if (!test_bit(SAB82532_XPR, &up->irqflags))
-               return;
-
-       clear_bit(SAB82532_ALLS, &up->irqflags);
-       clear_bit(SAB82532_XPR, &up->irqflags);
-
-       for (i = 0; i < up->port.fifosize; i++) {
-               writeb(xmit->buf[xmit->tail],
-                      &up->regs->w.xfifo[i]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               up->port.icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       }
-
-       /* Issue a Transmit Frame command.  */
-       sunsab_cec_wait(up);
-       writeb(SAB82532_CMDR_XF, &up->regs->w.cmdr);
-}
-
-/* port->lock is not held.  */
-static void sunsab_send_xchar(struct uart_port *port, char ch)
-{
-       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
-       unsigned long flags;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       sunsab_tec_wait(up);
-       writeb(ch, &up->regs->w.tic);
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-/* port->lock held by caller.  */
-static void sunsab_stop_rx(struct uart_port *port)
-{
-       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
-
-       up->interrupt_mask0 |= SAB82532_IMR0_TCD;
-       writeb(up->interrupt_mask1, &up->regs->w.imr0);
-}
-
-/* port->lock held by caller.  */
-static void sunsab_enable_ms(struct uart_port *port)
-{
-       /* For now we always receive these interrupts.  */
-}
-
-/* port->lock is not held.  */
-static void sunsab_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
-       unsigned long flags;
-       unsigned char val;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       val = up->cached_dafo;
-       if (break_state)
-               val |= SAB82532_DAFO_XBRK;
-       else
-               val &= ~SAB82532_DAFO_XBRK;
-       up->cached_dafo = val;
-
-       set_bit(SAB82532_REGS_PENDING, &up->irqflags);
-       if (test_bit(SAB82532_XPR, &up->irqflags))
-               sunsab_tx_idle(up);
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-/* port->lock is not held.  */
-static int sunsab_startup(struct uart_port *port)
-{
-       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
-       unsigned long flags;
-       unsigned char tmp;
-       int err = request_irq(up->port.irq, sunsab_interrupt,
-                             IRQF_SHARED, "sab", up);
-       if (err)
-               return err;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       /*
-        * Wait for any commands or immediate characters
-        */
-       sunsab_cec_wait(up);
-       sunsab_tec_wait(up);
-
-       /*
-        * Clear the FIFO buffers.
-        */
-       writeb(SAB82532_CMDR_RRES, &up->regs->w.cmdr);
-       sunsab_cec_wait(up);
-       writeb(SAB82532_CMDR_XRES, &up->regs->w.cmdr);
-
-       /*
-        * Clear the interrupt registers.
-        */
-       (void) readb(&up->regs->r.isr0);
-       (void) readb(&up->regs->r.isr1);
-
-       /*
-        * Now, initialize the UART 
-        */
-       writeb(0, &up->regs->w.ccr0);                           /* power-down */
-       writeb(SAB82532_CCR0_MCE | SAB82532_CCR0_SC_NRZ |
-              SAB82532_CCR0_SM_ASYNC, &up->regs->w.ccr0);
-       writeb(SAB82532_CCR1_ODS | SAB82532_CCR1_BCR | 7, &up->regs->w.ccr1);
-       writeb(SAB82532_CCR2_BDF | SAB82532_CCR2_SSEL |
-              SAB82532_CCR2_TOE, &up->regs->w.ccr2);
-       writeb(0, &up->regs->w.ccr3);
-       writeb(SAB82532_CCR4_MCK4 | SAB82532_CCR4_EBRG, &up->regs->w.ccr4);
-       up->cached_mode = (SAB82532_MODE_RTS | SAB82532_MODE_FCTS |
-                          SAB82532_MODE_RAC);
-       writeb(up->cached_mode, &up->regs->w.mode);
-       writeb(SAB82532_RFC_DPS|SAB82532_RFC_RFTH_32, &up->regs->w.rfc);
-       
-       tmp = readb(&up->regs->rw.ccr0);
-       tmp |= SAB82532_CCR0_PU;        /* power-up */
-       writeb(tmp, &up->regs->rw.ccr0);
-
-       /*
-        * Finally, enable interrupts
-        */
-       up->interrupt_mask0 = (SAB82532_IMR0_PERR | SAB82532_IMR0_FERR |
-                              SAB82532_IMR0_PLLA);
-       writeb(up->interrupt_mask0, &up->regs->w.imr0);
-       up->interrupt_mask1 = (SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS |
-                              SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN |
-                              SAB82532_IMR1_CSC | SAB82532_IMR1_XON |
-                              SAB82532_IMR1_XPR);
-       writeb(up->interrupt_mask1, &up->regs->w.imr1);
-       set_bit(SAB82532_ALLS, &up->irqflags);
-       set_bit(SAB82532_XPR, &up->irqflags);
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       return 0;
-}
-
-/* port->lock is not held.  */
-static void sunsab_shutdown(struct uart_port *port)
-{
-       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
-       unsigned long flags;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       /* Disable Interrupts */
-       up->interrupt_mask0 = 0xff;
-       writeb(up->interrupt_mask0, &up->regs->w.imr0);
-       up->interrupt_mask1 = 0xff;
-       writeb(up->interrupt_mask1, &up->regs->w.imr1);
-
-       /* Disable break condition */
-       up->cached_dafo = readb(&up->regs->rw.dafo);
-       up->cached_dafo &= ~SAB82532_DAFO_XBRK;
-       writeb(up->cached_dafo, &up->regs->rw.dafo);
-
-       /* Disable Receiver */  
-       up->cached_mode &= ~SAB82532_MODE_RAC;
-       writeb(up->cached_mode, &up->regs->rw.mode);
-
-       /*
-        * XXX FIXME
-        *
-        * If the chip is powered down here the system hangs/crashes during
-        * reboot or shutdown.  This needs to be investigated further,
-        * similar behaviour occurs in 2.4 when the driver is configured
-        * as a module only.  One hint may be that data is sometimes
-        * transmitted at 9600 baud during shutdown (regardless of the
-        * speed the chip was configured for when the port was open).
-        */
-#if 0
-       /* Power Down */        
-       tmp = readb(&up->regs->rw.ccr0);
-       tmp &= ~SAB82532_CCR0_PU;
-       writeb(tmp, &up->regs->rw.ccr0);
-#endif
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-       free_irq(up->port.irq, up);
-}
-
-/*
- * This is used to figure out the divisor speeds.
- *
- * The formula is:    Baud = SAB_BASE_BAUD / ((N + 1) * (1 << M)),
- *
- * with               0 <= N < 64 and 0 <= M < 16
- */
-
-static void calc_ebrg(int baud, int *n_ret, int *m_ret)
-{
-       int     n, m;
-
-       if (baud == 0) {
-               *n_ret = 0;
-               *m_ret = 0;
-               return;
-       }
-     
-       /*
-        * We scale numbers by 10 so that we get better accuracy
-        * without having to use floating point.  Here we increment m
-        * until n is within the valid range.
-        */
-       n = (SAB_BASE_BAUD * 10) / baud;
-       m = 0;
-       while (n >= 640) {
-               n = n / 2;
-               m++;
-       }
-       n = (n+5) / 10;
-       /*
-        * We try very hard to avoid speeds with M == 0 since they may
-        * not work correctly for XTAL frequences above 10 MHz.
-        */
-       if ((m == 0) && ((n & 1) == 0)) {
-               n = n / 2;
-               m++;
-       }
-       *n_ret = n - 1;
-       *m_ret = m;
-}
-
-/* Internal routine, port->lock is held and local interrupts are disabled.  */
-static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cflag,
-                                 unsigned int iflag, unsigned int baud,
-                                 unsigned int quot)
-{
-       unsigned char dafo;
-       int bits, n, m;
-
-       /* Byte size and parity */
-       switch (cflag & CSIZE) {
-             case CS5: dafo = SAB82532_DAFO_CHL5; bits = 7; break;
-             case CS6: dafo = SAB82532_DAFO_CHL6; bits = 8; break;
-             case CS7: dafo = SAB82532_DAFO_CHL7; bits = 9; break;
-             case CS8: dafo = SAB82532_DAFO_CHL8; bits = 10; break;
-             /* Never happens, but GCC is too dumb to figure it out */
-             default:  dafo = SAB82532_DAFO_CHL5; bits = 7; break;
-       }
-
-       if (cflag & CSTOPB) {
-               dafo |= SAB82532_DAFO_STOP;
-               bits++;
-       }
-
-       if (cflag & PARENB) {
-               dafo |= SAB82532_DAFO_PARE;
-               bits++;
-       }
-
-       if (cflag & PARODD) {
-               dafo |= SAB82532_DAFO_PAR_ODD;
-       } else {
-               dafo |= SAB82532_DAFO_PAR_EVEN;
-       }
-       up->cached_dafo = dafo;
-
-       calc_ebrg(baud, &n, &m);
-
-       up->cached_ebrg = n | (m << 6);
-
-       up->tec_timeout = (10 * 1000000) / baud;
-       up->cec_timeout = up->tec_timeout >> 2;
-
-       /* CTS flow control flags */
-       /* We encode read_status_mask and ignore_status_mask like so:
-        *
-        * ---------------------
-        * | ... | ISR1 | ISR0 |
-        * ---------------------
-        *  ..    15   8 7    0
-        */
-
-       up->port.read_status_mask = (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME |
-                                    SAB82532_ISR0_RFO | SAB82532_ISR0_RPF |
-                                    SAB82532_ISR0_CDSC);
-       up->port.read_status_mask |= (SAB82532_ISR1_CSC |
-                                     SAB82532_ISR1_ALLS |
-                                     SAB82532_ISR1_XPR) << 8;
-       if (iflag & INPCK)
-               up->port.read_status_mask |= (SAB82532_ISR0_PERR |
-                                             SAB82532_ISR0_FERR);
-       if (iflag & (BRKINT | PARMRK))
-               up->port.read_status_mask |= (SAB82532_ISR1_BRK << 8);
-
-       /*
-        * Characteres to ignore
-        */
-       up->port.ignore_status_mask = 0;
-       if (iflag & IGNPAR)
-               up->port.ignore_status_mask |= (SAB82532_ISR0_PERR |
-                                               SAB82532_ISR0_FERR);
-       if (iflag & IGNBRK) {
-               up->port.ignore_status_mask |= (SAB82532_ISR1_BRK << 8);
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (iflag & IGNPAR)
-                       up->port.ignore_status_mask |= SAB82532_ISR0_RFO;
-       }
-
-       /*
-        * ignore all characters if CREAD is not set
-        */
-       if ((cflag & CREAD) == 0)
-               up->port.ignore_status_mask |= (SAB82532_ISR0_RPF |
-                                               SAB82532_ISR0_TCD);
-
-       uart_update_timeout(&up->port, cflag,
-                           (up->port.uartclk / (16 * quot)));
-
-       /* Now schedule a register update when the chip's
-        * transmitter is idle.
-        */
-       up->cached_mode |= SAB82532_MODE_RAC;
-       set_bit(SAB82532_REGS_PENDING, &up->irqflags);
-       if (test_bit(SAB82532_XPR, &up->irqflags))
-               sunsab_tx_idle(up);
-}
-
-/* port->lock is not held.  */
-static void sunsab_set_termios(struct uart_port *port, struct ktermios *termios,
-                              struct ktermios *old)
-{
-       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
-       unsigned long flags;
-       unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
-       unsigned int quot = uart_get_divisor(port, baud);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       sunsab_convert_to_sab(up, termios->c_cflag, termios->c_iflag, baud, quot);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static const char *sunsab_type(struct uart_port *port)
-{
-       struct uart_sunsab_port *up = (void *)port;
-       static char buf[36];
-       
-       sprintf(buf, "SAB82532 %s", sab82532_version[up->type]);
-       return buf;
-}
-
-static void sunsab_release_port(struct uart_port *port)
-{
-}
-
-static int sunsab_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-static void sunsab_config_port(struct uart_port *port, int flags)
-{
-}
-
-static int sunsab_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       return -EINVAL;
-}
-
-static struct uart_ops sunsab_pops = {
-       .tx_empty       = sunsab_tx_empty,
-       .set_mctrl      = sunsab_set_mctrl,
-       .get_mctrl      = sunsab_get_mctrl,
-       .stop_tx        = sunsab_stop_tx,
-       .start_tx       = sunsab_start_tx,
-       .send_xchar     = sunsab_send_xchar,
-       .stop_rx        = sunsab_stop_rx,
-       .enable_ms      = sunsab_enable_ms,
-       .break_ctl      = sunsab_break_ctl,
-       .startup        = sunsab_startup,
-       .shutdown       = sunsab_shutdown,
-       .set_termios    = sunsab_set_termios,
-       .type           = sunsab_type,
-       .release_port   = sunsab_release_port,
-       .request_port   = sunsab_request_port,
-       .config_port    = sunsab_config_port,
-       .verify_port    = sunsab_verify_port,
-};
-
-static struct uart_driver sunsab_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "sunsab",
-       .dev_name               = "ttyS",
-       .major                  = TTY_MAJOR,
-};
-
-static struct uart_sunsab_port *sunsab_ports;
-
-#ifdef CONFIG_SERIAL_SUNSAB_CONSOLE
-
-static void sunsab_console_putchar(struct uart_port *port, int c)
-{
-       struct uart_sunsab_port *up = (struct uart_sunsab_port *)port;
-
-       sunsab_tec_wait(up);
-       writeb(c, &up->regs->w.tic);
-}
-
-static void sunsab_console_write(struct console *con, const char *s, unsigned n)
-{
-       struct uart_sunsab_port *up = &sunsab_ports[con->index];
-       unsigned long flags;
-       int locked = 1;
-
-       local_irq_save(flags);
-       if (up->port.sysrq) {
-               locked = 0;
-       } else if (oops_in_progress) {
-               locked = spin_trylock(&up->port.lock);
-       } else
-               spin_lock(&up->port.lock);
-
-       uart_console_write(&up->port, s, n, sunsab_console_putchar);
-       sunsab_tec_wait(up);
-
-       if (locked)
-               spin_unlock(&up->port.lock);
-       local_irq_restore(flags);
-}
-
-static int sunsab_console_setup(struct console *con, char *options)
-{
-       struct uart_sunsab_port *up = &sunsab_ports[con->index];
-       unsigned long flags;
-       unsigned int baud, quot;
-
-       /*
-        * The console framework calls us for each and every port
-        * registered. Defer the console setup until the requested
-        * port has been properly discovered. A bit of a hack,
-        * though...
-        */
-       if (up->port.type != PORT_SUNSAB)
-               return -1;
-
-       printk("Console: ttyS%d (SAB82532)\n",
-              (sunsab_reg.minor - 64) + con->index);
-
-       sunserial_console_termios(con, up->port.dev->of_node);
-
-       switch (con->cflag & CBAUD) {
-       case B150: baud = 150; break;
-       case B300: baud = 300; break;
-       case B600: baud = 600; break;
-       case B1200: baud = 1200; break;
-       case B2400: baud = 2400; break;
-       case B4800: baud = 4800; break;
-       default: case B9600: baud = 9600; break;
-       case B19200: baud = 19200; break;
-       case B38400: baud = 38400; break;
-       case B57600: baud = 57600; break;
-       case B115200: baud = 115200; break;
-       case B230400: baud = 230400; break;
-       case B460800: baud = 460800; break;
-       };
-
-       /*
-        * Temporary fix.
-        */
-       spin_lock_init(&up->port.lock);
-
-       /*
-        * Initialize the hardware
-        */
-       sunsab_startup(&up->port);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       /*
-        * Finally, enable interrupts
-        */
-       up->interrupt_mask0 = SAB82532_IMR0_PERR | SAB82532_IMR0_FERR |
-                               SAB82532_IMR0_PLLA | SAB82532_IMR0_CDSC;
-       writeb(up->interrupt_mask0, &up->regs->w.imr0);
-       up->interrupt_mask1 = SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS |
-                               SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN |
-                               SAB82532_IMR1_CSC | SAB82532_IMR1_XON |
-                               SAB82532_IMR1_XPR;
-       writeb(up->interrupt_mask1, &up->regs->w.imr1);
-
-       quot = uart_get_divisor(&up->port, baud);
-       sunsab_convert_to_sab(up, con->cflag, 0, baud, quot);
-       sunsab_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-       
-       return 0;
-}
-
-static struct console sunsab_console = {
-       .name   =       "ttyS",
-       .write  =       sunsab_console_write,
-       .device =       uart_console_device,
-       .setup  =       sunsab_console_setup,
-       .flags  =       CON_PRINTBUFFER,
-       .index  =       -1,
-       .data   =       &sunsab_reg,
-};
-
-static inline struct console *SUNSAB_CONSOLE(void)
-{
-       return &sunsab_console;
-}
-#else
-#define SUNSAB_CONSOLE()       (NULL)
-#define sunsab_console_init()  do { } while (0)
-#endif
-
-static int __devinit sunsab_init_one(struct uart_sunsab_port *up,
-                                    struct platform_device *op,
-                                    unsigned long offset,
-                                    int line)
-{
-       up->port.line = line;
-       up->port.dev = &op->dev;
-
-       up->port.mapbase = op->resource[0].start + offset;
-       up->port.membase = of_ioremap(&op->resource[0], offset,
-                                     sizeof(union sab82532_async_regs),
-                                     "sab");
-       if (!up->port.membase)
-               return -ENOMEM;
-       up->regs = (union sab82532_async_regs __iomem *) up->port.membase;
-
-       up->port.irq = op->archdata.irqs[0];
-
-       up->port.fifosize = SAB82532_XMIT_FIFO_SIZE;
-       up->port.iotype = UPIO_MEM;
-
-       writeb(SAB82532_IPC_IC_ACT_LOW, &up->regs->w.ipc);
-
-       up->port.ops = &sunsab_pops;
-       up->port.type = PORT_SUNSAB;
-       up->port.uartclk = SAB_BASE_BAUD;
-
-       up->type = readb(&up->regs->r.vstr) & 0x0f;
-       writeb(~((1 << 1) | (1 << 2) | (1 << 4)), &up->regs->w.pcr);
-       writeb(0xff, &up->regs->w.pim);
-       if ((up->port.line & 0x1) == 0) {
-               up->pvr_dsr_bit = (1 << 0);
-               up->pvr_dtr_bit = (1 << 1);
-               up->gis_shift = 2;
-       } else {
-               up->pvr_dsr_bit = (1 << 3);
-               up->pvr_dtr_bit = (1 << 2);
-               up->gis_shift = 0;
-       }
-       up->cached_pvr = (1 << 1) | (1 << 2) | (1 << 4);
-       writeb(up->cached_pvr, &up->regs->w.pvr);
-       up->cached_mode = readb(&up->regs->rw.mode);
-       up->cached_mode |= SAB82532_MODE_FRTS;
-       writeb(up->cached_mode, &up->regs->rw.mode);
-       up->cached_mode |= SAB82532_MODE_RTS;
-       writeb(up->cached_mode, &up->regs->rw.mode);
-
-       up->tec_timeout = SAB82532_MAX_TEC_TIMEOUT;
-       up->cec_timeout = SAB82532_MAX_CEC_TIMEOUT;
-
-       return 0;
-}
-
-static int __devinit sab_probe(struct platform_device *op, const struct of_device_id *match)
-{
-       static int inst;
-       struct uart_sunsab_port *up;
-       int err;
-
-       up = &sunsab_ports[inst * 2];
-
-       err = sunsab_init_one(&up[0], op,
-                             0,
-                             (inst * 2) + 0);
-       if (err)
-               goto out;
-
-       err = sunsab_init_one(&up[1], op,
-                             sizeof(union sab82532_async_regs),
-                             (inst * 2) + 1);
-       if (err)
-               goto out1;
-
-       sunserial_console_match(SUNSAB_CONSOLE(), op->dev.of_node,
-                               &sunsab_reg, up[0].port.line,
-                               false);
-
-       sunserial_console_match(SUNSAB_CONSOLE(), op->dev.of_node,
-                               &sunsab_reg, up[1].port.line,
-                               false);
-
-       err = uart_add_one_port(&sunsab_reg, &up[0].port);
-       if (err)
-               goto out2;
-
-       err = uart_add_one_port(&sunsab_reg, &up[1].port);
-       if (err)
-               goto out3;
-
-       dev_set_drvdata(&op->dev, &up[0]);
-
-       inst++;
-
-       return 0;
-
-out3:
-       uart_remove_one_port(&sunsab_reg, &up[0].port);
-out2:
-       of_iounmap(&op->resource[0],
-                  up[1].port.membase,
-                  sizeof(union sab82532_async_regs));
-out1:
-       of_iounmap(&op->resource[0],
-                  up[0].port.membase,
-                  sizeof(union sab82532_async_regs));
-out:
-       return err;
-}
-
-static int __devexit sab_remove(struct platform_device *op)
-{
-       struct uart_sunsab_port *up = dev_get_drvdata(&op->dev);
-
-       uart_remove_one_port(&sunsab_reg, &up[1].port);
-       uart_remove_one_port(&sunsab_reg, &up[0].port);
-       of_iounmap(&op->resource[0],
-                  up[1].port.membase,
-                  sizeof(union sab82532_async_regs));
-       of_iounmap(&op->resource[0],
-                  up[0].port.membase,
-                  sizeof(union sab82532_async_regs));
-
-       dev_set_drvdata(&op->dev, NULL);
-
-       return 0;
-}
-
-static const struct of_device_id sab_match[] = {
-       {
-               .name = "se",
-       },
-       {
-               .name = "serial",
-               .compatible = "sab82532",
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(of, sab_match);
-
-static struct of_platform_driver sab_driver = {
-       .driver = {
-               .name = "sab",
-               .owner = THIS_MODULE,
-               .of_match_table = sab_match,
-       },
-       .probe          = sab_probe,
-       .remove         = __devexit_p(sab_remove),
-};
-
-static int __init sunsab_init(void)
-{
-       struct device_node *dp;
-       int err;
-       int num_channels = 0;
-
-       for_each_node_by_name(dp, "se")
-               num_channels += 2;
-       for_each_node_by_name(dp, "serial") {
-               if (of_device_is_compatible(dp, "sab82532"))
-                       num_channels += 2;
-       }
-
-       if (num_channels) {
-               sunsab_ports = kzalloc(sizeof(struct uart_sunsab_port) *
-                                      num_channels, GFP_KERNEL);
-               if (!sunsab_ports)
-                       return -ENOMEM;
-
-               err = sunserial_register_minors(&sunsab_reg, num_channels);
-               if (err) {
-                       kfree(sunsab_ports);
-                       sunsab_ports = NULL;
-
-                       return err;
-               }
-       }
-
-       return of_register_platform_driver(&sab_driver);
-}
-
-static void __exit sunsab_exit(void)
-{
-       of_unregister_platform_driver(&sab_driver);
-       if (sunsab_reg.nr) {
-               sunserial_unregister_minors(&sunsab_reg, sunsab_reg.nr);
-       }
-
-       kfree(sunsab_ports);
-       sunsab_ports = NULL;
-}
-
-module_init(sunsab_init);
-module_exit(sunsab_exit);
-
-MODULE_AUTHOR("Eddie C. Dost and David S. Miller");
-MODULE_DESCRIPTION("Sun SAB82532 serial port driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/sunsab.h b/drivers/serial/sunsab.h
deleted file mode 100644 (file)
index b78e1f7..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-/* sunsab.h: Register Definitions for the Siemens SAB82532 DUSCC
- *
- * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
- */
-
-#ifndef _SUNSAB_H
-#define _SUNSAB_H
-
-struct sab82532_async_rd_regs {
-       u8      rfifo[0x20];    /* Receive FIFO                         */
-       u8      star;           /* Status Register                      */
-       u8      __pad1;
-       u8      mode;           /* Mode Register                        */
-       u8      timr;           /* Timer Register                       */
-       u8      xon;            /* XON Character                        */
-       u8      xoff;           /* XOFF Character                       */
-       u8      tcr;            /* Termination Character Register       */
-       u8      dafo;           /* Data Format                          */
-       u8      rfc;            /* RFIFO Control Register               */
-       u8      __pad2;
-       u8      rbcl;           /* Receive Byte Count Low               */
-       u8      rbch;           /* Receive Byte Count High              */
-       u8      ccr0;           /* Channel Configuration Register 0     */
-       u8      ccr1;           /* Channel Configuration Register 1     */
-       u8      ccr2;           /* Channel Configuration Register 2     */
-       u8      ccr3;           /* Channel Configuration Register 3     */
-       u8      __pad3[4];
-       u8      vstr;           /* Version Status Register              */
-       u8      __pad4[3];
-       u8      gis;            /* Global Interrupt Status              */
-       u8      ipc;            /* Interrupt Port Configuration         */
-       u8      isr0;           /* Interrupt Status 0                   */
-       u8      isr1;           /* Interrupt Status 1                   */
-       u8      pvr;            /* Port Value Register                  */
-       u8      pis;            /* Port Interrupt Status                */
-       u8      pcr;            /* Port Configuration Register          */
-       u8      ccr4;           /* Channel Configuration Register 4     */
-};
-
-struct sab82532_async_wr_regs {
-       u8      xfifo[0x20];    /* Transmit FIFO                        */
-       u8      cmdr;           /* Command Register                     */
-       u8      __pad1;
-       u8      mode;
-       u8      timr;
-       u8      xon;
-       u8      xoff;
-       u8      tcr;
-       u8      dafo;
-       u8      rfc;
-       u8      __pad2;
-       u8      xbcl;           /* Transmit Byte Count Low              */
-       u8      xbch;           /* Transmit Byte Count High             */
-       u8      ccr0;
-       u8      ccr1;
-       u8      ccr2;
-       u8      ccr3;
-       u8      tsax;           /* Time-Slot Assignment Reg. Transmit   */
-       u8      tsar;           /* Time-Slot Assignment Reg. Receive    */
-       u8      xccr;           /* Transmit Channel Capacity Register   */
-       u8      rccr;           /* Receive Channel Capacity Register    */
-       u8      bgr;            /* Baud Rate Generator Register         */
-       u8      tic;            /* Transmit Immediate Character         */
-       u8      mxn;            /* Mask XON Character                   */
-       u8      mxf;            /* Mask XOFF Character                  */
-       u8      iva;            /* Interrupt Vector Address             */
-       u8      ipc;
-       u8      imr0;           /* Interrupt Mask Register 0            */
-       u8      imr1;           /* Interrupt Mask Register 1            */
-       u8      pvr;
-       u8      pim;            /* Port Interrupt Mask                  */
-       u8      pcr;
-       u8      ccr4;
-};
-
-struct sab82532_async_rw_regs {        /* Read/Write registers                 */
-       u8      __pad1[0x20];
-       u8      __pad2;
-       u8      __pad3;
-       u8      mode;
-       u8      timr;
-       u8      xon;
-       u8      xoff;
-       u8      tcr;
-       u8      dafo;
-       u8      rfc;
-       u8      __pad4;
-       u8      __pad5;
-       u8      __pad6;
-       u8      ccr0;
-       u8      ccr1;
-       u8      ccr2;
-       u8      ccr3;
-       u8      __pad7;
-       u8      __pad8;
-       u8      __pad9;
-       u8      __pad10;
-       u8      __pad11;
-       u8      __pad12;
-       u8      __pad13;
-       u8      __pad14;
-       u8      __pad15;
-       u8      ipc;
-       u8      __pad16;
-       u8      __pad17;
-       u8      pvr;
-       u8      __pad18;
-       u8      pcr;
-       u8      ccr4;
-};
-
-union sab82532_async_regs {
-       __volatile__ struct sab82532_async_rd_regs      r;
-       __volatile__ struct sab82532_async_wr_regs      w;
-       __volatile__ struct sab82532_async_rw_regs      rw;
-};
-
-union sab82532_irq_status {
-       unsigned short                   stat;
-       struct {
-               unsigned char            isr0;
-               unsigned char            isr1;
-       } sreg;
-};
-
-/* irqflags bits */
-#define SAB82532_ALLS                  0x00000001
-#define SAB82532_XPR                   0x00000002
-#define SAB82532_REGS_PENDING          0x00000004
-
-/* RFIFO Status Byte */
-#define SAB82532_RSTAT_PE              0x80
-#define SAB82532_RSTAT_FE              0x40
-#define SAB82532_RSTAT_PARITY          0x01
-
-/* Status Register (STAR) */
-#define SAB82532_STAR_XDOV             0x80
-#define SAB82532_STAR_XFW              0x40
-#define SAB82532_STAR_RFNE             0x20
-#define SAB82532_STAR_FCS              0x10
-#define SAB82532_STAR_TEC              0x08
-#define SAB82532_STAR_CEC              0x04
-#define SAB82532_STAR_CTS              0x02
-
-/* Command Register (CMDR) */
-#define SAB82532_CMDR_RMC              0x80
-#define SAB82532_CMDR_RRES             0x40
-#define SAB82532_CMDR_RFRD             0x20
-#define SAB82532_CMDR_STI              0x10
-#define SAB82532_CMDR_XF               0x08
-#define SAB82532_CMDR_XRES             0x01
-
-/* Mode Register (MODE) */
-#define SAB82532_MODE_FRTS             0x40
-#define SAB82532_MODE_FCTS             0x20
-#define SAB82532_MODE_FLON             0x10
-#define SAB82532_MODE_RAC              0x08
-#define SAB82532_MODE_RTS              0x04
-#define SAB82532_MODE_TRS              0x02
-#define SAB82532_MODE_TLP              0x01
-
-/* Timer Register (TIMR) */
-#define SAB82532_TIMR_CNT_MASK         0xe0
-#define SAB82532_TIMR_VALUE_MASK       0x1f
-
-/* Data Format (DAFO) */
-#define SAB82532_DAFO_XBRK             0x40
-#define SAB82532_DAFO_STOP             0x20
-#define SAB82532_DAFO_PAR_SPACE                0x00
-#define SAB82532_DAFO_PAR_ODD          0x08
-#define SAB82532_DAFO_PAR_EVEN         0x10
-#define SAB82532_DAFO_PAR_MARK         0x18
-#define SAB82532_DAFO_PARE             0x04
-#define SAB82532_DAFO_CHL8             0x00
-#define SAB82532_DAFO_CHL7             0x01
-#define SAB82532_DAFO_CHL6             0x02
-#define SAB82532_DAFO_CHL5             0x03
-
-/* RFIFO Control Register (RFC) */
-#define SAB82532_RFC_DPS               0x40
-#define SAB82532_RFC_DXS               0x20
-#define SAB82532_RFC_RFDF              0x10
-#define SAB82532_RFC_RFTH_1            0x00
-#define SAB82532_RFC_RFTH_4            0x04
-#define SAB82532_RFC_RFTH_16           0x08
-#define SAB82532_RFC_RFTH_32           0x0c
-#define SAB82532_RFC_TCDE              0x01
-
-/* Received Byte Count High (RBCH) */
-#define SAB82532_RBCH_DMA              0x80
-#define SAB82532_RBCH_CAS              0x20
-
-/* Transmit Byte Count High (XBCH) */
-#define SAB82532_XBCH_DMA              0x80
-#define SAB82532_XBCH_CAS              0x20
-#define SAB82532_XBCH_XC               0x10
-
-/* Channel Configuration Register 0 (CCR0) */
-#define SAB82532_CCR0_PU               0x80
-#define SAB82532_CCR0_MCE              0x40
-#define SAB82532_CCR0_SC_NRZ           0x00
-#define SAB82532_CCR0_SC_NRZI          0x08
-#define SAB82532_CCR0_SC_FM0           0x10
-#define SAB82532_CCR0_SC_FM1           0x14
-#define SAB82532_CCR0_SC_MANCH         0x18
-#define SAB82532_CCR0_SM_HDLC          0x00
-#define SAB82532_CCR0_SM_SDLC_LOOP     0x01
-#define SAB82532_CCR0_SM_BISYNC                0x02
-#define SAB82532_CCR0_SM_ASYNC         0x03
-
-/* Channel Configuration Register 1 (CCR1) */
-#define SAB82532_CCR1_ODS              0x10
-#define SAB82532_CCR1_BCR              0x08
-#define SAB82532_CCR1_CM_MASK          0x07
-
-/* Channel Configuration Register 2 (CCR2) */
-#define SAB82532_CCR2_SOC1             0x80
-#define SAB82532_CCR2_SOC0             0x40
-#define SAB82532_CCR2_BR9              0x80
-#define SAB82532_CCR2_BR8              0x40
-#define SAB82532_CCR2_BDF              0x20
-#define SAB82532_CCR2_SSEL             0x10
-#define SAB82532_CCR2_XCS0             0x20
-#define SAB82532_CCR2_RCS0             0x10
-#define SAB82532_CCR2_TOE              0x08
-#define SAB82532_CCR2_RWX              0x04
-#define SAB82532_CCR2_DIV              0x01
-
-/* Channel Configuration Register 3 (CCR3) */
-#define SAB82532_CCR3_PSD              0x01
-
-/* Time Slot Assignment Register Transmit (TSAX) */
-#define SAB82532_TSAX_TSNX_MASK                0xfc
-#define SAB82532_TSAX_XCS2             0x02    /* see also CCR2 */
-#define SAB82532_TSAX_XCS1             0x01
-
-/* Time Slot Assignment Register Receive (TSAR) */
-#define SAB82532_TSAR_TSNR_MASK                0xfc
-#define SAB82532_TSAR_RCS2             0x02    /* see also CCR2 */
-#define SAB82532_TSAR_RCS1             0x01
-
-/* Version Status Register (VSTR) */
-#define SAB82532_VSTR_CD               0x80
-#define SAB82532_VSTR_DPLA             0x40
-#define SAB82532_VSTR_VN_MASK          0x0f
-#define SAB82532_VSTR_VN_1             0x00
-#define SAB82532_VSTR_VN_2             0x01
-#define SAB82532_VSTR_VN_3_2           0x02
-
-/* Global Interrupt Status Register (GIS) */
-#define SAB82532_GIS_PI                        0x80
-#define SAB82532_GIS_ISA1              0x08
-#define SAB82532_GIS_ISA0              0x04
-#define SAB82532_GIS_ISB1              0x02
-#define SAB82532_GIS_ISB0              0x01
-
-/* Interrupt Vector Address (IVA) */
-#define SAB82532_IVA_MASK              0xf1
-
-/* Interrupt Port Configuration (IPC) */
-#define SAB82532_IPC_VIS               0x80
-#define SAB82532_IPC_SLA1              0x10
-#define SAB82532_IPC_SLA0              0x08
-#define SAB82532_IPC_CASM              0x04
-#define SAB82532_IPC_IC_OPEN_DRAIN     0x00
-#define SAB82532_IPC_IC_ACT_LOW                0x01
-#define SAB82532_IPC_IC_ACT_HIGH       0x03
-
-/* Interrupt Status Register 0 (ISR0) */
-#define SAB82532_ISR0_TCD              0x80
-#define SAB82532_ISR0_TIME             0x40
-#define SAB82532_ISR0_PERR             0x20
-#define SAB82532_ISR0_FERR             0x10
-#define SAB82532_ISR0_PLLA             0x08
-#define SAB82532_ISR0_CDSC             0x04
-#define SAB82532_ISR0_RFO              0x02
-#define SAB82532_ISR0_RPF              0x01
-
-/* Interrupt Status Register 1 (ISR1) */
-#define SAB82532_ISR1_BRK              0x80
-#define SAB82532_ISR1_BRKT             0x40
-#define SAB82532_ISR1_ALLS             0x20
-#define SAB82532_ISR1_XOFF             0x10
-#define SAB82532_ISR1_TIN              0x08
-#define SAB82532_ISR1_CSC              0x04
-#define SAB82532_ISR1_XON              0x02
-#define SAB82532_ISR1_XPR              0x01
-
-/* Interrupt Mask Register 0 (IMR0) */
-#define SAB82532_IMR0_TCD              0x80
-#define SAB82532_IMR0_TIME             0x40
-#define SAB82532_IMR0_PERR             0x20
-#define SAB82532_IMR0_FERR             0x10
-#define SAB82532_IMR0_PLLA             0x08
-#define SAB82532_IMR0_CDSC             0x04
-#define SAB82532_IMR0_RFO              0x02
-#define SAB82532_IMR0_RPF              0x01
-
-/* Interrupt Mask Register 1 (IMR1) */
-#define SAB82532_IMR1_BRK              0x80
-#define SAB82532_IMR1_BRKT             0x40
-#define SAB82532_IMR1_ALLS             0x20
-#define SAB82532_IMR1_XOFF             0x10
-#define SAB82532_IMR1_TIN              0x08
-#define SAB82532_IMR1_CSC              0x04
-#define SAB82532_IMR1_XON              0x02
-#define SAB82532_IMR1_XPR              0x01
-
-/* Port Interrupt Status Register (PIS) */
-#define SAB82532_PIS_SYNC_B            0x08
-#define SAB82532_PIS_DTR_B             0x04
-#define SAB82532_PIS_DTR_A             0x02
-#define SAB82532_PIS_SYNC_A            0x01
-
-/* Channel Configuration Register 4 (CCR4) */
-#define SAB82532_CCR4_MCK4             0x80
-#define SAB82532_CCR4_EBRG             0x40
-#define SAB82532_CCR4_TST1             0x20
-#define SAB82532_CCR4_ICD              0x10
-
-
-#endif /* !(_SUNSAB_H) */
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
deleted file mode 100644 (file)
index 551ebfe..0000000
+++ /dev/null
@@ -1,1608 +0,0 @@
-/*
- * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
- *
- * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
- * Copyright (C) 1998-1999  Pete Zaitcev   (zaitcev@yahoo.com)
- *
- * This is mainly a variation of 8250.c, credits go to authors mentioned
- * therein.  In fact this driver should be merged into the generic 8250.c
- * infrastructure perhaps using a 8250_sparc.c module.
- *
- * Fixed to use tty_get_baud_rate().
- *   Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12
- *
- * Converted to new 2.5.x UART layer.
- *   David S. Miller (davem@davemloft.net), 2002-Jul-29
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/circ_buf.h>
-#include <linux/serial.h>
-#include <linux/sysrq.h>
-#include <linux/console.h>
-#include <linux/slab.h>
-#ifdef CONFIG_SERIO
-#include <linux/serio.h>
-#endif
-#include <linux/serial_reg.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/of_device.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/prom.h>
-
-#if defined(CONFIG_SERIAL_SUNSU_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
-#include "suncore.h"
-
-/* We are on a NS PC87303 clocked with 24.0 MHz, which results
- * in a UART clock of 1.8462 MHz.
- */
-#define SU_BASE_BAUD   (1846200 / 16)
-
-enum su_type { SU_PORT_NONE, SU_PORT_MS, SU_PORT_KBD, SU_PORT_PORT };
-static char *su_typev[] = { "su(???)", "su(mouse)", "su(kbd)", "su(serial)" };
-
-/*
- * Here we define the default xmit fifo size used for each type of UART.
- */
-static const struct serial_uart_config uart_config[PORT_MAX_8250+1] = {
-       { "unknown",    1,      0 },
-       { "8250",       1,      0 },
-       { "16450",      1,      0 },
-       { "16550",      1,      0 },
-       { "16550A",     16,     UART_CLEAR_FIFO | UART_USE_FIFO },
-       { "Cirrus",     1,      0 },
-       { "ST16650",    1,      UART_CLEAR_FIFO | UART_STARTECH },
-       { "ST16650V2",  32,     UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
-       { "TI16750",    64,     UART_CLEAR_FIFO | UART_USE_FIFO },
-       { "Startech",   1,      0 },
-       { "16C950/954", 128,    UART_CLEAR_FIFO | UART_USE_FIFO },
-       { "ST16654",    64,     UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
-       { "XR16850",    128,    UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
-       { "RSA",        2048,   UART_CLEAR_FIFO | UART_USE_FIFO }
-};
-
-struct uart_sunsu_port {
-       struct uart_port        port;
-       unsigned char           acr;
-       unsigned char           ier;
-       unsigned short          rev;
-       unsigned char           lcr;
-       unsigned int            lsr_break_flag;
-       unsigned int            cflag;
-
-       /* Probing information.  */
-       enum su_type            su_type;
-       unsigned int            type_probed;    /* XXX Stupid */
-       unsigned long           reg_size;
-
-#ifdef CONFIG_SERIO
-       struct serio            serio;
-       int                     serio_open;
-#endif
-};
-
-static unsigned int serial_in(struct uart_sunsu_port *up, int offset)
-{
-       offset <<= up->port.regshift;
-
-       switch (up->port.iotype) {
-       case UPIO_HUB6:
-               outb(up->port.hub6 - 1 + offset, up->port.iobase);
-               return inb(up->port.iobase + 1);
-
-       case UPIO_MEM:
-               return readb(up->port.membase + offset);
-
-       default:
-               return inb(up->port.iobase + offset);
-       }
-}
-
-static void serial_out(struct uart_sunsu_port *up, int offset, int value)
-{
-#ifndef CONFIG_SPARC64
-       /*
-        * MrCoffee has weird schematics: IRQ4 & P10(?) pins of SuperIO are
-        * connected with a gate then go to SlavIO. When IRQ4 goes tristated
-        * gate outputs a logical one. Since we use level triggered interrupts
-        * we have lockup and watchdog reset. We cannot mask IRQ because
-        * keyboard shares IRQ with us (Word has it as Bob Smelik's design).
-        * This problem is similar to what Alpha people suffer, see serial.c.
-        */
-       if (offset == UART_MCR)
-               value |= UART_MCR_OUT2;
-#endif
-       offset <<= up->port.regshift;
-
-       switch (up->port.iotype) {
-       case UPIO_HUB6:
-               outb(up->port.hub6 - 1 + offset, up->port.iobase);
-               outb(value, up->port.iobase + 1);
-               break;
-
-       case UPIO_MEM:
-               writeb(value, up->port.membase + offset);
-               break;
-
-       default:
-               outb(value, up->port.iobase + offset);
-       }
-}
-
-/*
- * We used to support using pause I/O for certain machines.  We
- * haven't supported this for a while, but just in case it's badly
- * needed for certain old 386 machines, I've left these #define's
- * in....
- */
-#define serial_inp(up, offset)         serial_in(up, offset)
-#define serial_outp(up, offset, value) serial_out(up, offset, value)
-
-
-/*
- * For the 16C950
- */
-static void serial_icr_write(struct uart_sunsu_port *up, int offset, int value)
-{
-       serial_out(up, UART_SCR, offset);
-       serial_out(up, UART_ICR, value);
-}
-
-#if 0 /* Unused currently */
-static unsigned int serial_icr_read(struct uart_sunsu_port *up, int offset)
-{
-       unsigned int value;
-
-       serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD);
-       serial_out(up, UART_SCR, offset);
-       value = serial_in(up, UART_ICR);
-       serial_icr_write(up, UART_ACR, up->acr);
-
-       return value;
-}
-#endif
-
-#ifdef CONFIG_SERIAL_8250_RSA
-/*
- * Attempts to turn on the RSA FIFO.  Returns zero on failure.
- * We set the port uart clock rate if we succeed.
- */
-static int __enable_rsa(struct uart_sunsu_port *up)
-{
-       unsigned char mode;
-       int result;
-
-       mode = serial_inp(up, UART_RSA_MSR);
-       result = mode & UART_RSA_MSR_FIFO;
-
-       if (!result) {
-               serial_outp(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
-               mode = serial_inp(up, UART_RSA_MSR);
-               result = mode & UART_RSA_MSR_FIFO;
-       }
-
-       if (result)
-               up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16;
-
-       return result;
-}
-
-static void enable_rsa(struct uart_sunsu_port *up)
-{
-       if (up->port.type == PORT_RSA) {
-               if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) {
-                       spin_lock_irq(&up->port.lock);
-                       __enable_rsa(up);
-                       spin_unlock_irq(&up->port.lock);
-               }
-               if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16)
-                       serial_outp(up, UART_RSA_FRR, 0);
-       }
-}
-
-/*
- * Attempts to turn off the RSA FIFO.  Returns zero on failure.
- * It is unknown why interrupts were disabled in here.  However,
- * the caller is expected to preserve this behaviour by grabbing
- * the spinlock before calling this function.
- */
-static void disable_rsa(struct uart_sunsu_port *up)
-{
-       unsigned char mode;
-       int result;
-
-       if (up->port.type == PORT_RSA &&
-           up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) {
-               spin_lock_irq(&up->port.lock);
-
-               mode = serial_inp(up, UART_RSA_MSR);
-               result = !(mode & UART_RSA_MSR_FIFO);
-
-               if (!result) {
-                       serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
-                       mode = serial_inp(up, UART_RSA_MSR);
-                       result = !(mode & UART_RSA_MSR_FIFO);
-               }
-
-               if (result)
-                       up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16;
-               spin_unlock_irq(&up->port.lock);
-       }
-}
-#endif /* CONFIG_SERIAL_8250_RSA */
-
-static inline void __stop_tx(struct uart_sunsu_port *p)
-{
-       if (p->ier & UART_IER_THRI) {
-               p->ier &= ~UART_IER_THRI;
-               serial_out(p, UART_IER, p->ier);
-       }
-}
-
-static void sunsu_stop_tx(struct uart_port *port)
-{
-       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
-
-       __stop_tx(up);
-
-       /*
-        * We really want to stop the transmitter from sending.
-        */
-       if (up->port.type == PORT_16C950) {
-               up->acr |= UART_ACR_TXDIS;
-               serial_icr_write(up, UART_ACR, up->acr);
-       }
-}
-
-static void sunsu_start_tx(struct uart_port *port)
-{
-       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
-
-       if (!(up->ier & UART_IER_THRI)) {
-               up->ier |= UART_IER_THRI;
-               serial_out(up, UART_IER, up->ier);
-       }
-
-       /*
-        * Re-enable the transmitter if we disabled it.
-        */
-       if (up->port.type == PORT_16C950 && up->acr & UART_ACR_TXDIS) {
-               up->acr &= ~UART_ACR_TXDIS;
-               serial_icr_write(up, UART_ACR, up->acr);
-       }
-}
-
-static void sunsu_stop_rx(struct uart_port *port)
-{
-       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
-
-       up->ier &= ~UART_IER_RLSI;
-       up->port.read_status_mask &= ~UART_LSR_DR;
-       serial_out(up, UART_IER, up->ier);
-}
-
-static void sunsu_enable_ms(struct uart_port *port)
-{
-       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
-       unsigned long flags;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       up->ier |= UART_IER_MSI;
-       serial_out(up, UART_IER, up->ier);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static struct tty_struct *
-receive_chars(struct uart_sunsu_port *up, unsigned char *status)
-{
-       struct tty_struct *tty = up->port.state->port.tty;
-       unsigned char ch, flag;
-       int max_count = 256;
-       int saw_console_brk = 0;
-
-       do {
-               ch = serial_inp(up, UART_RX);
-               flag = TTY_NORMAL;
-               up->port.icount.rx++;
-
-               if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
-                                      UART_LSR_FE | UART_LSR_OE))) {
-                       /*
-                        * For statistics only
-                        */
-                       if (*status & UART_LSR_BI) {
-                               *status &= ~(UART_LSR_FE | UART_LSR_PE);
-                               up->port.icount.brk++;
-                               if (up->port.cons != NULL &&
-                                   up->port.line == up->port.cons->index)
-                                       saw_console_brk = 1;
-                               /*
-                                * We do the SysRQ and SAK checking
-                                * here because otherwise the break
-                                * may get masked by ignore_status_mask
-                                * or read_status_mask.
-                                */
-                               if (uart_handle_break(&up->port))
-                                       goto ignore_char;
-                       } else if (*status & UART_LSR_PE)
-                               up->port.icount.parity++;
-                       else if (*status & UART_LSR_FE)
-                               up->port.icount.frame++;
-                       if (*status & UART_LSR_OE)
-                               up->port.icount.overrun++;
-
-                       /*
-                        * Mask off conditions which should be ingored.
-                        */
-                       *status &= up->port.read_status_mask;
-
-                       if (up->port.cons != NULL &&
-                           up->port.line == up->port.cons->index) {
-                               /* Recover the break flag from console xmit */
-                               *status |= up->lsr_break_flag;
-                               up->lsr_break_flag = 0;
-                       }
-
-                       if (*status & UART_LSR_BI) {
-                               flag = TTY_BREAK;
-                       } else if (*status & UART_LSR_PE)
-                               flag = TTY_PARITY;
-                       else if (*status & UART_LSR_FE)
-                               flag = TTY_FRAME;
-               }
-               if (uart_handle_sysrq_char(&up->port, ch))
-                       goto ignore_char;
-               if ((*status & up->port.ignore_status_mask) == 0)
-                       tty_insert_flip_char(tty, ch, flag);
-               if (*status & UART_LSR_OE)
-                       /*
-                        * Overrun is special, since it's reported
-                        * immediately, and doesn't affect the current
-                        * character.
-                        */
-                        tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-       ignore_char:
-               *status = serial_inp(up, UART_LSR);
-       } while ((*status & UART_LSR_DR) && (max_count-- > 0));
-
-       if (saw_console_brk)
-               sun_do_break();
-
-       return tty;
-}
-
-static void transmit_chars(struct uart_sunsu_port *up)
-{
-       struct circ_buf *xmit = &up->port.state->xmit;
-       int count;
-
-       if (up->port.x_char) {
-               serial_outp(up, UART_TX, up->port.x_char);
-               up->port.icount.tx++;
-               up->port.x_char = 0;
-               return;
-       }
-       if (uart_tx_stopped(&up->port)) {
-               sunsu_stop_tx(&up->port);
-               return;
-       }
-       if (uart_circ_empty(xmit)) {
-               __stop_tx(up);
-               return;
-       }
-
-       count = up->port.fifosize;
-       do {
-               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               up->port.icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (--count > 0);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&up->port);
-
-       if (uart_circ_empty(xmit))
-               __stop_tx(up);
-}
-
-static void check_modem_status(struct uart_sunsu_port *up)
-{
-       int status;
-
-       status = serial_in(up, UART_MSR);
-
-       if ((status & UART_MSR_ANY_DELTA) == 0)
-               return;
-
-       if (status & UART_MSR_TERI)
-               up->port.icount.rng++;
-       if (status & UART_MSR_DDSR)
-               up->port.icount.dsr++;
-       if (status & UART_MSR_DDCD)
-               uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
-       if (status & UART_MSR_DCTS)
-               uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
-
-       wake_up_interruptible(&up->port.state->port.delta_msr_wait);
-}
-
-static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id)
-{
-       struct uart_sunsu_port *up = dev_id;
-       unsigned long flags;
-       unsigned char status;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       do {
-               struct tty_struct *tty;
-
-               status = serial_inp(up, UART_LSR);
-               tty = NULL;
-               if (status & UART_LSR_DR)
-                       tty = receive_chars(up, &status);
-               check_modem_status(up);
-               if (status & UART_LSR_THRE)
-                       transmit_chars(up);
-
-               spin_unlock_irqrestore(&up->port.lock, flags);
-
-               if (tty)
-                       tty_flip_buffer_push(tty);
-
-               spin_lock_irqsave(&up->port.lock, flags);
-
-       } while (!(serial_in(up, UART_IIR) & UART_IIR_NO_INT));
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       return IRQ_HANDLED;
-}
-
-/* Separate interrupt handling path for keyboard/mouse ports.  */
-
-static void
-sunsu_change_speed(struct uart_port *port, unsigned int cflag,
-                  unsigned int iflag, unsigned int quot);
-
-static void sunsu_change_mouse_baud(struct uart_sunsu_port *up)
-{
-       unsigned int cur_cflag = up->cflag;
-       int quot, new_baud;
-
-       up->cflag &= ~CBAUD;
-       up->cflag |= suncore_mouse_baud_cflag_next(cur_cflag, &new_baud);
-
-       quot = up->port.uartclk / (16 * new_baud);
-
-       sunsu_change_speed(&up->port, up->cflag, 0, quot);
-}
-
-static void receive_kbd_ms_chars(struct uart_sunsu_port *up, int is_break)
-{
-       do {
-               unsigned char ch = serial_inp(up, UART_RX);
-
-               /* Stop-A is handled by drivers/char/keyboard.c now. */
-               if (up->su_type == SU_PORT_KBD) {
-#ifdef CONFIG_SERIO
-                       serio_interrupt(&up->serio, ch, 0);
-#endif
-               } else if (up->su_type == SU_PORT_MS) {
-                       int ret = suncore_mouse_baud_detection(ch, is_break);
-
-                       switch (ret) {
-                       case 2:
-                               sunsu_change_mouse_baud(up);
-                               /* fallthru */
-                       case 1:
-                               break;
-
-                       case 0:
-#ifdef CONFIG_SERIO
-                               serio_interrupt(&up->serio, ch, 0);
-#endif
-                               break;
-                       };
-               }
-       } while (serial_in(up, UART_LSR) & UART_LSR_DR);
-}
-
-static irqreturn_t sunsu_kbd_ms_interrupt(int irq, void *dev_id)
-{
-       struct uart_sunsu_port *up = dev_id;
-
-       if (!(serial_in(up, UART_IIR) & UART_IIR_NO_INT)) {
-               unsigned char status = serial_inp(up, UART_LSR);
-
-               if ((status & UART_LSR_DR) || (status & UART_LSR_BI))
-                       receive_kbd_ms_chars(up, (status & UART_LSR_BI) != 0);
-       }
-
-       return IRQ_HANDLED;
-}
-
-static unsigned int sunsu_tx_empty(struct uart_port *port)
-{
-       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
-       unsigned long flags;
-       unsigned int ret;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       return ret;
-}
-
-static unsigned int sunsu_get_mctrl(struct uart_port *port)
-{
-       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
-       unsigned char status;
-       unsigned int ret;
-
-       status = serial_in(up, UART_MSR);
-
-       ret = 0;
-       if (status & UART_MSR_DCD)
-               ret |= TIOCM_CAR;
-       if (status & UART_MSR_RI)
-               ret |= TIOCM_RNG;
-       if (status & UART_MSR_DSR)
-               ret |= TIOCM_DSR;
-       if (status & UART_MSR_CTS)
-               ret |= TIOCM_CTS;
-       return ret;
-}
-
-static void sunsu_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
-       unsigned char mcr = 0;
-
-       if (mctrl & TIOCM_RTS)
-               mcr |= UART_MCR_RTS;
-       if (mctrl & TIOCM_DTR)
-               mcr |= UART_MCR_DTR;
-       if (mctrl & TIOCM_OUT1)
-               mcr |= UART_MCR_OUT1;
-       if (mctrl & TIOCM_OUT2)
-               mcr |= UART_MCR_OUT2;
-       if (mctrl & TIOCM_LOOP)
-               mcr |= UART_MCR_LOOP;
-
-       serial_out(up, UART_MCR, mcr);
-}
-
-static void sunsu_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
-       unsigned long flags;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       if (break_state == -1)
-               up->lcr |= UART_LCR_SBC;
-       else
-               up->lcr &= ~UART_LCR_SBC;
-       serial_out(up, UART_LCR, up->lcr);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static int sunsu_startup(struct uart_port *port)
-{
-       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
-       unsigned long flags;
-       int retval;
-
-       if (up->port.type == PORT_16C950) {
-               /* Wake up and initialize UART */
-               up->acr = 0;
-               serial_outp(up, UART_LCR, 0xBF);
-               serial_outp(up, UART_EFR, UART_EFR_ECB);
-               serial_outp(up, UART_IER, 0);
-               serial_outp(up, UART_LCR, 0);
-               serial_icr_write(up, UART_CSR, 0); /* Reset the UART */
-               serial_outp(up, UART_LCR, 0xBF);
-               serial_outp(up, UART_EFR, UART_EFR_ECB);
-               serial_outp(up, UART_LCR, 0);
-       }
-
-#ifdef CONFIG_SERIAL_8250_RSA
-       /*
-        * If this is an RSA port, see if we can kick it up to the
-        * higher speed clock.
-        */
-       enable_rsa(up);
-#endif
-
-       /*
-        * Clear the FIFO buffers and disable them.
-        * (they will be reenabled in set_termios())
-        */
-       if (uart_config[up->port.type].flags & UART_CLEAR_FIFO) {
-               serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-               serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
-                               UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
-               serial_outp(up, UART_FCR, 0);
-       }
-
-       /*
-        * Clear the interrupt registers.
-        */
-       (void) serial_inp(up, UART_LSR);
-       (void) serial_inp(up, UART_RX);
-       (void) serial_inp(up, UART_IIR);
-       (void) serial_inp(up, UART_MSR);
-
-       /*
-        * At this point, there's no way the LSR could still be 0xff;
-        * if it is, then bail out, because there's likely no UART
-        * here.
-        */
-       if (!(up->port.flags & UPF_BUGGY_UART) &&
-           (serial_inp(up, UART_LSR) == 0xff)) {
-               printk("ttyS%d: LSR safety check engaged!\n", up->port.line);
-               return -ENODEV;
-       }
-
-       if (up->su_type != SU_PORT_PORT) {
-               retval = request_irq(up->port.irq, sunsu_kbd_ms_interrupt,
-                                    IRQF_SHARED, su_typev[up->su_type], up);
-       } else {
-               retval = request_irq(up->port.irq, sunsu_serial_interrupt,
-                                    IRQF_SHARED, su_typev[up->su_type], up);
-       }
-       if (retval) {
-               printk("su: Cannot register IRQ %d\n", up->port.irq);
-               return retval;
-       }
-
-       /*
-        * Now, initialize the UART
-        */
-       serial_outp(up, UART_LCR, UART_LCR_WLEN8);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       up->port.mctrl |= TIOCM_OUT2;
-
-       sunsu_set_mctrl(&up->port, up->port.mctrl);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       /*
-        * Finally, enable interrupts.  Note: Modem status interrupts
-        * are set via set_termios(), which will be occurring imminently
-        * anyway, so we don't enable them here.
-        */
-       up->ier = UART_IER_RLSI | UART_IER_RDI;
-       serial_outp(up, UART_IER, up->ier);
-
-       if (up->port.flags & UPF_FOURPORT) {
-               unsigned int icp;
-               /*
-                * Enable interrupts on the AST Fourport board
-                */
-               icp = (up->port.iobase & 0xfe0) | 0x01f;
-               outb_p(0x80, icp);
-               (void) inb_p(icp);
-       }
-
-       /*
-        * And clear the interrupt registers again for luck.
-        */
-       (void) serial_inp(up, UART_LSR);
-       (void) serial_inp(up, UART_RX);
-       (void) serial_inp(up, UART_IIR);
-       (void) serial_inp(up, UART_MSR);
-
-       return 0;
-}
-
-static void sunsu_shutdown(struct uart_port *port)
-{
-       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
-       unsigned long flags;
-
-       /*
-        * Disable interrupts from this port
-        */
-       up->ier = 0;
-       serial_outp(up, UART_IER, 0);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       if (up->port.flags & UPF_FOURPORT) {
-               /* reset interrupts on the AST Fourport board */
-               inb((up->port.iobase & 0xfe0) | 0x1f);
-               up->port.mctrl |= TIOCM_OUT1;
-       } else
-               up->port.mctrl &= ~TIOCM_OUT2;
-
-       sunsu_set_mctrl(&up->port, up->port.mctrl);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       /*
-        * Disable break condition and FIFOs
-        */
-       serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC);
-       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
-                                 UART_FCR_CLEAR_RCVR |
-                                 UART_FCR_CLEAR_XMIT);
-       serial_outp(up, UART_FCR, 0);
-
-#ifdef CONFIG_SERIAL_8250_RSA
-       /*
-        * Reset the RSA board back to 115kbps compat mode.
-        */
-       disable_rsa(up);
-#endif
-
-       /*
-        * Read data port to reset things.
-        */
-       (void) serial_in(up, UART_RX);
-
-       free_irq(up->port.irq, up);
-}
-
-static void
-sunsu_change_speed(struct uart_port *port, unsigned int cflag,
-                  unsigned int iflag, unsigned int quot)
-{
-       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
-       unsigned char cval, fcr = 0;
-       unsigned long flags;
-
-       switch (cflag & CSIZE) {
-       case CS5:
-               cval = 0x00;
-               break;
-       case CS6:
-               cval = 0x01;
-               break;
-       case CS7:
-               cval = 0x02;
-               break;
-       default:
-       case CS8:
-               cval = 0x03;
-               break;
-       }
-
-       if (cflag & CSTOPB)
-               cval |= 0x04;
-       if (cflag & PARENB)
-               cval |= UART_LCR_PARITY;
-       if (!(cflag & PARODD))
-               cval |= UART_LCR_EPAR;
-#ifdef CMSPAR
-       if (cflag & CMSPAR)
-               cval |= UART_LCR_SPAR;
-#endif
-
-       /*
-        * Work around a bug in the Oxford Semiconductor 952 rev B
-        * chip which causes it to seriously miscalculate baud rates
-        * when DLL is 0.
-        */
-       if ((quot & 0xff) == 0 && up->port.type == PORT_16C950 &&
-           up->rev == 0x5201)
-               quot ++;
-
-       if (uart_config[up->port.type].flags & UART_USE_FIFO) {
-               if ((up->port.uartclk / quot) < (2400 * 16))
-                       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
-#ifdef CONFIG_SERIAL_8250_RSA
-               else if (up->port.type == PORT_RSA)
-                       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14;
-#endif
-               else
-                       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
-       }
-       if (up->port.type == PORT_16750)
-               fcr |= UART_FCR7_64BYTE;
-
-       /*
-        * Ok, we're now changing the port state.  Do it with
-        * interrupts disabled.
-        */
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, cflag, (port->uartclk / (16 * quot)));
-
-       up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
-       if (iflag & INPCK)
-               up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (iflag & (BRKINT | PARMRK))
-               up->port.read_status_mask |= UART_LSR_BI;
-
-       /*
-        * Characteres to ignore
-        */
-       up->port.ignore_status_mask = 0;
-       if (iflag & IGNPAR)
-               up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
-       if (iflag & IGNBRK) {
-               up->port.ignore_status_mask |= UART_LSR_BI;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (iflag & IGNPAR)
-                       up->port.ignore_status_mask |= UART_LSR_OE;
-       }
-
-       /*
-        * ignore all characters if CREAD is not set
-        */
-       if ((cflag & CREAD) == 0)
-               up->port.ignore_status_mask |= UART_LSR_DR;
-
-       /*
-        * CTS flow control flag and modem status interrupts
-        */
-       up->ier &= ~UART_IER_MSI;
-       if (UART_ENABLE_MS(&up->port, cflag))
-               up->ier |= UART_IER_MSI;
-
-       serial_out(up, UART_IER, up->ier);
-
-       if (uart_config[up->port.type].flags & UART_STARTECH) {
-               serial_outp(up, UART_LCR, 0xBF);
-               serial_outp(up, UART_EFR, cflag & CRTSCTS ? UART_EFR_CTS :0);
-       }
-       serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
-       serial_outp(up, UART_DLL, quot & 0xff);         /* LS of divisor */
-       serial_outp(up, UART_DLM, quot >> 8);           /* MS of divisor */
-       if (up->port.type == PORT_16750)
-               serial_outp(up, UART_FCR, fcr);         /* set fcr */
-       serial_outp(up, UART_LCR, cval);                /* reset DLAB */
-       up->lcr = cval;                                 /* Save LCR */
-       if (up->port.type != PORT_16750) {
-               if (fcr & UART_FCR_ENABLE_FIFO) {
-                       /* emulated UARTs (Lucent Venus 167x) need two steps */
-                       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-               }
-               serial_outp(up, UART_FCR, fcr);         /* set fcr */
-       }
-
-       up->cflag = cflag;
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static void
-sunsu_set_termios(struct uart_port *port, struct ktermios *termios,
-                 struct ktermios *old)
-{
-       unsigned int baud, quot;
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
-       quot = uart_get_divisor(port, baud);
-
-       sunsu_change_speed(port, termios->c_cflag, termios->c_iflag, quot);
-}
-
-static void sunsu_release_port(struct uart_port *port)
-{
-}
-
-static int sunsu_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-static void sunsu_config_port(struct uart_port *port, int flags)
-{
-       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
-
-       if (flags & UART_CONFIG_TYPE) {
-               /*
-                * We are supposed to call autoconfig here, but this requires
-                * splitting all the OBP probing crap from the UART probing.
-                * We'll do it when we kill sunsu.c altogether.
-                */
-               port->type = up->type_probed;   /* XXX */
-       }
-}
-
-static int
-sunsu_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       return -EINVAL;
-}
-
-static const char *
-sunsu_type(struct uart_port *port)
-{
-       int type = port->type;
-
-       if (type >= ARRAY_SIZE(uart_config))
-               type = 0;
-       return uart_config[type].name;
-}
-
-static struct uart_ops sunsu_pops = {
-       .tx_empty       = sunsu_tx_empty,
-       .set_mctrl      = sunsu_set_mctrl,
-       .get_mctrl      = sunsu_get_mctrl,
-       .stop_tx        = sunsu_stop_tx,
-       .start_tx       = sunsu_start_tx,
-       .stop_rx        = sunsu_stop_rx,
-       .enable_ms      = sunsu_enable_ms,
-       .break_ctl      = sunsu_break_ctl,
-       .startup        = sunsu_startup,
-       .shutdown       = sunsu_shutdown,
-       .set_termios    = sunsu_set_termios,
-       .type           = sunsu_type,
-       .release_port   = sunsu_release_port,
-       .request_port   = sunsu_request_port,
-       .config_port    = sunsu_config_port,
-       .verify_port    = sunsu_verify_port,
-};
-
-#define UART_NR        4
-
-static struct uart_sunsu_port sunsu_ports[UART_NR];
-
-#ifdef CONFIG_SERIO
-
-static DEFINE_SPINLOCK(sunsu_serio_lock);
-
-static int sunsu_serio_write(struct serio *serio, unsigned char ch)
-{
-       struct uart_sunsu_port *up = serio->port_data;
-       unsigned long flags;
-       int lsr;
-
-       spin_lock_irqsave(&sunsu_serio_lock, flags);
-
-       do {
-               lsr = serial_in(up, UART_LSR);
-       } while (!(lsr & UART_LSR_THRE));
-
-       /* Send the character out. */
-       serial_out(up, UART_TX, ch);
-
-       spin_unlock_irqrestore(&sunsu_serio_lock, flags);
-
-       return 0;
-}
-
-static int sunsu_serio_open(struct serio *serio)
-{
-       struct uart_sunsu_port *up = serio->port_data;
-       unsigned long flags;
-       int ret;
-
-       spin_lock_irqsave(&sunsu_serio_lock, flags);
-       if (!up->serio_open) {
-               up->serio_open = 1;
-               ret = 0;
-       } else
-               ret = -EBUSY;
-       spin_unlock_irqrestore(&sunsu_serio_lock, flags);
-
-       return ret;
-}
-
-static void sunsu_serio_close(struct serio *serio)
-{
-       struct uart_sunsu_port *up = serio->port_data;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sunsu_serio_lock, flags);
-       up->serio_open = 0;
-       spin_unlock_irqrestore(&sunsu_serio_lock, flags);
-}
-
-#endif /* CONFIG_SERIO */
-
-static void sunsu_autoconfig(struct uart_sunsu_port *up)
-{
-       unsigned char status1, status2, scratch, scratch2, scratch3;
-       unsigned char save_lcr, save_mcr;
-       unsigned long flags;
-
-       if (up->su_type == SU_PORT_NONE)
-               return;
-
-       up->type_probed = PORT_UNKNOWN;
-       up->port.iotype = UPIO_MEM;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       if (!(up->port.flags & UPF_BUGGY_UART)) {
-               /*
-                * Do a simple existence test first; if we fail this, there's
-                * no point trying anything else.
-                *
-                * 0x80 is used as a nonsense port to prevent against false
-                * positives due to ISA bus float.  The assumption is that
-                * 0x80 is a non-existent port; which should be safe since
-                * include/asm/io.h also makes this assumption.
-                */
-               scratch = serial_inp(up, UART_IER);
-               serial_outp(up, UART_IER, 0);
-#ifdef __i386__
-               outb(0xff, 0x080);
-#endif
-               scratch2 = serial_inp(up, UART_IER);
-               serial_outp(up, UART_IER, 0x0f);
-#ifdef __i386__
-               outb(0, 0x080);
-#endif
-               scratch3 = serial_inp(up, UART_IER);
-               serial_outp(up, UART_IER, scratch);
-               if (scratch2 != 0 || scratch3 != 0x0F)
-                       goto out;       /* We failed; there's nothing here */
-       }
-
-       save_mcr = serial_in(up, UART_MCR);
-       save_lcr = serial_in(up, UART_LCR);
-
-       /* 
-        * Check to see if a UART is really there.  Certain broken
-        * internal modems based on the Rockwell chipset fail this
-        * test, because they apparently don't implement the loopback
-        * test mode.  So this test is skipped on the COM 1 through
-        * COM 4 ports.  This *should* be safe, since no board
-        * manufacturer would be stupid enough to design a board
-        * that conflicts with COM 1-4 --- we hope!
-        */
-       if (!(up->port.flags & UPF_SKIP_TEST)) {
-               serial_outp(up, UART_MCR, UART_MCR_LOOP | 0x0A);
-               status1 = serial_inp(up, UART_MSR) & 0xF0;
-               serial_outp(up, UART_MCR, save_mcr);
-               if (status1 != 0x90)
-                       goto out;       /* We failed loopback test */
-       }
-       serial_outp(up, UART_LCR, 0xBF);        /* set up for StarTech test */
-       serial_outp(up, UART_EFR, 0);           /* EFR is the same as FCR */
-       serial_outp(up, UART_LCR, 0);
-       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-       scratch = serial_in(up, UART_IIR) >> 6;
-       switch (scratch) {
-               case 0:
-                       up->port.type = PORT_16450;
-                       break;
-               case 1:
-                       up->port.type = PORT_UNKNOWN;
-                       break;
-               case 2:
-                       up->port.type = PORT_16550;
-                       break;
-               case 3:
-                       up->port.type = PORT_16550A;
-                       break;
-       }
-       if (up->port.type == PORT_16550A) {
-               /* Check for Startech UART's */
-               serial_outp(up, UART_LCR, UART_LCR_DLAB);
-               if (serial_in(up, UART_EFR) == 0) {
-                       up->port.type = PORT_16650;
-               } else {
-                       serial_outp(up, UART_LCR, 0xBF);
-                       if (serial_in(up, UART_EFR) == 0)
-                               up->port.type = PORT_16650V2;
-               }
-       }
-       if (up->port.type == PORT_16550A) {
-               /* Check for TI 16750 */
-               serial_outp(up, UART_LCR, save_lcr | UART_LCR_DLAB);
-               serial_outp(up, UART_FCR,
-                           UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
-               scratch = serial_in(up, UART_IIR) >> 5;
-               if (scratch == 7) {
-                       /*
-                        * If this is a 16750, and not a cheap UART
-                        * clone, then it should only go into 64 byte
-                        * mode if the UART_FCR7_64BYTE bit was set
-                        * while UART_LCR_DLAB was latched.
-                        */
-                       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-                       serial_outp(up, UART_LCR, 0);
-                       serial_outp(up, UART_FCR,
-                                   UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
-                       scratch = serial_in(up, UART_IIR) >> 5;
-                       if (scratch == 6)
-                               up->port.type = PORT_16750;
-               }
-               serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-       }
-       serial_outp(up, UART_LCR, save_lcr);
-       if (up->port.type == PORT_16450) {
-               scratch = serial_in(up, UART_SCR);
-               serial_outp(up, UART_SCR, 0xa5);
-               status1 = serial_in(up, UART_SCR);
-               serial_outp(up, UART_SCR, 0x5a);
-               status2 = serial_in(up, UART_SCR);
-               serial_outp(up, UART_SCR, scratch);
-
-               if ((status1 != 0xa5) || (status2 != 0x5a))
-                       up->port.type = PORT_8250;
-       }
-
-       up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size;
-
-       if (up->port.type == PORT_UNKNOWN)
-               goto out;
-       up->type_probed = up->port.type;        /* XXX */
-
-       /*
-        * Reset the UART.
-        */
-#ifdef CONFIG_SERIAL_8250_RSA
-       if (up->port.type == PORT_RSA)
-               serial_outp(up, UART_RSA_FRR, 0);
-#endif
-       serial_outp(up, UART_MCR, save_mcr);
-       serial_outp(up, UART_FCR, (UART_FCR_ENABLE_FIFO |
-                                    UART_FCR_CLEAR_RCVR |
-                                    UART_FCR_CLEAR_XMIT));
-       serial_outp(up, UART_FCR, 0);
-       (void)serial_in(up, UART_RX);
-       serial_outp(up, UART_IER, 0);
-
-out:
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static struct uart_driver sunsu_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "sunsu",
-       .dev_name               = "ttyS",
-       .major                  = TTY_MAJOR,
-};
-
-static int __devinit sunsu_kbd_ms_init(struct uart_sunsu_port *up)
-{
-       int quot, baud;
-#ifdef CONFIG_SERIO
-       struct serio *serio;
-#endif
-
-       if (up->su_type == SU_PORT_KBD) {
-               up->cflag = B1200 | CS8 | CLOCAL | CREAD;
-               baud = 1200;
-       } else {
-               up->cflag = B4800 | CS8 | CLOCAL | CREAD;
-               baud = 4800;
-       }
-       quot = up->port.uartclk / (16 * baud);
-
-       sunsu_autoconfig(up);
-       if (up->port.type == PORT_UNKNOWN)
-               return -ENODEV;
-
-       printk("%s: %s port at %llx, irq %u\n",
-              up->port.dev->of_node->full_name,
-              (up->su_type == SU_PORT_KBD) ? "Keyboard" : "Mouse",
-              (unsigned long long) up->port.mapbase,
-              up->port.irq);
-
-#ifdef CONFIG_SERIO
-       serio = &up->serio;
-       serio->port_data = up;
-
-       serio->id.type = SERIO_RS232;
-       if (up->su_type == SU_PORT_KBD) {
-               serio->id.proto = SERIO_SUNKBD;
-               strlcpy(serio->name, "sukbd", sizeof(serio->name));
-       } else {
-               serio->id.proto = SERIO_SUN;
-               serio->id.extra = 1;
-               strlcpy(serio->name, "sums", sizeof(serio->name));
-       }
-       strlcpy(serio->phys,
-               (!(up->port.line & 1) ? "su/serio0" : "su/serio1"),
-               sizeof(serio->phys));
-
-       serio->write = sunsu_serio_write;
-       serio->open = sunsu_serio_open;
-       serio->close = sunsu_serio_close;
-       serio->dev.parent = up->port.dev;
-
-       serio_register_port(serio);
-#endif
-
-       sunsu_change_speed(&up->port, up->cflag, 0, quot);
-
-       sunsu_startup(&up->port);
-       return 0;
-}
-
-/*
- * ------------------------------------------------------------
- * Serial console driver
- * ------------------------------------------------------------
- */
-
-#ifdef CONFIG_SERIAL_SUNSU_CONSOLE
-
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-
-/*
- *     Wait for transmitter & holding register to empty
- */
-static __inline__ void wait_for_xmitr(struct uart_sunsu_port *up)
-{
-       unsigned int status, tmout = 10000;
-
-       /* Wait up to 10ms for the character(s) to be sent. */
-       do {
-               status = serial_in(up, UART_LSR);
-
-               if (status & UART_LSR_BI)
-                       up->lsr_break_flag = UART_LSR_BI;
-
-               if (--tmout == 0)
-                       break;
-               udelay(1);
-       } while ((status & BOTH_EMPTY) != BOTH_EMPTY);
-
-       /* Wait up to 1s for flow control if necessary */
-       if (up->port.flags & UPF_CONS_FLOW) {
-               tmout = 1000000;
-               while (--tmout &&
-                      ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
-                       udelay(1);
-       }
-}
-
-static void sunsu_console_putchar(struct uart_port *port, int ch)
-{
-       struct uart_sunsu_port *up = (struct uart_sunsu_port *)port;
-
-       wait_for_xmitr(up);
-       serial_out(up, UART_TX, ch);
-}
-
-/*
- *     Print a string to the serial port trying not to disturb
- *     any possible real use of the port...
- */
-static void sunsu_console_write(struct console *co, const char *s,
-                               unsigned int count)
-{
-       struct uart_sunsu_port *up = &sunsu_ports[co->index];
-       unsigned long flags;
-       unsigned int ier;
-       int locked = 1;
-
-       local_irq_save(flags);
-       if (up->port.sysrq) {
-               locked = 0;
-       } else if (oops_in_progress) {
-               locked = spin_trylock(&up->port.lock);
-       } else
-               spin_lock(&up->port.lock);
-
-       /*
-        *      First save the UER then disable the interrupts
-        */
-       ier = serial_in(up, UART_IER);
-       serial_out(up, UART_IER, 0);
-
-       uart_console_write(&up->port, s, count, sunsu_console_putchar);
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore the IER
-        */
-       wait_for_xmitr(up);
-       serial_out(up, UART_IER, ier);
-
-       if (locked)
-               spin_unlock(&up->port.lock);
-       local_irq_restore(flags);
-}
-
-/*
- *     Setup initial baud/bits/parity. We do two things here:
- *     - construct a cflag setting for the first su_open()
- *     - initialize the serial port
- *     Return non-zero if we didn't find a serial port.
- */
-static int __init sunsu_console_setup(struct console *co, char *options)
-{
-       static struct ktermios dummy;
-       struct ktermios termios;
-       struct uart_port *port;
-
-       printk("Console: ttyS%d (SU)\n",
-              (sunsu_reg.minor - 64) + co->index);
-
-       /*
-        * Check whether an invalid uart number has been specified, and
-        * if so, search for the first available port that does have
-        * console support.
-        */
-       if (co->index >= UART_NR)
-               co->index = 0;
-       port = &sunsu_ports[co->index].port;
-
-       /*
-        * Temporary fix.
-        */
-       spin_lock_init(&port->lock);
-
-       /* Get firmware console settings.  */
-       sunserial_console_termios(co, port->dev->of_node);
-
-       memset(&termios, 0, sizeof(struct ktermios));
-       termios.c_cflag = co->cflag;
-       port->mctrl |= TIOCM_DTR;
-       port->ops->set_termios(port, &termios, &dummy);
-
-       return 0;
-}
-
-static struct console sunsu_console = {
-       .name   =       "ttyS",
-       .write  =       sunsu_console_write,
-       .device =       uart_console_device,
-       .setup  =       sunsu_console_setup,
-       .flags  =       CON_PRINTBUFFER,
-       .index  =       -1,
-       .data   =       &sunsu_reg,
-};
-
-/*
- *     Register console.
- */
-
-static inline struct console *SUNSU_CONSOLE(void)
-{
-       return &sunsu_console;
-}
-#else
-#define SUNSU_CONSOLE()                        (NULL)
-#define sunsu_serial_console_init()    do { } while (0)
-#endif
-
-static enum su_type __devinit su_get_type(struct device_node *dp)
-{
-       struct device_node *ap = of_find_node_by_path("/aliases");
-
-       if (ap) {
-               const char *keyb = of_get_property(ap, "keyboard", NULL);
-               const char *ms = of_get_property(ap, "mouse", NULL);
-
-               if (keyb) {
-                       if (dp == of_find_node_by_path(keyb))
-                               return SU_PORT_KBD;
-               }
-               if (ms) {
-                       if (dp == of_find_node_by_path(ms))
-                               return SU_PORT_MS;
-               }
-       }
-
-       return SU_PORT_PORT;
-}
-
-static int __devinit su_probe(struct platform_device *op, const struct of_device_id *match)
-{
-       static int inst;
-       struct device_node *dp = op->dev.of_node;
-       struct uart_sunsu_port *up;
-       struct resource *rp;
-       enum su_type type;
-       bool ignore_line;
-       int err;
-
-       type = su_get_type(dp);
-       if (type == SU_PORT_PORT) {
-               if (inst >= UART_NR)
-                       return -EINVAL;
-               up = &sunsu_ports[inst];
-       } else {
-               up = kzalloc(sizeof(*up), GFP_KERNEL);
-               if (!up)
-                       return -ENOMEM;
-       }
-
-       up->port.line = inst;
-
-       spin_lock_init(&up->port.lock);
-
-       up->su_type = type;
-
-       rp = &op->resource[0];
-       up->port.mapbase = rp->start;
-       up->reg_size = (rp->end - rp->start) + 1;
-       up->port.membase = of_ioremap(rp, 0, up->reg_size, "su");
-       if (!up->port.membase) {
-               if (type != SU_PORT_PORT)
-                       kfree(up);
-               return -ENOMEM;
-       }
-
-       up->port.irq = op->archdata.irqs[0];
-
-       up->port.dev = &op->dev;
-
-       up->port.type = PORT_UNKNOWN;
-       up->port.uartclk = (SU_BASE_BAUD * 16);
-
-       err = 0;
-       if (up->su_type == SU_PORT_KBD || up->su_type == SU_PORT_MS) {
-               err = sunsu_kbd_ms_init(up);
-               if (err) {
-                       of_iounmap(&op->resource[0],
-                                  up->port.membase, up->reg_size);
-                       kfree(up);
-                       return err;
-               }
-               dev_set_drvdata(&op->dev, up);
-
-               return 0;
-       }
-
-       up->port.flags |= UPF_BOOT_AUTOCONF;
-
-       sunsu_autoconfig(up);
-
-       err = -ENODEV;
-       if (up->port.type == PORT_UNKNOWN)
-               goto out_unmap;
-
-       up->port.ops = &sunsu_pops;
-
-       ignore_line = false;
-       if (!strcmp(dp->name, "rsc-console") ||
-           !strcmp(dp->name, "lom-console"))
-               ignore_line = true;
-
-       sunserial_console_match(SUNSU_CONSOLE(), dp,
-                               &sunsu_reg, up->port.line,
-                               ignore_line);
-       err = uart_add_one_port(&sunsu_reg, &up->port);
-       if (err)
-               goto out_unmap;
-
-       dev_set_drvdata(&op->dev, up);
-
-       inst++;
-
-       return 0;
-
-out_unmap:
-       of_iounmap(&op->resource[0], up->port.membase, up->reg_size);
-       return err;
-}
-
-static int __devexit su_remove(struct platform_device *op)
-{
-       struct uart_sunsu_port *up = dev_get_drvdata(&op->dev);
-       bool kbdms = false;
-
-       if (up->su_type == SU_PORT_MS ||
-           up->su_type == SU_PORT_KBD)
-               kbdms = true;
-
-       if (kbdms) {
-#ifdef CONFIG_SERIO
-               serio_unregister_port(&up->serio);
-#endif
-       } else if (up->port.type != PORT_UNKNOWN)
-               uart_remove_one_port(&sunsu_reg, &up->port);
-
-       if (up->port.membase)
-               of_iounmap(&op->resource[0], up->port.membase, up->reg_size);
-
-       if (kbdms)
-               kfree(up);
-
-       dev_set_drvdata(&op->dev, NULL);
-
-       return 0;
-}
-
-static const struct of_device_id su_match[] = {
-       {
-               .name = "su",
-       },
-       {
-               .name = "su_pnp",
-       },
-       {
-               .name = "serial",
-               .compatible = "su",
-       },
-       {
-               .type = "serial",
-               .compatible = "su",
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(of, su_match);
-
-static struct of_platform_driver su_driver = {
-       .driver = {
-               .name = "su",
-               .owner = THIS_MODULE,
-               .of_match_table = su_match,
-       },
-       .probe          = su_probe,
-       .remove         = __devexit_p(su_remove),
-};
-
-static int __init sunsu_init(void)
-{
-       struct device_node *dp;
-       int err;
-       int num_uart = 0;
-
-       for_each_node_by_name(dp, "su") {
-               if (su_get_type(dp) == SU_PORT_PORT)
-                       num_uart++;
-       }
-       for_each_node_by_name(dp, "su_pnp") {
-               if (su_get_type(dp) == SU_PORT_PORT)
-                       num_uart++;
-       }
-       for_each_node_by_name(dp, "serial") {
-               if (of_device_is_compatible(dp, "su")) {
-                       if (su_get_type(dp) == SU_PORT_PORT)
-                               num_uart++;
-               }
-       }
-       for_each_node_by_type(dp, "serial") {
-               if (of_device_is_compatible(dp, "su")) {
-                       if (su_get_type(dp) == SU_PORT_PORT)
-                               num_uart++;
-               }
-       }
-
-       if (num_uart) {
-               err = sunserial_register_minors(&sunsu_reg, num_uart);
-               if (err)
-                       return err;
-       }
-
-       err = of_register_platform_driver(&su_driver);
-       if (err && num_uart)
-               sunserial_unregister_minors(&sunsu_reg, num_uart);
-
-       return err;
-}
-
-static void __exit sunsu_exit(void)
-{
-       if (sunsu_reg.nr)
-               sunserial_unregister_minors(&sunsu_reg, sunsu_reg.nr);
-}
-
-module_init(sunsu_init);
-module_exit(sunsu_exit);
-
-MODULE_AUTHOR("Eddie C. Dost, Peter Zaitcev, and David S. Miller");
-MODULE_DESCRIPTION("Sun SU serial port driver");
-MODULE_VERSION("2.0");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
deleted file mode 100644 (file)
index c1967ac..0000000
+++ /dev/null
@@ -1,1655 +0,0 @@
-/* sunzilog.c: Zilog serial driver for Sparc systems.
- *
- * Driver for Zilog serial chips found on Sun workstations and
- * servers.  This driver could actually be made more generic.
- *
- * This is based on the old drivers/sbus/char/zs.c code.  A lot
- * of code has been simply moved over directly from there but
- * much has been rewritten.  Credits therefore go out to Eddie
- * C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell for their
- * work there.
- *
- * Copyright (C) 2002, 2006, 2007 David S. Miller (davem@davemloft.net)
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/circ_buf.h>
-#include <linux/serial.h>
-#include <linux/sysrq.h>
-#include <linux/console.h>
-#include <linux/spinlock.h>
-#ifdef CONFIG_SERIO
-#include <linux/serio.h>
-#endif
-#include <linux/init.h>
-#include <linux/of_device.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/prom.h>
-
-#if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
-#include "suncore.h"
-#include "sunzilog.h"
-
-/* On 32-bit sparcs we need to delay after register accesses
- * to accommodate sun4 systems, but we do not need to flush writes.
- * On 64-bit sparc we only need to flush single writes to ensure
- * completion.
- */
-#ifndef CONFIG_SPARC64
-#define ZSDELAY()              udelay(5)
-#define ZSDELAY_LONG()         udelay(20)
-#define ZS_WSYNC(channel)      do { } while (0)
-#else
-#define ZSDELAY()
-#define ZSDELAY_LONG()
-#define ZS_WSYNC(__channel) \
-       readb(&((__channel)->control))
-#endif
-
-#define ZS_CLOCK               4915200 /* Zilog input clock rate. */
-#define ZS_CLOCK_DIVISOR       16      /* Divisor this driver uses. */
-
-/*
- * We wrap our port structure around the generic uart_port.
- */
-struct uart_sunzilog_port {
-       struct uart_port                port;
-
-       /* IRQ servicing chain.  */
-       struct uart_sunzilog_port       *next;
-
-       /* Current values of Zilog write registers.  */
-       unsigned char                   curregs[NUM_ZSREGS];
-
-       unsigned int                    flags;
-#define SUNZILOG_FLAG_CONS_KEYB                0x00000001
-#define SUNZILOG_FLAG_CONS_MOUSE       0x00000002
-#define SUNZILOG_FLAG_IS_CONS          0x00000004
-#define SUNZILOG_FLAG_IS_KGDB          0x00000008
-#define SUNZILOG_FLAG_MODEM_STATUS     0x00000010
-#define SUNZILOG_FLAG_IS_CHANNEL_A     0x00000020
-#define SUNZILOG_FLAG_REGS_HELD                0x00000040
-#define SUNZILOG_FLAG_TX_STOPPED       0x00000080
-#define SUNZILOG_FLAG_TX_ACTIVE                0x00000100
-#define SUNZILOG_FLAG_ESCC             0x00000200
-#define SUNZILOG_FLAG_ISR_HANDLER      0x00000400
-
-       unsigned int cflag;
-
-       unsigned char                   parity_mask;
-       unsigned char                   prev_status;
-
-#ifdef CONFIG_SERIO
-       struct serio                    serio;
-       int                             serio_open;
-#endif
-};
-
-static void sunzilog_putchar(struct uart_port *port, int ch);
-
-#define ZILOG_CHANNEL_FROM_PORT(PORT)  ((struct zilog_channel __iomem *)((PORT)->membase))
-#define UART_ZILOG(PORT)               ((struct uart_sunzilog_port *)(PORT))
-
-#define ZS_IS_KEYB(UP) ((UP)->flags & SUNZILOG_FLAG_CONS_KEYB)
-#define ZS_IS_MOUSE(UP)        ((UP)->flags & SUNZILOG_FLAG_CONS_MOUSE)
-#define ZS_IS_CONS(UP) ((UP)->flags & SUNZILOG_FLAG_IS_CONS)
-#define ZS_IS_KGDB(UP) ((UP)->flags & SUNZILOG_FLAG_IS_KGDB)
-#define ZS_WANTS_MODEM_STATUS(UP)      ((UP)->flags & SUNZILOG_FLAG_MODEM_STATUS)
-#define ZS_IS_CHANNEL_A(UP)    ((UP)->flags & SUNZILOG_FLAG_IS_CHANNEL_A)
-#define ZS_REGS_HELD(UP)       ((UP)->flags & SUNZILOG_FLAG_REGS_HELD)
-#define ZS_TX_STOPPED(UP)      ((UP)->flags & SUNZILOG_FLAG_TX_STOPPED)
-#define ZS_TX_ACTIVE(UP)       ((UP)->flags & SUNZILOG_FLAG_TX_ACTIVE)
-
-/* Reading and writing Zilog8530 registers.  The delays are to make this
- * driver work on the Sun4 which needs a settling delay after each chip
- * register access, other machines handle this in hardware via auxiliary
- * flip-flops which implement the settle time we do in software.
- *
- * The port lock must be held and local IRQs must be disabled
- * when {read,write}_zsreg is invoked.
- */
-static unsigned char read_zsreg(struct zilog_channel __iomem *channel,
-                               unsigned char reg)
-{
-       unsigned char retval;
-
-       writeb(reg, &channel->control);
-       ZSDELAY();
-       retval = readb(&channel->control);
-       ZSDELAY();
-
-       return retval;
-}
-
-static void write_zsreg(struct zilog_channel __iomem *channel,
-                       unsigned char reg, unsigned char value)
-{
-       writeb(reg, &channel->control);
-       ZSDELAY();
-       writeb(value, &channel->control);
-       ZSDELAY();
-}
-
-static void sunzilog_clear_fifo(struct zilog_channel __iomem *channel)
-{
-       int i;
-
-       for (i = 0; i < 32; i++) {
-               unsigned char regval;
-
-               regval = readb(&channel->control);
-               ZSDELAY();
-               if (regval & Rx_CH_AV)
-                       break;
-
-               regval = read_zsreg(channel, R1);
-               readb(&channel->data);
-               ZSDELAY();
-
-               if (regval & (PAR_ERR | Rx_OVR | CRC_ERR)) {
-                       writeb(ERR_RES, &channel->control);
-                       ZSDELAY();
-                       ZS_WSYNC(channel);
-               }
-       }
-}
-
-/* This function must only be called when the TX is not busy.  The UART
- * port lock must be held and local interrupts disabled.
- */
-static int __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *regs)
-{
-       int i;
-       int escc;
-       unsigned char r15;
-
-       /* Let pending transmits finish.  */
-       for (i = 0; i < 1000; i++) {
-               unsigned char stat = read_zsreg(channel, R1);
-               if (stat & ALL_SNT)
-                       break;
-               udelay(100);
-       }
-
-       writeb(ERR_RES, &channel->control);
-       ZSDELAY();
-       ZS_WSYNC(channel);
-
-       sunzilog_clear_fifo(channel);
-
-       /* Disable all interrupts.  */
-       write_zsreg(channel, R1,
-                   regs[R1] & ~(RxINT_MASK | TxINT_ENAB | EXT_INT_ENAB));
-
-       /* Set parity, sync config, stop bits, and clock divisor.  */
-       write_zsreg(channel, R4, regs[R4]);
-
-       /* Set misc. TX/RX control bits.  */
-       write_zsreg(channel, R10, regs[R10]);
-
-       /* Set TX/RX controls sans the enable bits.  */
-       write_zsreg(channel, R3, regs[R3] & ~RxENAB);
-       write_zsreg(channel, R5, regs[R5] & ~TxENAB);
-
-       /* Synchronous mode config.  */
-       write_zsreg(channel, R6, regs[R6]);
-       write_zsreg(channel, R7, regs[R7]);
-
-       /* Don't mess with the interrupt vector (R2, unused by us) and
-        * master interrupt control (R9).  We make sure this is setup
-        * properly at probe time then never touch it again.
-        */
-
-       /* Disable baud generator.  */
-       write_zsreg(channel, R14, regs[R14] & ~BRENAB);
-
-       /* Clock mode control.  */
-       write_zsreg(channel, R11, regs[R11]);
-
-       /* Lower and upper byte of baud rate generator divisor.  */
-       write_zsreg(channel, R12, regs[R12]);
-       write_zsreg(channel, R13, regs[R13]);
-       
-       /* Now rewrite R14, with BRENAB (if set).  */
-       write_zsreg(channel, R14, regs[R14]);
-
-       /* External status interrupt control.  */
-       write_zsreg(channel, R15, (regs[R15] | WR7pEN) & ~FIFOEN);
-
-       /* ESCC Extension Register */
-       r15 = read_zsreg(channel, R15);
-       if (r15 & 0x01) {
-               write_zsreg(channel, R7,  regs[R7p]);
-
-               /* External status interrupt and FIFO control.  */
-               write_zsreg(channel, R15, regs[R15] & ~WR7pEN);
-               escc = 1;
-       } else {
-                /* Clear FIFO bit case it is an issue */
-               regs[R15] &= ~FIFOEN;
-               escc = 0;
-       }
-
-       /* Reset external status interrupts.  */
-       write_zsreg(channel, R0, RES_EXT_INT); /* First Latch  */
-       write_zsreg(channel, R0, RES_EXT_INT); /* Second Latch */
-
-       /* Rewrite R3/R5, this time without enables masked.  */
-       write_zsreg(channel, R3, regs[R3]);
-       write_zsreg(channel, R5, regs[R5]);
-
-       /* Rewrite R1, this time without IRQ enabled masked.  */
-       write_zsreg(channel, R1, regs[R1]);
-
-       return escc;
-}
-
-/* Reprogram the Zilog channel HW registers with the copies found in the
- * software state struct.  If the transmitter is busy, we defer this update
- * until the next TX complete interrupt.  Else, we do it right now.
- *
- * The UART port lock must be held and local interrupts disabled.
- */
-static void sunzilog_maybe_update_regs(struct uart_sunzilog_port *up,
-                                      struct zilog_channel __iomem *channel)
-{
-       if (!ZS_REGS_HELD(up)) {
-               if (ZS_TX_ACTIVE(up)) {
-                       up->flags |= SUNZILOG_FLAG_REGS_HELD;
-               } else {
-                       __load_zsregs(channel, up->curregs);
-               }
-       }
-}
-
-static void sunzilog_change_mouse_baud(struct uart_sunzilog_port *up)
-{
-       unsigned int cur_cflag = up->cflag;
-       int brg, new_baud;
-
-       up->cflag &= ~CBAUD;
-       up->cflag |= suncore_mouse_baud_cflag_next(cur_cflag, &new_baud);
-
-       brg = BPS_TO_BRG(new_baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
-       up->curregs[R12] = (brg & 0xff);
-       up->curregs[R13] = (brg >> 8) & 0xff;
-       sunzilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(&up->port));
-}
-
-static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up,
-                                        unsigned char ch, int is_break)
-{
-       if (ZS_IS_KEYB(up)) {
-               /* Stop-A is handled by drivers/char/keyboard.c now. */
-#ifdef CONFIG_SERIO
-               if (up->serio_open)
-                       serio_interrupt(&up->serio, ch, 0);
-#endif
-       } else if (ZS_IS_MOUSE(up)) {
-               int ret = suncore_mouse_baud_detection(ch, is_break);
-
-               switch (ret) {
-               case 2:
-                       sunzilog_change_mouse_baud(up);
-                       /* fallthru */
-               case 1:
-                       break;
-
-               case 0:
-#ifdef CONFIG_SERIO
-                       if (up->serio_open)
-                               serio_interrupt(&up->serio, ch, 0);
-#endif
-                       break;
-               };
-       }
-}
-
-static struct tty_struct *
-sunzilog_receive_chars(struct uart_sunzilog_port *up,
-                      struct zilog_channel __iomem *channel)
-{
-       struct tty_struct *tty;
-       unsigned char ch, r1, flag;
-
-       tty = NULL;
-       if (up->port.state != NULL &&           /* Unopened serial console */
-           up->port.state->port.tty != NULL)   /* Keyboard || mouse */
-               tty = up->port.state->port.tty;
-
-       for (;;) {
-
-               r1 = read_zsreg(channel, R1);
-               if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
-                       writeb(ERR_RES, &channel->control);
-                       ZSDELAY();
-                       ZS_WSYNC(channel);
-               }
-
-               ch = readb(&channel->control);
-               ZSDELAY();
-
-               /* This funny hack depends upon BRK_ABRT not interfering
-                * with the other bits we care about in R1.
-                */
-               if (ch & BRK_ABRT)
-                       r1 |= BRK_ABRT;
-
-               if (!(ch & Rx_CH_AV))
-                       break;
-
-               ch = readb(&channel->data);
-               ZSDELAY();
-
-               ch &= up->parity_mask;
-
-               if (unlikely(ZS_IS_KEYB(up)) || unlikely(ZS_IS_MOUSE(up))) {
-                       sunzilog_kbdms_receive_chars(up, ch, 0);
-                       continue;
-               }
-
-               if (tty == NULL) {
-                       uart_handle_sysrq_char(&up->port, ch);
-                       continue;
-               }
-
-               /* A real serial line, record the character and status.  */
-               flag = TTY_NORMAL;
-               up->port.icount.rx++;
-               if (r1 & (BRK_ABRT | PAR_ERR | Rx_OVR | CRC_ERR)) {
-                       if (r1 & BRK_ABRT) {
-                               r1 &= ~(PAR_ERR | CRC_ERR);
-                               up->port.icount.brk++;
-                               if (uart_handle_break(&up->port))
-                                       continue;
-                       }
-                       else if (r1 & PAR_ERR)
-                               up->port.icount.parity++;
-                       else if (r1 & CRC_ERR)
-                               up->port.icount.frame++;
-                       if (r1 & Rx_OVR)
-                               up->port.icount.overrun++;
-                       r1 &= up->port.read_status_mask;
-                       if (r1 & BRK_ABRT)
-                               flag = TTY_BREAK;
-                       else if (r1 & PAR_ERR)
-                               flag = TTY_PARITY;
-                       else if (r1 & CRC_ERR)
-                               flag = TTY_FRAME;
-               }
-               if (uart_handle_sysrq_char(&up->port, ch))
-                       continue;
-
-               if (up->port.ignore_status_mask == 0xff ||
-                   (r1 & up->port.ignore_status_mask) == 0) {
-                       tty_insert_flip_char(tty, ch, flag);
-               }
-               if (r1 & Rx_OVR)
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-       }
-
-       return tty;
-}
-
-static void sunzilog_status_handle(struct uart_sunzilog_port *up,
-                                  struct zilog_channel __iomem *channel)
-{
-       unsigned char status;
-
-       status = readb(&channel->control);
-       ZSDELAY();
-
-       writeb(RES_EXT_INT, &channel->control);
-       ZSDELAY();
-       ZS_WSYNC(channel);
-
-       if (status & BRK_ABRT) {
-               if (ZS_IS_MOUSE(up))
-                       sunzilog_kbdms_receive_chars(up, 0, 1);
-               if (ZS_IS_CONS(up)) {
-                       /* Wait for BREAK to deassert to avoid potentially
-                        * confusing the PROM.
-                        */
-                       while (1) {
-                               status = readb(&channel->control);
-                               ZSDELAY();
-                               if (!(status & BRK_ABRT))
-                                       break;
-                       }
-                       sun_do_break();
-                       return;
-               }
-       }
-
-       if (ZS_WANTS_MODEM_STATUS(up)) {
-               if (status & SYNC)
-                       up->port.icount.dsr++;
-
-               /* The Zilog just gives us an interrupt when DCD/CTS/etc. change.
-                * But it does not tell us which bit has changed, we have to keep
-                * track of this ourselves.
-                */
-               if ((status ^ up->prev_status) ^ DCD)
-                       uart_handle_dcd_change(&up->port,
-                                              (status & DCD));
-               if ((status ^ up->prev_status) ^ CTS)
-                       uart_handle_cts_change(&up->port,
-                                              (status & CTS));
-
-               wake_up_interruptible(&up->port.state->port.delta_msr_wait);
-       }
-
-       up->prev_status = status;
-}
-
-static void sunzilog_transmit_chars(struct uart_sunzilog_port *up,
-                                   struct zilog_channel __iomem *channel)
-{
-       struct circ_buf *xmit;
-
-       if (ZS_IS_CONS(up)) {
-               unsigned char status = readb(&channel->control);
-               ZSDELAY();
-
-               /* TX still busy?  Just wait for the next TX done interrupt.
-                *
-                * It can occur because of how we do serial console writes.  It would
-                * be nice to transmit console writes just like we normally would for
-                * a TTY line. (ie. buffered and TX interrupt driven).  That is not
-                * easy because console writes cannot sleep.  One solution might be
-                * to poll on enough port->xmit space becomming free.  -DaveM
-                */
-               if (!(status & Tx_BUF_EMP))
-                       return;
-       }
-
-       up->flags &= ~SUNZILOG_FLAG_TX_ACTIVE;
-
-       if (ZS_REGS_HELD(up)) {
-               __load_zsregs(channel, up->curregs);
-               up->flags &= ~SUNZILOG_FLAG_REGS_HELD;
-       }
-
-       if (ZS_TX_STOPPED(up)) {
-               up->flags &= ~SUNZILOG_FLAG_TX_STOPPED;
-               goto ack_tx_int;
-       }
-
-       if (up->port.x_char) {
-               up->flags |= SUNZILOG_FLAG_TX_ACTIVE;
-               writeb(up->port.x_char, &channel->data);
-               ZSDELAY();
-               ZS_WSYNC(channel);
-
-               up->port.icount.tx++;
-               up->port.x_char = 0;
-               return;
-       }
-
-       if (up->port.state == NULL)
-               goto ack_tx_int;
-       xmit = &up->port.state->xmit;
-       if (uart_circ_empty(xmit))
-               goto ack_tx_int;
-
-       if (uart_tx_stopped(&up->port))
-               goto ack_tx_int;
-
-       up->flags |= SUNZILOG_FLAG_TX_ACTIVE;
-       writeb(xmit->buf[xmit->tail], &channel->data);
-       ZSDELAY();
-       ZS_WSYNC(channel);
-
-       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-       up->port.icount.tx++;
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&up->port);
-
-       return;
-
-ack_tx_int:
-       writeb(RES_Tx_P, &channel->control);
-       ZSDELAY();
-       ZS_WSYNC(channel);
-}
-
-static irqreturn_t sunzilog_interrupt(int irq, void *dev_id)
-{
-       struct uart_sunzilog_port *up = dev_id;
-
-       while (up) {
-               struct zilog_channel __iomem *channel
-                       = ZILOG_CHANNEL_FROM_PORT(&up->port);
-               struct tty_struct *tty;
-               unsigned char r3;
-
-               spin_lock(&up->port.lock);
-               r3 = read_zsreg(channel, R3);
-
-               /* Channel A */
-               tty = NULL;
-               if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
-                       writeb(RES_H_IUS, &channel->control);
-                       ZSDELAY();
-                       ZS_WSYNC(channel);
-
-                       if (r3 & CHARxIP)
-                               tty = sunzilog_receive_chars(up, channel);
-                       if (r3 & CHAEXT)
-                               sunzilog_status_handle(up, channel);
-                       if (r3 & CHATxIP)
-                               sunzilog_transmit_chars(up, channel);
-               }
-               spin_unlock(&up->port.lock);
-
-               if (tty)
-                       tty_flip_buffer_push(tty);
-
-               /* Channel B */
-               up = up->next;
-               channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
-
-               spin_lock(&up->port.lock);
-               tty = NULL;
-               if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
-                       writeb(RES_H_IUS, &channel->control);
-                       ZSDELAY();
-                       ZS_WSYNC(channel);
-
-                       if (r3 & CHBRxIP)
-                               tty = sunzilog_receive_chars(up, channel);
-                       if (r3 & CHBEXT)
-                               sunzilog_status_handle(up, channel);
-                       if (r3 & CHBTxIP)
-                               sunzilog_transmit_chars(up, channel);
-               }
-               spin_unlock(&up->port.lock);
-
-               if (tty)
-                       tty_flip_buffer_push(tty);
-
-               up = up->next;
-       }
-
-       return IRQ_HANDLED;
-}
-
-/* A convenient way to quickly get R0 status.  The caller must _not_ hold the
- * port lock, it is acquired here.
- */
-static __inline__ unsigned char sunzilog_read_channel_status(struct uart_port *port)
-{
-       struct zilog_channel __iomem *channel;
-       unsigned char status;
-
-       channel = ZILOG_CHANNEL_FROM_PORT(port);
-       status = readb(&channel->control);
-       ZSDELAY();
-
-       return status;
-}
-
-/* The port lock is not held.  */
-static unsigned int sunzilog_tx_empty(struct uart_port *port)
-{
-       unsigned long flags;
-       unsigned char status;
-       unsigned int ret;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       status = sunzilog_read_channel_status(port);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       if (status & Tx_BUF_EMP)
-               ret = TIOCSER_TEMT;
-       else
-               ret = 0;
-
-       return ret;
-}
-
-/* The port lock is held and interrupts are disabled.  */
-static unsigned int sunzilog_get_mctrl(struct uart_port *port)
-{
-       unsigned char status;
-       unsigned int ret;
-
-       status = sunzilog_read_channel_status(port);
-
-       ret = 0;
-       if (status & DCD)
-               ret |= TIOCM_CAR;
-       if (status & SYNC)
-               ret |= TIOCM_DSR;
-       if (status & CTS)
-               ret |= TIOCM_CTS;
-
-       return ret;
-}
-
-/* The port lock is held and interrupts are disabled.  */
-static void sunzilog_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
-       struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
-       unsigned char set_bits, clear_bits;
-
-       set_bits = clear_bits = 0;
-
-       if (mctrl & TIOCM_RTS)
-               set_bits |= RTS;
-       else
-               clear_bits |= RTS;
-       if (mctrl & TIOCM_DTR)
-               set_bits |= DTR;
-       else
-               clear_bits |= DTR;
-
-       /* NOTE: Not subject to 'transmitter active' rule.  */ 
-       up->curregs[R5] |= set_bits;
-       up->curregs[R5] &= ~clear_bits;
-       write_zsreg(channel, R5, up->curregs[R5]);
-}
-
-/* The port lock is held and interrupts are disabled.  */
-static void sunzilog_stop_tx(struct uart_port *port)
-{
-       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
-
-       up->flags |= SUNZILOG_FLAG_TX_STOPPED;
-}
-
-/* The port lock is held and interrupts are disabled.  */
-static void sunzilog_start_tx(struct uart_port *port)
-{
-       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
-       struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
-       unsigned char status;
-
-       up->flags |= SUNZILOG_FLAG_TX_ACTIVE;
-       up->flags &= ~SUNZILOG_FLAG_TX_STOPPED;
-
-       status = readb(&channel->control);
-       ZSDELAY();
-
-       /* TX busy?  Just wait for the TX done interrupt.  */
-       if (!(status & Tx_BUF_EMP))
-               return;
-
-       /* Send the first character to jump-start the TX done
-        * IRQ sending engine.
-        */
-       if (port->x_char) {
-               writeb(port->x_char, &channel->data);
-               ZSDELAY();
-               ZS_WSYNC(channel);
-
-               port->icount.tx++;
-               port->x_char = 0;
-       } else {
-               struct circ_buf *xmit = &port->state->xmit;
-
-               writeb(xmit->buf[xmit->tail], &channel->data);
-               ZSDELAY();
-               ZS_WSYNC(channel);
-
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-
-               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-                       uart_write_wakeup(&up->port);
-       }
-}
-
-/* The port lock is held.  */
-static void sunzilog_stop_rx(struct uart_port *port)
-{
-       struct uart_sunzilog_port *up = UART_ZILOG(port);
-       struct zilog_channel __iomem *channel;
-
-       if (ZS_IS_CONS(up))
-               return;
-
-       channel = ZILOG_CHANNEL_FROM_PORT(port);
-
-       /* Disable all RX interrupts.  */
-       up->curregs[R1] &= ~RxINT_MASK;
-       sunzilog_maybe_update_regs(up, channel);
-}
-
-/* The port lock is held.  */
-static void sunzilog_enable_ms(struct uart_port *port)
-{
-       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
-       struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
-       unsigned char new_reg;
-
-       new_reg = up->curregs[R15] | (DCDIE | SYNCIE | CTSIE);
-       if (new_reg != up->curregs[R15]) {
-               up->curregs[R15] = new_reg;
-
-               /* NOTE: Not subject to 'transmitter active' rule.  */ 
-               write_zsreg(channel, R15, up->curregs[R15] & ~WR7pEN);
-       }
-}
-
-/* The port lock is not held.  */
-static void sunzilog_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
-       struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
-       unsigned char set_bits, clear_bits, new_reg;
-       unsigned long flags;
-
-       set_bits = clear_bits = 0;
-
-       if (break_state)
-               set_bits |= SND_BRK;
-       else
-               clear_bits |= SND_BRK;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       new_reg = (up->curregs[R5] | set_bits) & ~clear_bits;
-       if (new_reg != up->curregs[R5]) {
-               up->curregs[R5] = new_reg;
-
-               /* NOTE: Not subject to 'transmitter active' rule.  */ 
-               write_zsreg(channel, R5, up->curregs[R5]);
-       }
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void __sunzilog_startup(struct uart_sunzilog_port *up)
-{
-       struct zilog_channel __iomem *channel;
-
-       channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
-       up->prev_status = readb(&channel->control);
-
-       /* Enable receiver and transmitter.  */
-       up->curregs[R3] |= RxENAB;
-       up->curregs[R5] |= TxENAB;
-
-       up->curregs[R1] |= EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
-       sunzilog_maybe_update_regs(up, channel);
-}
-
-static int sunzilog_startup(struct uart_port *port)
-{
-       struct uart_sunzilog_port *up = UART_ZILOG(port);
-       unsigned long flags;
-
-       if (ZS_IS_CONS(up))
-               return 0;
-
-       spin_lock_irqsave(&port->lock, flags);
-       __sunzilog_startup(up);
-       spin_unlock_irqrestore(&port->lock, flags);
-       return 0;
-}
-
-/*
- * The test for ZS_IS_CONS is explained by the following e-mail:
- *****
- * From: Russell King <rmk@arm.linux.org.uk>
- * Date: Sun, 8 Dec 2002 10:18:38 +0000
- *
- * On Sun, Dec 08, 2002 at 02:43:36AM -0500, Pete Zaitcev wrote:
- * > I boot my 2.5 boxes using "console=ttyS0,9600" argument,
- * > and I noticed that something is not right with reference
- * > counting in this case. It seems that when the console
- * > is open by kernel initially, this is not accounted
- * > as an open, and uart_startup is not called.
- *
- * That is correct.  We are unable to call uart_startup when the serial
- * console is initialised because it may need to allocate memory (as
- * request_irq does) and the memory allocators may not have been
- * initialised.
- *
- * 1. initialise the port into a state where it can send characters in the
- *    console write method.
- *
- * 2. don't do the actual hardware shutdown in your shutdown() method (but
- *    do the normal software shutdown - ie, free irqs etc)
- *****
- */
-static void sunzilog_shutdown(struct uart_port *port)
-{
-       struct uart_sunzilog_port *up = UART_ZILOG(port);
-       struct zilog_channel __iomem *channel;
-       unsigned long flags;
-
-       if (ZS_IS_CONS(up))
-               return;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       channel = ZILOG_CHANNEL_FROM_PORT(port);
-
-       /* Disable receiver and transmitter.  */
-       up->curregs[R3] &= ~RxENAB;
-       up->curregs[R5] &= ~TxENAB;
-
-       /* Disable all interrupts and BRK assertion.  */
-       up->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
-       up->curregs[R5] &= ~SND_BRK;
-       sunzilog_maybe_update_regs(up, channel);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/* Shared by TTY driver and serial console setup.  The port lock is held
- * and local interrupts are disabled.
- */
-static void
-sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag,
-                      unsigned int iflag, int brg)
-{
-
-       up->curregs[R10] = NRZ;
-       up->curregs[R11] = TCBR | RCBR;
-
-       /* Program BAUD and clock source. */
-       up->curregs[R4] &= ~XCLK_MASK;
-       up->curregs[R4] |= X16CLK;
-       up->curregs[R12] = brg & 0xff;
-       up->curregs[R13] = (brg >> 8) & 0xff;
-       up->curregs[R14] = BRSRC | BRENAB;
-
-       /* Character size, stop bits, and parity. */
-       up->curregs[R3] &= ~RxN_MASK;
-       up->curregs[R5] &= ~TxN_MASK;
-       switch (cflag & CSIZE) {
-       case CS5:
-               up->curregs[R3] |= Rx5;
-               up->curregs[R5] |= Tx5;
-               up->parity_mask = 0x1f;
-               break;
-       case CS6:
-               up->curregs[R3] |= Rx6;
-               up->curregs[R5] |= Tx6;
-               up->parity_mask = 0x3f;
-               break;
-       case CS7:
-               up->curregs[R3] |= Rx7;
-               up->curregs[R5] |= Tx7;
-               up->parity_mask = 0x7f;
-               break;
-       case CS8:
-       default:
-               up->curregs[R3] |= Rx8;
-               up->curregs[R5] |= Tx8;
-               up->parity_mask = 0xff;
-               break;
-       };
-       up->curregs[R4] &= ~0x0c;
-       if (cflag & CSTOPB)
-               up->curregs[R4] |= SB2;
-       else
-               up->curregs[R4] |= SB1;
-       if (cflag & PARENB)
-               up->curregs[R4] |= PAR_ENAB;
-       else
-               up->curregs[R4] &= ~PAR_ENAB;
-       if (!(cflag & PARODD))
-               up->curregs[R4] |= PAR_EVEN;
-       else
-               up->curregs[R4] &= ~PAR_EVEN;
-
-       up->port.read_status_mask = Rx_OVR;
-       if (iflag & INPCK)
-               up->port.read_status_mask |= CRC_ERR | PAR_ERR;
-       if (iflag & (BRKINT | PARMRK))
-               up->port.read_status_mask |= BRK_ABRT;
-
-       up->port.ignore_status_mask = 0;
-       if (iflag & IGNPAR)
-               up->port.ignore_status_mask |= CRC_ERR | PAR_ERR;
-       if (iflag & IGNBRK) {
-               up->port.ignore_status_mask |= BRK_ABRT;
-               if (iflag & IGNPAR)
-                       up->port.ignore_status_mask |= Rx_OVR;
-       }
-
-       if ((cflag & CREAD) == 0)
-               up->port.ignore_status_mask = 0xff;
-}
-
-/* The port lock is not held.  */
-static void
-sunzilog_set_termios(struct uart_port *port, struct ktermios *termios,
-                    struct ktermios *old)
-{
-       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
-       unsigned long flags;
-       int baud, brg;
-
-       baud = uart_get_baud_rate(port, termios, old, 1200, 76800);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
-
-       sunzilog_convert_to_zs(up, termios->c_cflag, termios->c_iflag, brg);
-
-       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
-               up->flags |= SUNZILOG_FLAG_MODEM_STATUS;
-       else
-               up->flags &= ~SUNZILOG_FLAG_MODEM_STATUS;
-
-       up->cflag = termios->c_cflag;
-
-       sunzilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port));
-
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static const char *sunzilog_type(struct uart_port *port)
-{
-       struct uart_sunzilog_port *up = UART_ZILOG(port);
-
-       return (up->flags & SUNZILOG_FLAG_ESCC) ? "zs (ESCC)" : "zs";
-}
-
-/* We do not request/release mappings of the registers here, this
- * happens at early serial probe time.
- */
-static void sunzilog_release_port(struct uart_port *port)
-{
-}
-
-static int sunzilog_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-/* These do not need to do anything interesting either.  */
-static void sunzilog_config_port(struct uart_port *port, int flags)
-{
-}
-
-/* We do not support letting the user mess with the divisor, IRQ, etc. */
-static int sunzilog_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       return -EINVAL;
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-static int sunzilog_get_poll_char(struct uart_port *port)
-{
-       unsigned char ch, r1;
-       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
-       struct zilog_channel __iomem *channel
-               = ZILOG_CHANNEL_FROM_PORT(&up->port);
-
-
-       r1 = read_zsreg(channel, R1);
-       if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
-               writeb(ERR_RES, &channel->control);
-               ZSDELAY();
-               ZS_WSYNC(channel);
-       }
-
-       ch = readb(&channel->control);
-       ZSDELAY();
-
-       /* This funny hack depends upon BRK_ABRT not interfering
-        * with the other bits we care about in R1.
-        */
-       if (ch & BRK_ABRT)
-               r1 |= BRK_ABRT;
-
-       if (!(ch & Rx_CH_AV))
-               return NO_POLL_CHAR;
-
-       ch = readb(&channel->data);
-       ZSDELAY();
-
-       ch &= up->parity_mask;
-       return ch;
-}
-
-static void sunzilog_put_poll_char(struct uart_port *port,
-                       unsigned char ch)
-{
-       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *)port;
-
-       sunzilog_putchar(&up->port, ch);
-}
-#endif /* CONFIG_CONSOLE_POLL */
-
-static struct uart_ops sunzilog_pops = {
-       .tx_empty       =       sunzilog_tx_empty,
-       .set_mctrl      =       sunzilog_set_mctrl,
-       .get_mctrl      =       sunzilog_get_mctrl,
-       .stop_tx        =       sunzilog_stop_tx,
-       .start_tx       =       sunzilog_start_tx,
-       .stop_rx        =       sunzilog_stop_rx,
-       .enable_ms      =       sunzilog_enable_ms,
-       .break_ctl      =       sunzilog_break_ctl,
-       .startup        =       sunzilog_startup,
-       .shutdown       =       sunzilog_shutdown,
-       .set_termios    =       sunzilog_set_termios,
-       .type           =       sunzilog_type,
-       .release_port   =       sunzilog_release_port,
-       .request_port   =       sunzilog_request_port,
-       .config_port    =       sunzilog_config_port,
-       .verify_port    =       sunzilog_verify_port,
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_get_char  =       sunzilog_get_poll_char,
-       .poll_put_char  =       sunzilog_put_poll_char,
-#endif
-};
-
-static int uart_chip_count;
-static struct uart_sunzilog_port *sunzilog_port_table;
-static struct zilog_layout __iomem **sunzilog_chip_regs;
-
-static struct uart_sunzilog_port *sunzilog_irq_chain;
-
-static struct uart_driver sunzilog_reg = {
-       .owner          =       THIS_MODULE,
-       .driver_name    =       "sunzilog",
-       .dev_name       =       "ttyS",
-       .major          =       TTY_MAJOR,
-};
-
-static int __init sunzilog_alloc_tables(int num_sunzilog)
-{
-       struct uart_sunzilog_port *up;
-       unsigned long size;
-       int num_channels = num_sunzilog * 2;
-       int i;
-
-       size = num_channels * sizeof(struct uart_sunzilog_port);
-       sunzilog_port_table = kzalloc(size, GFP_KERNEL);
-       if (!sunzilog_port_table)
-               return -ENOMEM;
-
-       for (i = 0; i < num_channels; i++) {
-               up = &sunzilog_port_table[i];
-
-               spin_lock_init(&up->port.lock);
-
-               if (i == 0)
-                       sunzilog_irq_chain = up;
-
-               if (i < num_channels - 1)
-                       up->next = up + 1;
-               else
-                       up->next = NULL;
-       }
-
-       size = num_sunzilog * sizeof(struct zilog_layout __iomem *);
-       sunzilog_chip_regs = kzalloc(size, GFP_KERNEL);
-       if (!sunzilog_chip_regs) {
-               kfree(sunzilog_port_table);
-               sunzilog_irq_chain = NULL;
-               return -ENOMEM;
-       }
-
-       return 0;
-}
-
-static void sunzilog_free_tables(void)
-{
-       kfree(sunzilog_port_table);
-       sunzilog_irq_chain = NULL;
-       kfree(sunzilog_chip_regs);
-}
-
-#define ZS_PUT_CHAR_MAX_DELAY  2000    /* 10 ms */
-
-static void sunzilog_putchar(struct uart_port *port, int ch)
-{
-       struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
-       int loops = ZS_PUT_CHAR_MAX_DELAY;
-
-       /* This is a timed polling loop so do not switch the explicit
-        * udelay with ZSDELAY as that is a NOP on some platforms.  -DaveM
-        */
-       do {
-               unsigned char val = readb(&channel->control);
-               if (val & Tx_BUF_EMP) {
-                       ZSDELAY();
-                       break;
-               }
-               udelay(5);
-       } while (--loops);
-
-       writeb(ch, &channel->data);
-       ZSDELAY();
-       ZS_WSYNC(channel);
-}
-
-#ifdef CONFIG_SERIO
-
-static DEFINE_SPINLOCK(sunzilog_serio_lock);
-
-static int sunzilog_serio_write(struct serio *serio, unsigned char ch)
-{
-       struct uart_sunzilog_port *up = serio->port_data;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sunzilog_serio_lock, flags);
-
-       sunzilog_putchar(&up->port, ch);
-
-       spin_unlock_irqrestore(&sunzilog_serio_lock, flags);
-
-       return 0;
-}
-
-static int sunzilog_serio_open(struct serio *serio)
-{
-       struct uart_sunzilog_port *up = serio->port_data;
-       unsigned long flags;
-       int ret;
-
-       spin_lock_irqsave(&sunzilog_serio_lock, flags);
-       if (!up->serio_open) {
-               up->serio_open = 1;
-               ret = 0;
-       } else
-               ret = -EBUSY;
-       spin_unlock_irqrestore(&sunzilog_serio_lock, flags);
-
-       return ret;
-}
-
-static void sunzilog_serio_close(struct serio *serio)
-{
-       struct uart_sunzilog_port *up = serio->port_data;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sunzilog_serio_lock, flags);
-       up->serio_open = 0;
-       spin_unlock_irqrestore(&sunzilog_serio_lock, flags);
-}
-
-#endif /* CONFIG_SERIO */
-
-#ifdef CONFIG_SERIAL_SUNZILOG_CONSOLE
-static void
-sunzilog_console_write(struct console *con, const char *s, unsigned int count)
-{
-       struct uart_sunzilog_port *up = &sunzilog_port_table[con->index];
-       unsigned long flags;
-       int locked = 1;
-
-       local_irq_save(flags);
-       if (up->port.sysrq) {
-               locked = 0;
-       } else if (oops_in_progress) {
-               locked = spin_trylock(&up->port.lock);
-       } else
-               spin_lock(&up->port.lock);
-
-       uart_console_write(&up->port, s, count, sunzilog_putchar);
-       udelay(2);
-
-       if (locked)
-               spin_unlock(&up->port.lock);
-       local_irq_restore(flags);
-}
-
-static int __init sunzilog_console_setup(struct console *con, char *options)
-{
-       struct uart_sunzilog_port *up = &sunzilog_port_table[con->index];
-       unsigned long flags;
-       int baud, brg;
-
-       if (up->port.type != PORT_SUNZILOG)
-               return -1;
-
-       printk(KERN_INFO "Console: ttyS%d (SunZilog zs%d)\n",
-              (sunzilog_reg.minor - 64) + con->index, con->index);
-
-       /* Get firmware console settings.  */
-       sunserial_console_termios(con, up->port.dev->of_node);
-
-       /* Firmware console speed is limited to 150-->38400 baud so
-        * this hackish cflag thing is OK.
-        */
-       switch (con->cflag & CBAUD) {
-       case B150: baud = 150; break;
-       case B300: baud = 300; break;
-       case B600: baud = 600; break;
-       case B1200: baud = 1200; break;
-       case B2400: baud = 2400; break;
-       case B4800: baud = 4800; break;
-       default: case B9600: baud = 9600; break;
-       case B19200: baud = 19200; break;
-       case B38400: baud = 38400; break;
-       };
-
-       brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       up->curregs[R15] |= BRKIE;
-       sunzilog_convert_to_zs(up, con->cflag, 0, brg);
-
-       sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
-       __sunzilog_startup(up);
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       return 0;
-}
-
-static struct console sunzilog_console_ops = {
-       .name   =       "ttyS",
-       .write  =       sunzilog_console_write,
-       .device =       uart_console_device,
-       .setup  =       sunzilog_console_setup,
-       .flags  =       CON_PRINTBUFFER,
-       .index  =       -1,
-       .data   =       &sunzilog_reg,
-};
-
-static inline struct console *SUNZILOG_CONSOLE(void)
-{
-       return &sunzilog_console_ops;
-}
-
-#else
-#define SUNZILOG_CONSOLE()     (NULL)
-#endif
-
-static void __devinit sunzilog_init_kbdms(struct uart_sunzilog_port *up)
-{
-       int baud, brg;
-
-       if (up->flags & SUNZILOG_FLAG_CONS_KEYB) {
-               up->cflag = B1200 | CS8 | CLOCAL | CREAD;
-               baud = 1200;
-       } else {
-               up->cflag = B4800 | CS8 | CLOCAL | CREAD;
-               baud = 4800;
-       }
-
-       up->curregs[R15] |= BRKIE;
-       brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
-       sunzilog_convert_to_zs(up, up->cflag, 0, brg);
-       sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
-       __sunzilog_startup(up);
-}
-
-#ifdef CONFIG_SERIO
-static void __devinit sunzilog_register_serio(struct uart_sunzilog_port *up)
-{
-       struct serio *serio = &up->serio;
-
-       serio->port_data = up;
-
-       serio->id.type = SERIO_RS232;
-       if (up->flags & SUNZILOG_FLAG_CONS_KEYB) {
-               serio->id.proto = SERIO_SUNKBD;
-               strlcpy(serio->name, "zskbd", sizeof(serio->name));
-       } else {
-               serio->id.proto = SERIO_SUN;
-               serio->id.extra = 1;
-               strlcpy(serio->name, "zsms", sizeof(serio->name));
-       }
-       strlcpy(serio->phys,
-               ((up->flags & SUNZILOG_FLAG_CONS_KEYB) ?
-                "zs/serio0" : "zs/serio1"),
-               sizeof(serio->phys));
-
-       serio->write = sunzilog_serio_write;
-       serio->open = sunzilog_serio_open;
-       serio->close = sunzilog_serio_close;
-       serio->dev.parent = up->port.dev;
-
-       serio_register_port(serio);
-}
-#endif
-
-static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
-{
-       struct zilog_channel __iomem *channel;
-       unsigned long flags;
-       int baud, brg;
-
-       channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       if (ZS_IS_CHANNEL_A(up)) {
-               write_zsreg(channel, R9, FHWRES);
-               ZSDELAY_LONG();
-               (void) read_zsreg(channel, R0);
-       }
-
-       if (up->flags & (SUNZILOG_FLAG_CONS_KEYB |
-                        SUNZILOG_FLAG_CONS_MOUSE)) {
-               up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
-               up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
-               up->curregs[R3] = RxENAB | Rx8;
-               up->curregs[R5] = TxENAB | Tx8;
-               up->curregs[R6] = 0x00; /* SDLC Address */
-               up->curregs[R7] = 0x7E; /* SDLC Flag    */
-               up->curregs[R9] = NV;
-               up->curregs[R7p] = 0x00;
-               sunzilog_init_kbdms(up);
-               /* Only enable interrupts if an ISR handler available */
-               if (up->flags & SUNZILOG_FLAG_ISR_HANDLER)
-                       up->curregs[R9] |= MIE;
-               write_zsreg(channel, R9, up->curregs[R9]);
-       } else {
-               /* Normal serial TTY. */
-               up->parity_mask = 0xff;
-               up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
-               up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
-               up->curregs[R3] = RxENAB | Rx8;
-               up->curregs[R5] = TxENAB | Tx8;
-               up->curregs[R6] = 0x00; /* SDLC Address */
-               up->curregs[R7] = 0x7E; /* SDLC Flag    */
-               up->curregs[R9] = NV;
-               up->curregs[R10] = NRZ;
-               up->curregs[R11] = TCBR | RCBR;
-               baud = 9600;
-               brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
-               up->curregs[R12] = (brg & 0xff);
-               up->curregs[R13] = (brg >> 8) & 0xff;
-               up->curregs[R14] = BRSRC | BRENAB;
-               up->curregs[R15] = FIFOEN; /* Use FIFO if on ESCC */
-               up->curregs[R7p] = TxFIFO_LVL | RxFIFO_LVL;
-               if (__load_zsregs(channel, up->curregs)) {
-                       up->flags |= SUNZILOG_FLAG_ESCC;
-               }
-               /* Only enable interrupts if an ISR handler available */
-               if (up->flags & SUNZILOG_FLAG_ISR_HANDLER)
-                       up->curregs[R9] |= MIE;
-               write_zsreg(channel, R9, up->curregs[R9]);
-       }
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-#ifdef CONFIG_SERIO
-       if (up->flags & (SUNZILOG_FLAG_CONS_KEYB |
-                        SUNZILOG_FLAG_CONS_MOUSE))
-               sunzilog_register_serio(up);
-#endif
-}
-
-static int zilog_irq = -1;
-
-static int __devinit zs_probe(struct platform_device *op, const struct of_device_id *match)
-{
-       static int kbm_inst, uart_inst;
-       int inst;
-       struct uart_sunzilog_port *up;
-       struct zilog_layout __iomem *rp;
-       int keyboard_mouse = 0;
-       int err;
-
-       if (of_find_property(op->dev.of_node, "keyboard", NULL))
-               keyboard_mouse = 1;
-
-       /* uarts must come before keyboards/mice */
-       if (keyboard_mouse)
-               inst = uart_chip_count + kbm_inst;
-       else
-               inst = uart_inst;
-
-       sunzilog_chip_regs[inst] = of_ioremap(&op->resource[0], 0,
-                                             sizeof(struct zilog_layout),
-                                             "zs");
-       if (!sunzilog_chip_regs[inst])
-               return -ENOMEM;
-
-       rp = sunzilog_chip_regs[inst];
-
-       if (zilog_irq == -1)
-               zilog_irq = op->archdata.irqs[0];
-
-       up = &sunzilog_port_table[inst * 2];
-
-       /* Channel A */
-       up[0].port.mapbase = op->resource[0].start + 0x00;
-       up[0].port.membase = (void __iomem *) &rp->channelA;
-       up[0].port.iotype = UPIO_MEM;
-       up[0].port.irq = op->archdata.irqs[0];
-       up[0].port.uartclk = ZS_CLOCK;
-       up[0].port.fifosize = 1;
-       up[0].port.ops = &sunzilog_pops;
-       up[0].port.type = PORT_SUNZILOG;
-       up[0].port.flags = 0;
-       up[0].port.line = (inst * 2) + 0;
-       up[0].port.dev = &op->dev;
-       up[0].flags |= SUNZILOG_FLAG_IS_CHANNEL_A;
-       if (keyboard_mouse)
-               up[0].flags |= SUNZILOG_FLAG_CONS_KEYB;
-       sunzilog_init_hw(&up[0]);
-
-       /* Channel B */
-       up[1].port.mapbase = op->resource[0].start + 0x04;
-       up[1].port.membase = (void __iomem *) &rp->channelB;
-       up[1].port.iotype = UPIO_MEM;
-       up[1].port.irq = op->archdata.irqs[0];
-       up[1].port.uartclk = ZS_CLOCK;
-       up[1].port.fifosize = 1;
-       up[1].port.ops = &sunzilog_pops;
-       up[1].port.type = PORT_SUNZILOG;
-       up[1].port.flags = 0;
-       up[1].port.line = (inst * 2) + 1;
-       up[1].port.dev = &op->dev;
-       up[1].flags |= 0;
-       if (keyboard_mouse)
-               up[1].flags |= SUNZILOG_FLAG_CONS_MOUSE;
-       sunzilog_init_hw(&up[1]);
-
-       if (!keyboard_mouse) {
-               if (sunserial_console_match(SUNZILOG_CONSOLE(), op->dev.of_node,
-                                           &sunzilog_reg, up[0].port.line,
-                                           false))
-                       up->flags |= SUNZILOG_FLAG_IS_CONS;
-               err = uart_add_one_port(&sunzilog_reg, &up[0].port);
-               if (err) {
-                       of_iounmap(&op->resource[0],
-                                  rp, sizeof(struct zilog_layout));
-                       return err;
-               }
-               if (sunserial_console_match(SUNZILOG_CONSOLE(), op->dev.of_node,
-                                           &sunzilog_reg, up[1].port.line,
-                                           false))
-                       up->flags |= SUNZILOG_FLAG_IS_CONS;
-               err = uart_add_one_port(&sunzilog_reg, &up[1].port);
-               if (err) {
-                       uart_remove_one_port(&sunzilog_reg, &up[0].port);
-                       of_iounmap(&op->resource[0],
-                                  rp, sizeof(struct zilog_layout));
-                       return err;
-               }
-               uart_inst++;
-       } else {
-               printk(KERN_INFO "%s: Keyboard at MMIO 0x%llx (irq = %d) "
-                      "is a %s\n",
-                      dev_name(&op->dev),
-                      (unsigned long long) up[0].port.mapbase,
-                      op->archdata.irqs[0], sunzilog_type(&up[0].port));
-               printk(KERN_INFO "%s: Mouse at MMIO 0x%llx (irq = %d) "
-                      "is a %s\n",
-                      dev_name(&op->dev),
-                      (unsigned long long) up[1].port.mapbase,
-                      op->archdata.irqs[0], sunzilog_type(&up[1].port));
-               kbm_inst++;
-       }
-
-       dev_set_drvdata(&op->dev, &up[0]);
-
-       return 0;
-}
-
-static void __devexit zs_remove_one(struct uart_sunzilog_port *up)
-{
-       if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) {
-#ifdef CONFIG_SERIO
-               serio_unregister_port(&up->serio);
-#endif
-       } else
-               uart_remove_one_port(&sunzilog_reg, &up->port);
-}
-
-static int __devexit zs_remove(struct platform_device *op)
-{
-       struct uart_sunzilog_port *up = dev_get_drvdata(&op->dev);
-       struct zilog_layout __iomem *regs;
-
-       zs_remove_one(&up[0]);
-       zs_remove_one(&up[1]);
-
-       regs = sunzilog_chip_regs[up[0].port.line / 2];
-       of_iounmap(&op->resource[0], regs, sizeof(struct zilog_layout));
-
-       dev_set_drvdata(&op->dev, NULL);
-
-       return 0;
-}
-
-static const struct of_device_id zs_match[] = {
-       {
-               .name = "zs",
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(of, zs_match);
-
-static struct of_platform_driver zs_driver = {
-       .driver = {
-               .name = "zs",
-               .owner = THIS_MODULE,
-               .of_match_table = zs_match,
-       },
-       .probe          = zs_probe,
-       .remove         = __devexit_p(zs_remove),
-};
-
-static int __init sunzilog_init(void)
-{
-       struct device_node *dp;
-       int err;
-       int num_keybms = 0;
-       int num_sunzilog = 0;
-
-       for_each_node_by_name(dp, "zs") {
-               num_sunzilog++;
-               if (of_find_property(dp, "keyboard", NULL))
-                       num_keybms++;
-       }
-
-       if (num_sunzilog) {
-               err = sunzilog_alloc_tables(num_sunzilog);
-               if (err)
-                       goto out;
-
-               uart_chip_count = num_sunzilog - num_keybms;
-
-               err = sunserial_register_minors(&sunzilog_reg,
-                                               uart_chip_count * 2);
-               if (err)
-                       goto out_free_tables;
-       }
-
-       err = of_register_platform_driver(&zs_driver);
-       if (err)
-               goto out_unregister_uart;
-
-       if (zilog_irq != -1) {
-               struct uart_sunzilog_port *up = sunzilog_irq_chain;
-               err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED,
-                                 "zs", sunzilog_irq_chain);
-               if (err)
-                       goto out_unregister_driver;
-
-               /* Enable Interrupts */
-               while (up) {
-                       struct zilog_channel __iomem *channel;
-
-                       /* printk (KERN_INFO "Enable IRQ for ZILOG Hardware %p\n", up); */
-                       channel          = ZILOG_CHANNEL_FROM_PORT(&up->port);
-                       up->flags       |= SUNZILOG_FLAG_ISR_HANDLER;
-                       up->curregs[R9] |= MIE;
-                       write_zsreg(channel, R9, up->curregs[R9]);
-                       up = up->next;
-               }
-       }
-
-out:
-       return err;
-
-out_unregister_driver:
-       of_unregister_platform_driver(&zs_driver);
-
-out_unregister_uart:
-       if (num_sunzilog) {
-               sunserial_unregister_minors(&sunzilog_reg, num_sunzilog);
-               sunzilog_reg.cons = NULL;
-       }
-
-out_free_tables:
-       sunzilog_free_tables();
-       goto out;
-}
-
-static void __exit sunzilog_exit(void)
-{
-       of_unregister_platform_driver(&zs_driver);
-
-       if (zilog_irq != -1) {
-               struct uart_sunzilog_port *up = sunzilog_irq_chain;
-
-               /* Disable Interrupts */
-               while (up) {
-                       struct zilog_channel __iomem *channel;
-
-                       /* printk (KERN_INFO "Disable IRQ for ZILOG Hardware %p\n", up); */
-                       channel          = ZILOG_CHANNEL_FROM_PORT(&up->port);
-                       up->flags       &= ~SUNZILOG_FLAG_ISR_HANDLER;
-                       up->curregs[R9] &= ~MIE;
-                       write_zsreg(channel, R9, up->curregs[R9]);
-                       up = up->next;
-               }
-
-               free_irq(zilog_irq, sunzilog_irq_chain);
-               zilog_irq = -1;
-       }
-
-       if (sunzilog_reg.nr) {
-               sunserial_unregister_minors(&sunzilog_reg, sunzilog_reg.nr);
-               sunzilog_free_tables();
-       }
-}
-
-module_init(sunzilog_init);
-module_exit(sunzilog_exit);
-
-MODULE_AUTHOR("David S. Miller");
-MODULE_DESCRIPTION("Sun Zilog serial port driver");
-MODULE_VERSION("2.0");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/sunzilog.h b/drivers/serial/sunzilog.h
deleted file mode 100644 (file)
index 5dec7b4..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-#ifndef _SUNZILOG_H
-#define _SUNZILOG_H
-
-struct zilog_channel {
-       volatile unsigned char control;
-       volatile unsigned char __pad1;
-       volatile unsigned char data;
-       volatile unsigned char __pad2;
-};
-
-struct zilog_layout {
-       struct zilog_channel channelB;
-       struct zilog_channel channelA;
-};
-
-#define        NUM_ZSREGS      17
-#define        R7p             16 /* Written as R7 with P15 bit 0 set */
-
-/* Conversion routines to/from brg time constants from/to bits
- * per second.
- */
-#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
-#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
-
-/* The Zilog register set */
-
-#define        FLAG    0x7e
-
-/* Write Register 0 */
-#define        R0      0               /* Register selects */
-#define        R1      1
-#define        R2      2
-#define        R3      3
-#define        R4      4
-#define        R5      5
-#define        R6      6
-#define        R7      7
-#define        R8      8
-#define        R9      9
-#define        R10     10
-#define        R11     11
-#define        R12     12
-#define        R13     13
-#define        R14     14
-#define        R15     15
-
-#define        NULLCODE        0       /* Null Code */
-#define        POINT_HIGH      0x8     /* Select upper half of registers */
-#define        RES_EXT_INT     0x10    /* Reset Ext. Status Interrupts */
-#define        SEND_ABORT      0x18    /* HDLC Abort */
-#define        RES_RxINT_FC    0x20    /* Reset RxINT on First Character */
-#define        RES_Tx_P        0x28    /* Reset TxINT Pending */
-#define        ERR_RES         0x30    /* Error Reset */
-#define        RES_H_IUS       0x38    /* Reset highest IUS */
-
-#define        RES_Rx_CRC      0x40    /* Reset Rx CRC Checker */
-#define        RES_Tx_CRC      0x80    /* Reset Tx CRC Checker */
-#define        RES_EOM_L       0xC0    /* Reset EOM latch */
-
-/* Write Register 1 */
-
-#define        EXT_INT_ENAB    0x1     /* Ext Int Enable */
-#define        TxINT_ENAB      0x2     /* Tx Int Enable */
-#define        PAR_SPEC        0x4     /* Parity is special condition */
-
-#define        RxINT_DISAB     0       /* Rx Int Disable */
-#define        RxINT_FCERR     0x8     /* Rx Int on First Character Only or Error */
-#define        INT_ALL_Rx      0x10    /* Int on all Rx Characters or error */
-#define        INT_ERR_Rx      0x18    /* Int on error only */
-#define RxINT_MASK     0x18
-
-#define        WT_RDY_RT       0x20    /* Wait/Ready on R/T */
-#define        WT_FN_RDYFN     0x40    /* Wait/FN/Ready FN */
-#define        WT_RDY_ENAB     0x80    /* Wait/Ready Enable */
-
-/* Write Register #2 (Interrupt Vector) */
-
-/* Write Register 3 */
-
-#define        RxENAB          0x1     /* Rx Enable */
-#define        SYNC_L_INH      0x2     /* Sync Character Load Inhibit */
-#define        ADD_SM          0x4     /* Address Search Mode (SDLC) */
-#define        RxCRC_ENAB      0x8     /* Rx CRC Enable */
-#define        ENT_HM          0x10    /* Enter Hunt Mode */
-#define        AUTO_ENAB       0x20    /* Auto Enables */
-#define        Rx5             0x0     /* Rx 5 Bits/Character */
-#define        Rx7             0x40    /* Rx 7 Bits/Character */
-#define        Rx6             0x80    /* Rx 6 Bits/Character */
-#define        Rx8             0xc0    /* Rx 8 Bits/Character */
-#define RxN_MASK       0xc0
-
-/* Write Register 4 */
-
-#define        PAR_ENAB        0x1     /* Parity Enable */
-#define        PAR_EVEN        0x2     /* Parity Even/Odd* */
-
-#define        SYNC_ENAB       0       /* Sync Modes Enable */
-#define        SB1             0x4     /* 1 stop bit/char */
-#define        SB15            0x8     /* 1.5 stop bits/char */
-#define        SB2             0xc     /* 2 stop bits/char */
-
-#define        MONSYNC         0       /* 8 Bit Sync character */
-#define        BISYNC          0x10    /* 16 bit sync character */
-#define        SDLC            0x20    /* SDLC Mode (01111110 Sync Flag) */
-#define        EXTSYNC         0x30    /* External Sync Mode */
-
-#define        X1CLK           0x0     /* x1 clock mode */
-#define        X16CLK          0x40    /* x16 clock mode */
-#define        X32CLK          0x80    /* x32 clock mode */
-#define        X64CLK          0xC0    /* x64 clock mode */
-#define XCLK_MASK      0xC0
-
-/* Write Register 5 */
-
-#define        TxCRC_ENAB      0x1     /* Tx CRC Enable */
-#define        RTS             0x2     /* RTS */
-#define        SDLC_CRC        0x4     /* SDLC/CRC-16 */
-#define        TxENAB          0x8     /* Tx Enable */
-#define        SND_BRK         0x10    /* Send Break */
-#define        Tx5             0x0     /* Tx 5 bits (or less)/character */
-#define        Tx7             0x20    /* Tx 7 bits/character */
-#define        Tx6             0x40    /* Tx 6 bits/character */
-#define        Tx8             0x60    /* Tx 8 bits/character */
-#define TxN_MASK       0x60
-#define        DTR             0x80    /* DTR */
-
-/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
-
-/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
-
-/* Write Register 7' (ESCC Only) */
-#define        AUTO_TxFLAG     1       /* Automatic Tx SDLC Flag */
-#define        AUTO_EOM_RST    2       /* Automatic EOM Reset */
-#define        AUTOnRTS        4       /* Automatic /RTS pin deactivation */
-#define        RxFIFO_LVL      8       /* Receive FIFO interrupt level */
-#define        nDTRnREQ        0x10    /* /DTR/REQ timing */
-#define        TxFIFO_LVL      0x20    /* Transmit FIFO interrupt level */
-#define        EXT_RD_EN       0x40    /* Extended read register enable */
-
-/* Write Register 8 (transmit buffer) */
-
-/* Write Register 9 (Master interrupt control) */
-#define        VIS     1       /* Vector Includes Status */
-#define        NV      2       /* No Vector */
-#define        DLC     4       /* Disable Lower Chain */
-#define        MIE     8       /* Master Interrupt Enable */
-#define        STATHI  0x10    /* Status high */
-#define        SWIACK  0x20    /* Software Interrupt Ack (not on NMOS) */
-#define        NORESET 0       /* No reset on write to R9 */
-#define        CHRB    0x40    /* Reset channel B */
-#define        CHRA    0x80    /* Reset channel A */
-#define        FHWRES  0xc0    /* Force hardware reset */
-
-/* Write Register 10 (misc control bits) */
-#define        BIT6    1       /* 6 bit/8bit sync */
-#define        LOOPMODE 2      /* SDLC Loop mode */
-#define        ABUNDER 4       /* Abort/flag on SDLC xmit underrun */
-#define        MARKIDLE 8      /* Mark/flag on idle */
-#define        GAOP    0x10    /* Go active on poll */
-#define        NRZ     0       /* NRZ mode */
-#define        NRZI    0x20    /* NRZI mode */
-#define        FM1     0x40    /* FM1 (transition = 1) */
-#define        FM0     0x60    /* FM0 (transition = 0) */
-#define        CRCPS   0x80    /* CRC Preset I/O */
-
-/* Write Register 11 (Clock Mode control) */
-#define        TRxCXT  0       /* TRxC = Xtal output */
-#define        TRxCTC  1       /* TRxC = Transmit clock */
-#define        TRxCBR  2       /* TRxC = BR Generator Output */
-#define        TRxCDP  3       /* TRxC = DPLL output */
-#define        TRxCOI  4       /* TRxC O/I */
-#define        TCRTxCP 0       /* Transmit clock = RTxC pin */
-#define        TCTRxCP 8       /* Transmit clock = TRxC pin */
-#define        TCBR    0x10    /* Transmit clock = BR Generator output */
-#define        TCDPLL  0x18    /* Transmit clock = DPLL output */
-#define        RCRTxCP 0       /* Receive clock = RTxC pin */
-#define        RCTRxCP 0x20    /* Receive clock = TRxC pin */
-#define        RCBR    0x40    /* Receive clock = BR Generator output */
-#define        RCDPLL  0x60    /* Receive clock = DPLL output */
-#define        RTxCX   0x80    /* RTxC Xtal/No Xtal */
-
-/* Write Register 12 (lower byte of baud rate generator time constant) */
-
-/* Write Register 13 (upper byte of baud rate generator time constant) */
-
-/* Write Register 14 (Misc control bits) */
-#define        BRENAB  1       /* Baud rate generator enable */
-#define        BRSRC   2       /* Baud rate generator source */
-#define        DTRREQ  4       /* DTR/Request function */
-#define        AUTOECHO 8      /* Auto Echo */
-#define        LOOPBAK 0x10    /* Local loopback */
-#define        SEARCH  0x20    /* Enter search mode */
-#define        RMC     0x40    /* Reset missing clock */
-#define        DISDPLL 0x60    /* Disable DPLL */
-#define        SSBR    0x80    /* Set DPLL source = BR generator */
-#define        SSRTxC  0xa0    /* Set DPLL source = RTxC */
-#define        SFMM    0xc0    /* Set FM mode */
-#define        SNRZI   0xe0    /* Set NRZI mode */
-
-/* Write Register 15 (external/status interrupt control) */
-#define        WR7pEN  1       /* WR7' Enable (ESCC only) */
-#define        ZCIE    2       /* Zero count IE */
-#define        FIFOEN  4       /* FIFO Enable (ESCC only) */
-#define        DCDIE   8       /* DCD IE */
-#define        SYNCIE  0x10    /* Sync/hunt IE */
-#define        CTSIE   0x20    /* CTS IE */
-#define        TxUIE   0x40    /* Tx Underrun/EOM IE */
-#define        BRKIE   0x80    /* Break/Abort IE */
-
-
-/* Read Register 0 */
-#define        Rx_CH_AV        0x1     /* Rx Character Available */
-#define        ZCOUNT          0x2     /* Zero count */
-#define        Tx_BUF_EMP      0x4     /* Tx Buffer empty */
-#define        DCD             0x8     /* DCD */
-#define        SYNC            0x10    /* Sync/hunt */
-#define        CTS             0x20    /* CTS */
-#define        TxEOM           0x40    /* Tx underrun */
-#define        BRK_ABRT        0x80    /* Break/Abort */
-
-/* Read Register 1 */
-#define        ALL_SNT         0x1     /* All sent */
-/* Residue Data for 8 Rx bits/char programmed */
-#define        RES3            0x8     /* 0/3 */
-#define        RES4            0x4     /* 0/4 */
-#define        RES5            0xc     /* 0/5 */
-#define        RES6            0x2     /* 0/6 */
-#define        RES7            0xa     /* 0/7 */
-#define        RES8            0x6     /* 0/8 */
-#define        RES18           0xe     /* 1/8 */
-#define        RES28           0x0     /* 2/8 */
-/* Special Rx Condition Interrupts */
-#define        PAR_ERR         0x10    /* Parity error */
-#define        Rx_OVR          0x20    /* Rx Overrun Error */
-#define        CRC_ERR         0x40    /* CRC/Framing Error */
-#define        END_FR          0x80    /* End of Frame (SDLC) */
-
-/* Read Register 2 (channel b only) - Interrupt vector */
-#define CHB_Tx_EMPTY   0x00
-#define CHB_EXT_STAT   0x02
-#define CHB_Rx_AVAIL   0x04
-#define CHB_SPECIAL    0x06
-#define CHA_Tx_EMPTY   0x08
-#define CHA_EXT_STAT   0x0a
-#define CHA_Rx_AVAIL   0x0c
-#define CHA_SPECIAL    0x0e
-#define STATUS_MASK    0x0e
-
-/* Read Register 3 (interrupt pending register) ch a only */
-#define        CHBEXT  0x1             /* Channel B Ext/Stat IP */
-#define        CHBTxIP 0x2             /* Channel B Tx IP */
-#define        CHBRxIP 0x4             /* Channel B Rx IP */
-#define        CHAEXT  0x8             /* Channel A Ext/Stat IP */
-#define        CHATxIP 0x10            /* Channel A Tx IP */
-#define        CHARxIP 0x20            /* Channel A Rx IP */
-
-/* Read Register 6 (LSB frame byte count [Not on NMOS]) */
-
-/* Read Register 7 (MSB frame byte count and FIFO status [Not on NMOS]) */
-
-/* Read Register 8 (receive data register) */
-
-/* Read Register 10  (misc status bits) */
-#define        ONLOOP  2               /* On loop */
-#define        LOOPSEND 0x10           /* Loop sending */
-#define        CLK2MIS 0x40            /* Two clocks missing */
-#define        CLK1MIS 0x80            /* One clock missing */
-
-/* Read Register 12 (lower byte of baud rate generator constant) */
-
-/* Read Register 13 (upper byte of baud rate generator constant) */
-
-/* Read Register 15 (value of WR 15) */
-
-/* Misc macros */
-#define ZS_CLEARERR(channel)    do { sbus_writeb(ERR_RES, &channel->control); \
-                                    udelay(5); } while(0)
-
-#define ZS_CLEARSTAT(channel)   do { sbus_writeb(RES_EXT_INT, &channel->control); \
-                                    udelay(5); } while(0)
-
-#define ZS_CLEARFIFO(channel)   do { sbus_readb(&channel->data); \
-                                    udelay(2); \
-                                    sbus_readb(&channel->data); \
-                                    udelay(2); \
-                                    sbus_readb(&channel->data); \
-                                    udelay(2); } while(0)
-
-#endif /* _SUNZILOG_H */
diff --git a/drivers/serial/timbuart.c b/drivers/serial/timbuart.c
deleted file mode 100644 (file)
index 1f36b7e..0000000
+++ /dev/null
@@ -1,531 +0,0 @@
-/*
- * timbuart.c timberdale FPGA UART driver
- * Copyright (c) 2009 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
- */
-
-/* Supports:
- * Timberdale FPGA UART
- */
-
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/serial_core.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-
-#include "timbuart.h"
-
-struct timbuart_port {
-       struct uart_port        port;
-       struct tasklet_struct   tasklet;
-       int                     usedma;
-       u32                     last_ier;
-       struct platform_device  *dev;
-};
-
-static int baudrates[] = {9600, 19200, 38400, 57600, 115200, 230400, 460800,
-       921600, 1843200, 3250000};
-
-static void timbuart_mctrl_check(struct uart_port *port, u32 isr, u32 *ier);
-
-static irqreturn_t timbuart_handleinterrupt(int irq, void *devid);
-
-static void timbuart_stop_rx(struct uart_port *port)
-{
-       /* spin lock held by upper layer, disable all RX interrupts */
-       u32 ier = ioread32(port->membase + TIMBUART_IER) & ~RXFLAGS;
-       iowrite32(ier, port->membase + TIMBUART_IER);
-}
-
-static void timbuart_stop_tx(struct uart_port *port)
-{
-       /* spinlock held by upper layer, disable TX interrupt */
-       u32 ier = ioread32(port->membase + TIMBUART_IER) & ~TXBAE;
-       iowrite32(ier, port->membase + TIMBUART_IER);
-}
-
-static void timbuart_start_tx(struct uart_port *port)
-{
-       struct timbuart_port *uart =
-               container_of(port, struct timbuart_port, port);
-
-       /* do not transfer anything here -> fire off the tasklet */
-       tasklet_schedule(&uart->tasklet);
-}
-
-static unsigned int timbuart_tx_empty(struct uart_port *port)
-{
-       u32 isr = ioread32(port->membase + TIMBUART_ISR);
-
-       return (isr & TXBE) ? TIOCSER_TEMT : 0;
-}
-
-static void timbuart_flush_buffer(struct uart_port *port)
-{
-       if (!timbuart_tx_empty(port)) {
-               u8 ctl = ioread8(port->membase + TIMBUART_CTRL) |
-                       TIMBUART_CTRL_FLSHTX;
-
-               iowrite8(ctl, port->membase + TIMBUART_CTRL);
-               iowrite32(TXBF, port->membase + TIMBUART_ISR);
-       }
-}
-
-static void timbuart_rx_chars(struct uart_port *port)
-{
-       struct tty_struct *tty = port->state->port.tty;
-
-       while (ioread32(port->membase + TIMBUART_ISR) & RXDP) {
-               u8 ch = ioread8(port->membase + TIMBUART_RXFIFO);
-               port->icount.rx++;
-               tty_insert_flip_char(tty, ch, TTY_NORMAL);
-       }
-
-       spin_unlock(&port->lock);
-       tty_flip_buffer_push(port->state->port.tty);
-       spin_lock(&port->lock);
-
-       dev_dbg(port->dev, "%s - total read %d bytes\n",
-               __func__, port->icount.rx);
-}
-
-static void timbuart_tx_chars(struct uart_port *port)
-{
-       struct circ_buf *xmit = &port->state->xmit;
-
-       while (!(ioread32(port->membase + TIMBUART_ISR) & TXBF) &&
-               !uart_circ_empty(xmit)) {
-               iowrite8(xmit->buf[xmit->tail],
-                       port->membase + TIMBUART_TXFIFO);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-       }
-
-       dev_dbg(port->dev,
-               "%s - total written %d bytes, CTL: %x, RTS: %x, baud: %x\n",
-                __func__,
-               port->icount.tx,
-               ioread8(port->membase + TIMBUART_CTRL),
-               port->mctrl & TIOCM_RTS,
-               ioread8(port->membase + TIMBUART_BAUDRATE));
-}
-
-static void timbuart_handle_tx_port(struct uart_port *port, u32 isr, u32 *ier)
-{
-       struct timbuart_port *uart =
-               container_of(port, struct timbuart_port, port);
-       struct circ_buf *xmit = &port->state->xmit;
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port))
-               return;
-
-       if (port->x_char)
-               return;
-
-       if (isr & TXFLAGS) {
-               timbuart_tx_chars(port);
-               /* clear all TX interrupts */
-               iowrite32(TXFLAGS, port->membase + TIMBUART_ISR);
-
-               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-                       uart_write_wakeup(port);
-       } else
-               /* Re-enable any tx interrupt */
-               *ier |= uart->last_ier & TXFLAGS;
-
-       /* enable interrupts if there are chars in the transmit buffer,
-        * Or if we delivered some bytes and want the almost empty interrupt
-        * we wake up the upper layer later when we got the interrupt
-        * to give it some time to go out...
-        */
-       if (!uart_circ_empty(xmit))
-               *ier |= TXBAE;
-
-       dev_dbg(port->dev, "%s - leaving\n", __func__);
-}
-
-void timbuart_handle_rx_port(struct uart_port *port, u32 isr, u32 *ier)
-{
-       if (isr & RXFLAGS) {
-               /* Some RX status is set */
-               if (isr & RXBF) {
-                       u8 ctl = ioread8(port->membase + TIMBUART_CTRL) |
-                               TIMBUART_CTRL_FLSHRX;
-                       iowrite8(ctl, port->membase + TIMBUART_CTRL);
-                       port->icount.overrun++;
-               } else if (isr & (RXDP))
-                       timbuart_rx_chars(port);
-
-               /* ack all RX interrupts */
-               iowrite32(RXFLAGS, port->membase + TIMBUART_ISR);
-       }
-
-       /* always have the RX interrupts enabled */
-       *ier |= RXBAF | RXBF | RXTT;
-
-       dev_dbg(port->dev, "%s - leaving\n", __func__);
-}
-
-void timbuart_tasklet(unsigned long arg)
-{
-       struct timbuart_port *uart = (struct timbuart_port *)arg;
-       u32 isr, ier = 0;
-
-       spin_lock(&uart->port.lock);
-
-       isr = ioread32(uart->port.membase + TIMBUART_ISR);
-       dev_dbg(uart->port.dev, "%s ISR: %x\n", __func__, isr);
-
-       if (!uart->usedma)
-               timbuart_handle_tx_port(&uart->port, isr, &ier);
-
-       timbuart_mctrl_check(&uart->port, isr, &ier);
-
-       if (!uart->usedma)
-               timbuart_handle_rx_port(&uart->port, isr, &ier);
-
-       iowrite32(ier, uart->port.membase + TIMBUART_IER);
-
-       spin_unlock(&uart->port.lock);
-       dev_dbg(uart->port.dev, "%s leaving\n", __func__);
-}
-
-static unsigned int timbuart_get_mctrl(struct uart_port *port)
-{
-       u8 cts = ioread8(port->membase + TIMBUART_CTRL);
-       dev_dbg(port->dev, "%s - cts %x\n", __func__, cts);
-
-       if (cts & TIMBUART_CTRL_CTS)
-               return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
-       else
-               return TIOCM_DSR | TIOCM_CAR;
-}
-
-static void timbuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       dev_dbg(port->dev, "%s - %x\n", __func__, mctrl);
-
-       if (mctrl & TIOCM_RTS)
-               iowrite8(TIMBUART_CTRL_RTS, port->membase + TIMBUART_CTRL);
-       else
-               iowrite8(0, port->membase + TIMBUART_CTRL);
-}
-
-static void timbuart_mctrl_check(struct uart_port *port, u32 isr, u32 *ier)
-{
-       unsigned int cts;
-
-       if (isr & CTS_DELTA) {
-               /* ack */
-               iowrite32(CTS_DELTA, port->membase + TIMBUART_ISR);
-               cts = timbuart_get_mctrl(port);
-               uart_handle_cts_change(port, cts & TIOCM_CTS);
-               wake_up_interruptible(&port->state->port.delta_msr_wait);
-       }
-
-       *ier |= CTS_DELTA;
-}
-
-static void timbuart_enable_ms(struct uart_port *port)
-{
-       /* N/A */
-}
-
-static void timbuart_break_ctl(struct uart_port *port, int ctl)
-{
-       /* N/A */
-}
-
-static int timbuart_startup(struct uart_port *port)
-{
-       struct timbuart_port *uart =
-               container_of(port, struct timbuart_port, port);
-
-       dev_dbg(port->dev, "%s\n", __func__);
-
-       iowrite8(TIMBUART_CTRL_FLSHRX, port->membase + TIMBUART_CTRL);
-       iowrite32(0x1ff, port->membase + TIMBUART_ISR);
-       /* Enable all but TX interrupts */
-       iowrite32(RXBAF | RXBF | RXTT | CTS_DELTA,
-               port->membase + TIMBUART_IER);
-
-       return request_irq(port->irq, timbuart_handleinterrupt, IRQF_SHARED,
-               "timb-uart", uart);
-}
-
-static void timbuart_shutdown(struct uart_port *port)
-{
-       struct timbuart_port *uart =
-               container_of(port, struct timbuart_port, port);
-       dev_dbg(port->dev, "%s\n", __func__);
-       free_irq(port->irq, uart);
-       iowrite32(0, port->membase + TIMBUART_IER);
-}
-
-static int get_bindex(int baud)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(baudrates); i++)
-               if (baud <= baudrates[i])
-                       return i;
-
-       return -1;
-}
-
-static void timbuart_set_termios(struct uart_port *port,
-       struct ktermios *termios,
-       struct ktermios *old)
-{
-       unsigned int baud;
-       short bindex;
-       unsigned long flags;
-
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
-       bindex = get_bindex(baud);
-       dev_dbg(port->dev, "%s - bindex %d\n", __func__, bindex);
-
-       if (bindex < 0)
-               bindex = 0;
-       baud = baudrates[bindex];
-
-       /* The serial layer calls into this once with old = NULL when setting
-          up initially */
-       if (old)
-               tty_termios_copy_hw(termios, old);
-       tty_termios_encode_baud_rate(termios, baud, baud);
-
-       spin_lock_irqsave(&port->lock, flags);
-       iowrite8((u8)bindex, port->membase + TIMBUART_BAUDRATE);
-       uart_update_timeout(port, termios->c_cflag, baud);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *timbuart_type(struct uart_port *port)
-{
-       return port->type == PORT_UNKNOWN ? "timbuart" : NULL;
-}
-
-/* We do not request/release mappings of the registers here,
- * currently it's done in the proble function.
- */
-static void timbuart_release_port(struct uart_port *port)
-{
-       struct platform_device *pdev = to_platform_device(port->dev);
-       int size =
-               resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0));
-
-       if (port->flags & UPF_IOREMAP) {
-               iounmap(port->membase);
-               port->membase = NULL;
-       }
-
-       release_mem_region(port->mapbase, size);
-}
-
-static int timbuart_request_port(struct uart_port *port)
-{
-       struct platform_device *pdev = to_platform_device(port->dev);
-       int size =
-               resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0));
-
-       if (!request_mem_region(port->mapbase, size, "timb-uart"))
-               return -EBUSY;
-
-       if (port->flags & UPF_IOREMAP) {
-               port->membase = ioremap(port->mapbase, size);
-               if (port->membase == NULL) {
-                       release_mem_region(port->mapbase, size);
-                       return -ENOMEM;
-               }
-       }
-
-       return 0;
-}
-
-static irqreturn_t timbuart_handleinterrupt(int irq, void *devid)
-{
-       struct timbuart_port *uart = (struct timbuart_port *)devid;
-
-       if (ioread8(uart->port.membase + TIMBUART_IPR)) {
-               uart->last_ier = ioread32(uart->port.membase + TIMBUART_IER);
-
-               /* disable interrupts, the tasklet enables them again */
-               iowrite32(0, uart->port.membase + TIMBUART_IER);
-
-               /* fire off bottom half */
-               tasklet_schedule(&uart->tasklet);
-
-               return IRQ_HANDLED;
-       } else
-               return IRQ_NONE;
-}
-
-/*
- * Configure/autoconfigure the port.
- */
-static void timbuart_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE) {
-               port->type = PORT_TIMBUART;
-               timbuart_request_port(port);
-       }
-}
-
-static int timbuart_verify_port(struct uart_port *port,
-       struct serial_struct *ser)
-{
-       /* we don't want the core code to modify any port params */
-       return -EINVAL;
-}
-
-static struct uart_ops timbuart_ops = {
-       .tx_empty = timbuart_tx_empty,
-       .set_mctrl = timbuart_set_mctrl,
-       .get_mctrl = timbuart_get_mctrl,
-       .stop_tx = timbuart_stop_tx,
-       .start_tx = timbuart_start_tx,
-       .flush_buffer = timbuart_flush_buffer,
-       .stop_rx = timbuart_stop_rx,
-       .enable_ms = timbuart_enable_ms,
-       .break_ctl = timbuart_break_ctl,
-       .startup = timbuart_startup,
-       .shutdown = timbuart_shutdown,
-       .set_termios = timbuart_set_termios,
-       .type = timbuart_type,
-       .release_port = timbuart_release_port,
-       .request_port = timbuart_request_port,
-       .config_port = timbuart_config_port,
-       .verify_port = timbuart_verify_port
-};
-
-static struct uart_driver timbuart_driver = {
-       .owner = THIS_MODULE,
-       .driver_name = "timberdale_uart",
-       .dev_name = "ttyTU",
-       .major = TIMBUART_MAJOR,
-       .minor = TIMBUART_MINOR,
-       .nr = 1
-};
-
-static int __devinit timbuart_probe(struct platform_device *dev)
-{
-       int err, irq;
-       struct timbuart_port *uart;
-       struct resource *iomem;
-
-       dev_dbg(&dev->dev, "%s\n", __func__);
-
-       uart = kzalloc(sizeof(*uart), GFP_KERNEL);
-       if (!uart) {
-               err = -EINVAL;
-               goto err_mem;
-       }
-
-       uart->usedma = 0;
-
-       uart->port.uartclk = 3250000 * 16;
-       uart->port.fifosize  = TIMBUART_FIFO_SIZE;
-       uart->port.regshift  = 2;
-       uart->port.iotype  = UPIO_MEM;
-       uart->port.ops = &timbuart_ops;
-       uart->port.irq = 0;
-       uart->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
-       uart->port.line  = 0;
-       uart->port.dev  = &dev->dev;
-
-       iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       if (!iomem) {
-               err = -ENOMEM;
-               goto err_register;
-       }
-       uart->port.mapbase = iomem->start;
-       uart->port.membase = NULL;
-
-       irq = platform_get_irq(dev, 0);
-       if (irq < 0) {
-               err = -EINVAL;
-               goto err_register;
-       }
-       uart->port.irq = irq;
-
-       tasklet_init(&uart->tasklet, timbuart_tasklet, (unsigned long)uart);
-
-       err = uart_register_driver(&timbuart_driver);
-       if (err)
-               goto err_register;
-
-       err = uart_add_one_port(&timbuart_driver, &uart->port);
-       if (err)
-               goto err_add_port;
-
-       platform_set_drvdata(dev, uart);
-
-       return 0;
-
-err_add_port:
-       uart_unregister_driver(&timbuart_driver);
-err_register:
-       kfree(uart);
-err_mem:
-       printk(KERN_ERR "timberdale: Failed to register Timberdale UART: %d\n",
-               err);
-
-       return err;
-}
-
-static int __devexit timbuart_remove(struct platform_device *dev)
-{
-       struct timbuart_port *uart = platform_get_drvdata(dev);
-
-       tasklet_kill(&uart->tasklet);
-       uart_remove_one_port(&timbuart_driver, &uart->port);
-       uart_unregister_driver(&timbuart_driver);
-       kfree(uart);
-
-       return 0;
-}
-
-static struct platform_driver timbuart_platform_driver = {
-       .driver = {
-               .name   = "timb-uart",
-               .owner  = THIS_MODULE,
-       },
-       .probe          = timbuart_probe,
-       .remove         = __devexit_p(timbuart_remove),
-};
-
-/*--------------------------------------------------------------------------*/
-
-static int __init timbuart_init(void)
-{
-       return platform_driver_register(&timbuart_platform_driver);
-}
-
-static void __exit timbuart_exit(void)
-{
-       platform_driver_unregister(&timbuart_platform_driver);
-}
-
-module_init(timbuart_init);
-module_exit(timbuart_exit);
-
-MODULE_DESCRIPTION("Timberdale UART driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:timb-uart");
-
diff --git a/drivers/serial/timbuart.h b/drivers/serial/timbuart.h
deleted file mode 100644 (file)
index 7e56676..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * timbuart.c timberdale FPGA GPIO driver
- * Copyright (c) 2009 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
- */
-
-/* Supports:
- * Timberdale FPGA UART
- */
-
-#ifndef _TIMBUART_H
-#define _TIMBUART_H
-
-#define TIMBUART_FIFO_SIZE     2048
-
-#define TIMBUART_RXFIFO                0x08
-#define TIMBUART_TXFIFO                0x0c
-#define TIMBUART_IER           0x10
-#define TIMBUART_IPR           0x14
-#define TIMBUART_ISR           0x18
-#define TIMBUART_CTRL          0x1c
-#define TIMBUART_BAUDRATE      0x20
-
-#define TIMBUART_CTRL_RTS      0x01
-#define TIMBUART_CTRL_CTS      0x02
-#define TIMBUART_CTRL_FLSHTX   0x40
-#define TIMBUART_CTRL_FLSHRX   0x80
-
-#define TXBF           0x01
-#define TXBAE          0x02
-#define CTS_DELTA      0x04
-#define RXDP           0x08
-#define RXBAF          0x10
-#define RXBF           0x20
-#define RXTT           0x40
-#define RXBNAE         0x80
-#define TXBE           0x100
-
-#define RXFLAGS (RXDP | RXBAF | RXBF | RXTT | RXBNAE)
-#define TXFLAGS (TXBF | TXBAE)
-
-#define TIMBUART_MAJOR 204
-#define TIMBUART_MINOR 192
-
-#endif /* _TIMBUART_H */
-
diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c
deleted file mode 100644 (file)
index d2fce86..0000000
+++ /dev/null
@@ -1,709 +0,0 @@
-/*
- * uartlite.c: Serial driver for Xilinx uartlite serial controller
- *
- * Copyright (C) 2006 Peter Korsgaard <jacmet@sunsite.dk>
- * Copyright (C) 2007 Secret Lab Technologies Ltd.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2.  This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/console.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <linux/tty.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <asm/io.h>
-#if defined(CONFIG_OF) && (defined(CONFIG_PPC32) || defined(CONFIG_MICROBLAZE))
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
-
-/* Match table for of_platform binding */
-static struct of_device_id ulite_of_match[] __devinitdata = {
-       { .compatible = "xlnx,opb-uartlite-1.00.b", },
-       { .compatible = "xlnx,xps-uartlite-1.00.a", },
-       {}
-};
-MODULE_DEVICE_TABLE(of, ulite_of_match);
-
-#endif
-
-#define ULITE_NAME             "ttyUL"
-#define ULITE_MAJOR            204
-#define ULITE_MINOR            187
-#define ULITE_NR_UARTS         4
-
-/* ---------------------------------------------------------------------
- * Register definitions
- *
- * For register details see datasheet:
- * http://www.xilinx.com/support/documentation/ip_documentation/opb_uartlite.pdf 
- */
-
-#define ULITE_RX               0x00
-#define ULITE_TX               0x04
-#define ULITE_STATUS           0x08
-#define ULITE_CONTROL          0x0c
-
-#define ULITE_REGION           16
-
-#define ULITE_STATUS_RXVALID   0x01
-#define ULITE_STATUS_RXFULL    0x02
-#define ULITE_STATUS_TXEMPTY   0x04
-#define ULITE_STATUS_TXFULL    0x08
-#define ULITE_STATUS_IE                0x10
-#define ULITE_STATUS_OVERRUN   0x20
-#define ULITE_STATUS_FRAME     0x40
-#define ULITE_STATUS_PARITY    0x80
-
-#define ULITE_CONTROL_RST_TX   0x01
-#define ULITE_CONTROL_RST_RX   0x02
-#define ULITE_CONTROL_IE       0x10
-
-
-static struct uart_port ulite_ports[ULITE_NR_UARTS];
-
-/* ---------------------------------------------------------------------
- * Core UART driver operations
- */
-
-static int ulite_receive(struct uart_port *port, int stat)
-{
-       struct tty_struct *tty = port->state->port.tty;
-       unsigned char ch = 0;
-       char flag = TTY_NORMAL;
-
-       if ((stat & (ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN
-                    | ULITE_STATUS_FRAME)) == 0)
-               return 0;
-
-       /* stats */
-       if (stat & ULITE_STATUS_RXVALID) {
-               port->icount.rx++;
-               ch = ioread32be(port->membase + ULITE_RX);
-
-               if (stat & ULITE_STATUS_PARITY)
-                       port->icount.parity++;
-       }
-
-       if (stat & ULITE_STATUS_OVERRUN)
-               port->icount.overrun++;
-
-       if (stat & ULITE_STATUS_FRAME)
-               port->icount.frame++;
-
-
-       /* drop byte with parity error if IGNPAR specificed */
-       if (stat & port->ignore_status_mask & ULITE_STATUS_PARITY)
-               stat &= ~ULITE_STATUS_RXVALID;
-
-       stat &= port->read_status_mask;
-
-       if (stat & ULITE_STATUS_PARITY)
-               flag = TTY_PARITY;
-
-
-       stat &= ~port->ignore_status_mask;
-
-       if (stat & ULITE_STATUS_RXVALID)
-               tty_insert_flip_char(tty, ch, flag);
-
-       if (stat & ULITE_STATUS_FRAME)
-               tty_insert_flip_char(tty, 0, TTY_FRAME);
-
-       if (stat & ULITE_STATUS_OVERRUN)
-               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-
-       return 1;
-}
-
-static int ulite_transmit(struct uart_port *port, int stat)
-{
-       struct circ_buf *xmit  = &port->state->xmit;
-
-       if (stat & ULITE_STATUS_TXFULL)
-               return 0;
-
-       if (port->x_char) {
-               iowrite32be(port->x_char, port->membase + ULITE_TX);
-               port->x_char = 0;
-               port->icount.tx++;
-               return 1;
-       }
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port))
-               return 0;
-
-       iowrite32be(xmit->buf[xmit->tail], port->membase + ULITE_TX);
-       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
-       port->icount.tx++;
-
-       /* wake up */
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       return 1;
-}
-
-static irqreturn_t ulite_isr(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       int busy, n = 0;
-
-       do {
-               int stat = ioread32be(port->membase + ULITE_STATUS);
-               busy  = ulite_receive(port, stat);
-               busy |= ulite_transmit(port, stat);
-               n++;
-       } while (busy);
-
-       /* work done? */
-       if (n > 1) {
-               tty_flip_buffer_push(port->state->port.tty);
-               return IRQ_HANDLED;
-       } else {
-               return IRQ_NONE;
-       }
-}
-
-static unsigned int ulite_tx_empty(struct uart_port *port)
-{
-       unsigned long flags;
-       unsigned int ret;
-
-       spin_lock_irqsave(&port->lock, flags);
-       ret = ioread32be(port->membase + ULITE_STATUS);
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0;
-}
-
-static unsigned int ulite_get_mctrl(struct uart_port *port)
-{
-       return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
-}
-
-static void ulite_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       /* N/A */
-}
-
-static void ulite_stop_tx(struct uart_port *port)
-{
-       /* N/A */
-}
-
-static void ulite_start_tx(struct uart_port *port)
-{
-       ulite_transmit(port, ioread32be(port->membase + ULITE_STATUS));
-}
-
-static void ulite_stop_rx(struct uart_port *port)
-{
-       /* don't forward any more data (like !CREAD) */
-       port->ignore_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY
-               | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
-}
-
-static void ulite_enable_ms(struct uart_port *port)
-{
-       /* N/A */
-}
-
-static void ulite_break_ctl(struct uart_port *port, int ctl)
-{
-       /* N/A */
-}
-
-static int ulite_startup(struct uart_port *port)
-{
-       int ret;
-
-       ret = request_irq(port->irq, ulite_isr,
-                         IRQF_SHARED | IRQF_SAMPLE_RANDOM, "uartlite", port);
-       if (ret)
-               return ret;
-
-       iowrite32be(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX,
-              port->membase + ULITE_CONTROL);
-       iowrite32be(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
-
-       return 0;
-}
-
-static void ulite_shutdown(struct uart_port *port)
-{
-       iowrite32be(0, port->membase + ULITE_CONTROL);
-       ioread32be(port->membase + ULITE_CONTROL); /* dummy */
-       free_irq(port->irq, port);
-}
-
-static void ulite_set_termios(struct uart_port *port, struct ktermios *termios,
-                             struct ktermios *old)
-{
-       unsigned long flags;
-       unsigned int baud;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       port->read_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN
-               | ULITE_STATUS_TXFULL;
-
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |=
-                       ULITE_STATUS_PARITY | ULITE_STATUS_FRAME;
-
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= ULITE_STATUS_PARITY
-                       | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
-
-       /* ignore all characters if CREAD is not set */
-       if ((termios->c_cflag & CREAD) == 0)
-               port->ignore_status_mask |=
-                       ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY
-                       | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
-
-       /* update timeout */
-       baud = uart_get_baud_rate(port, termios, old, 0, 460800);
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *ulite_type(struct uart_port *port)
-{
-       return port->type == PORT_UARTLITE ? "uartlite" : NULL;
-}
-
-static void ulite_release_port(struct uart_port *port)
-{
-       release_mem_region(port->mapbase, ULITE_REGION);
-       iounmap(port->membase);
-       port->membase = NULL;
-}
-
-static int ulite_request_port(struct uart_port *port)
-{
-       pr_debug("ulite console: port=%p; port->mapbase=%llx\n",
-                port, (unsigned long long) port->mapbase);
-
-       if (!request_mem_region(port->mapbase, ULITE_REGION, "uartlite")) {
-               dev_err(port->dev, "Memory region busy\n");
-               return -EBUSY;
-       }
-
-       port->membase = ioremap(port->mapbase, ULITE_REGION);
-       if (!port->membase) {
-               dev_err(port->dev, "Unable to map registers\n");
-               release_mem_region(port->mapbase, ULITE_REGION);
-               return -EBUSY;
-       }
-
-       return 0;
-}
-
-static void ulite_config_port(struct uart_port *port, int flags)
-{
-       if (!ulite_request_port(port))
-               port->type = PORT_UARTLITE;
-}
-
-static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       /* we don't want the core code to modify any port params */
-       return -EINVAL;
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-static int ulite_get_poll_char(struct uart_port *port)
-{
-       if (!(ioread32be(port->membase + ULITE_STATUS)
-                                               & ULITE_STATUS_RXVALID))
-               return NO_POLL_CHAR;
-
-       return ioread32be(port->membase + ULITE_RX);
-}
-
-static void ulite_put_poll_char(struct uart_port *port, unsigned char ch)
-{
-       while (ioread32be(port->membase + ULITE_STATUS) & ULITE_STATUS_TXFULL)
-               cpu_relax();
-
-       /* write char to device */
-       iowrite32be(ch, port->membase + ULITE_TX);
-}
-#endif
-
-static struct uart_ops ulite_ops = {
-       .tx_empty       = ulite_tx_empty,
-       .set_mctrl      = ulite_set_mctrl,
-       .get_mctrl      = ulite_get_mctrl,
-       .stop_tx        = ulite_stop_tx,
-       .start_tx       = ulite_start_tx,
-       .stop_rx        = ulite_stop_rx,
-       .enable_ms      = ulite_enable_ms,
-       .break_ctl      = ulite_break_ctl,
-       .startup        = ulite_startup,
-       .shutdown       = ulite_shutdown,
-       .set_termios    = ulite_set_termios,
-       .type           = ulite_type,
-       .release_port   = ulite_release_port,
-       .request_port   = ulite_request_port,
-       .config_port    = ulite_config_port,
-       .verify_port    = ulite_verify_port,
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_get_char  = ulite_get_poll_char,
-       .poll_put_char  = ulite_put_poll_char,
-#endif
-};
-
-/* ---------------------------------------------------------------------
- * Console driver operations
- */
-
-#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
-static void ulite_console_wait_tx(struct uart_port *port)
-{
-       int i;
-       u8 val;
-
-       /* Spin waiting for TX fifo to have space available */
-       for (i = 0; i < 100000; i++) {
-               val = ioread32be(port->membase + ULITE_STATUS);
-               if ((val & ULITE_STATUS_TXFULL) == 0)
-                       break;
-               cpu_relax();
-       }
-}
-
-static void ulite_console_putchar(struct uart_port *port, int ch)
-{
-       ulite_console_wait_tx(port);
-       iowrite32be(ch, port->membase + ULITE_TX);
-}
-
-static void ulite_console_write(struct console *co, const char *s,
-                               unsigned int count)
-{
-       struct uart_port *port = &ulite_ports[co->index];
-       unsigned long flags;
-       unsigned int ier;
-       int locked = 1;
-
-       if (oops_in_progress) {
-               locked = spin_trylock_irqsave(&port->lock, flags);
-       } else
-               spin_lock_irqsave(&port->lock, flags);
-
-       /* save and disable interrupt */
-       ier = ioread32be(port->membase + ULITE_STATUS) & ULITE_STATUS_IE;
-       iowrite32be(0, port->membase + ULITE_CONTROL);
-
-       uart_console_write(port, s, count, ulite_console_putchar);
-
-       ulite_console_wait_tx(port);
-
-       /* restore interrupt state */
-       if (ier)
-               iowrite32be(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
-
-       if (locked)
-               spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static int __devinit ulite_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       if (co->index < 0 || co->index >= ULITE_NR_UARTS)
-               return -EINVAL;
-
-       port = &ulite_ports[co->index];
-
-       /* Has the device been initialized yet? */
-       if (!port->mapbase) {
-               pr_debug("console on ttyUL%i not present\n", co->index);
-               return -ENODEV;
-       }
-
-       /* not initialized yet? */
-       if (!port->membase) {
-               if (ulite_request_port(port))
-                       return -ENODEV;
-       }
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver ulite_uart_driver;
-
-static struct console ulite_console = {
-       .name   = ULITE_NAME,
-       .write  = ulite_console_write,
-       .device = uart_console_device,
-       .setup  = ulite_console_setup,
-       .flags  = CON_PRINTBUFFER,
-       .index  = -1, /* Specified on the cmdline (e.g. console=ttyUL0 ) */
-       .data   = &ulite_uart_driver,
-};
-
-static int __init ulite_console_init(void)
-{
-       register_console(&ulite_console);
-       return 0;
-}
-
-console_initcall(ulite_console_init);
-
-#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */
-
-static struct uart_driver ulite_uart_driver = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "uartlite",
-       .dev_name       = ULITE_NAME,
-       .major          = ULITE_MAJOR,
-       .minor          = ULITE_MINOR,
-       .nr             = ULITE_NR_UARTS,
-#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
-       .cons           = &ulite_console,
-#endif
-};
-
-/* ---------------------------------------------------------------------
- * Port assignment functions (mapping devices to uart_port structures)
- */
-
-/** ulite_assign: register a uartlite device with the driver
- *
- * @dev: pointer to device structure
- * @id: requested id number.  Pass -1 for automatic port assignment
- * @base: base address of uartlite registers
- * @irq: irq number for uartlite
- *
- * Returns: 0 on success, <0 otherwise
- */
-static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq)
-{
-       struct uart_port *port;
-       int rc;
-
-       /* if id = -1; then scan for a free id and use that */
-       if (id < 0) {
-               for (id = 0; id < ULITE_NR_UARTS; id++)
-                       if (ulite_ports[id].mapbase == 0)
-                               break;
-       }
-       if (id < 0 || id >= ULITE_NR_UARTS) {
-               dev_err(dev, "%s%i too large\n", ULITE_NAME, id);
-               return -EINVAL;
-       }
-
-       if ((ulite_ports[id].mapbase) && (ulite_ports[id].mapbase != base)) {
-               dev_err(dev, "cannot assign to %s%i; it is already in use\n",
-                       ULITE_NAME, id);
-               return -EBUSY;
-       }
-
-       port = &ulite_ports[id];
-
-       spin_lock_init(&port->lock);
-       port->fifosize = 16;
-       port->regshift = 2;
-       port->iotype = UPIO_MEM;
-       port->iobase = 1; /* mark port in use */
-       port->mapbase = base;
-       port->membase = NULL;
-       port->ops = &ulite_ops;
-       port->irq = irq;
-       port->flags = UPF_BOOT_AUTOCONF;
-       port->dev = dev;
-       port->type = PORT_UNKNOWN;
-       port->line = id;
-
-       dev_set_drvdata(dev, port);
-
-       /* Register the port */
-       rc = uart_add_one_port(&ulite_uart_driver, port);
-       if (rc) {
-               dev_err(dev, "uart_add_one_port() failed; err=%i\n", rc);
-               port->mapbase = 0;
-               dev_set_drvdata(dev, NULL);
-               return rc;
-       }
-
-       return 0;
-}
-
-/** ulite_release: register a uartlite device with the driver
- *
- * @dev: pointer to device structure
- */
-static int __devexit ulite_release(struct device *dev)
-{
-       struct uart_port *port = dev_get_drvdata(dev);
-       int rc = 0;
-
-       if (port) {
-               rc = uart_remove_one_port(&ulite_uart_driver, port);
-               dev_set_drvdata(dev, NULL);
-               port->mapbase = 0;
-       }
-
-       return rc;
-}
-
-/* ---------------------------------------------------------------------
- * Platform bus binding
- */
-
-static int __devinit ulite_probe(struct platform_device *pdev)
-{
-       struct resource *res, *res2;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-
-       res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!res2)
-               return -ENODEV;
-
-       return ulite_assign(&pdev->dev, pdev->id, res->start, res2->start);
-}
-
-static int __devexit ulite_remove(struct platform_device *pdev)
-{
-       return ulite_release(&pdev->dev);
-}
-
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:uartlite");
-
-static struct platform_driver ulite_platform_driver = {
-       .probe  = ulite_probe,
-       .remove = __devexit_p(ulite_remove),
-       .driver = {
-                  .owner = THIS_MODULE,
-                  .name  = "uartlite",
-                  },
-};
-
-/* ---------------------------------------------------------------------
- * OF bus bindings
- */
-#if defined(CONFIG_OF) && (defined(CONFIG_PPC32) || defined(CONFIG_MICROBLAZE))
-static int __devinit
-ulite_of_probe(struct platform_device *op, const struct of_device_id *match)
-{
-       struct resource res;
-       const unsigned int *id;
-       int irq, rc;
-
-       dev_dbg(&op->dev, "%s(%p, %p)\n", __func__, op, match);
-
-       rc = of_address_to_resource(op->dev.of_node, 0, &res);
-       if (rc) {
-               dev_err(&op->dev, "invalid address\n");
-               return rc;
-       }
-
-       irq = irq_of_parse_and_map(op->dev.of_node, 0);
-
-       id = of_get_property(op->dev.of_node, "port-number", NULL);
-
-       return ulite_assign(&op->dev, id ? *id : -1, res.start, irq);
-}
-
-static int __devexit ulite_of_remove(struct platform_device *op)
-{
-       return ulite_release(&op->dev);
-}
-
-static struct of_platform_driver ulite_of_driver = {
-       .probe = ulite_of_probe,
-       .remove = __devexit_p(ulite_of_remove),
-       .driver = {
-               .name = "uartlite",
-               .owner = THIS_MODULE,
-               .of_match_table = ulite_of_match,
-       },
-};
-
-/* Registration helpers to keep the number of #ifdefs to a minimum */
-static inline int __init ulite_of_register(void)
-{
-       pr_debug("uartlite: calling of_register_platform_driver()\n");
-       return of_register_platform_driver(&ulite_of_driver);
-}
-
-static inline void __exit ulite_of_unregister(void)
-{
-       of_unregister_platform_driver(&ulite_of_driver);
-}
-#else /* CONFIG_OF && (CONFIG_PPC32 || CONFIG_MICROBLAZE) */
-/* Appropriate config not enabled; do nothing helpers */
-static inline int __init ulite_of_register(void) { return 0; }
-static inline void __exit ulite_of_unregister(void) { }
-#endif /* CONFIG_OF && (CONFIG_PPC32 || CONFIG_MICROBLAZE) */
-
-/* ---------------------------------------------------------------------
- * Module setup/teardown
- */
-
-int __init ulite_init(void)
-{
-       int ret;
-
-       pr_debug("uartlite: calling uart_register_driver()\n");
-       ret = uart_register_driver(&ulite_uart_driver);
-       if (ret)
-               goto err_uart;
-
-       ret = ulite_of_register();
-       if (ret)
-               goto err_of;
-
-       pr_debug("uartlite: calling platform_driver_register()\n");
-       ret = platform_driver_register(&ulite_platform_driver);
-       if (ret)
-               goto err_plat;
-
-       return 0;
-
-err_plat:
-       ulite_of_unregister();
-err_of:
-       uart_unregister_driver(&ulite_uart_driver);
-err_uart:
-       printk(KERN_ERR "registering uartlite driver failed: err=%i", ret);
-       return ret;
-}
-
-void __exit ulite_exit(void)
-{
-       platform_driver_unregister(&ulite_platform_driver);
-       ulite_of_unregister();
-       uart_unregister_driver(&ulite_uart_driver);
-}
-
-module_init(ulite_init);
-module_exit(ulite_exit);
-
-MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
-MODULE_DESCRIPTION("Xilinx uartlite serial driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/ucc_uart.c b/drivers/serial/ucc_uart.c
deleted file mode 100644 (file)
index 3f4848e..0000000
+++ /dev/null
@@ -1,1537 +0,0 @@
-/*
- * Freescale QUICC Engine UART device driver
- *
- * Author: Timur Tabi <timur@freescale.com>
- *
- * Copyright 2007 Freescale Semiconductor, Inc.  This file is licensed under
- * the terms of the GNU General Public License version 2.  This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- *
- * This driver adds support for UART devices via Freescale's QUICC Engine
- * found on some Freescale SOCs.
- *
- * If Soft-UART support is needed but not already present, then this driver
- * will request and upload the "Soft-UART" microcode upon probe.  The
- * filename of the microcode should be fsl_qe_ucode_uart_X_YZ.bin, where "X"
- * is the name of the SOC (e.g. 8323), and YZ is the revision of the SOC,
- * (e.g. "11" for 1.1).
- */
-
-#include <linux/module.h>
-#include <linux/serial.h>
-#include <linux/slab.h>
-#include <linux/serial_core.h>
-#include <linux/io.h>
-#include <linux/of_platform.h>
-#include <linux/dma-mapping.h>
-
-#include <linux/fs_uart_pd.h>
-#include <asm/ucc_slow.h>
-
-#include <linux/firmware.h>
-#include <asm/reg.h>
-
-/*
- * The GUMR flag for Soft UART.  This would normally be defined in qe.h,
- * but Soft-UART is a hack and we want to keep everything related to it in
- * this file.
- */
-#define UCC_SLOW_GUMR_H_SUART          0x00004000      /* Soft-UART */
-
-/*
- * soft_uart is 1 if we need to use Soft-UART mode
- */
-static int soft_uart;
-/*
- * firmware_loaded is 1 if the firmware has been loaded, 0 otherwise.
- */
-static int firmware_loaded;
-
-/* Enable this macro to configure all serial ports in internal loopback
-   mode */
-/* #define LOOPBACK */
-
-/* The major and minor device numbers are defined in
- * http://www.lanana.org/docs/device-list/devices-2.6+.txt.  For the QE
- * UART, we have major number 204 and minor numbers 46 - 49, which are the
- * same as for the CPM2.  This decision was made because no Freescale part
- * has both a CPM and a QE.
- */
-#define SERIAL_QE_MAJOR 204
-#define SERIAL_QE_MINOR 46
-
-/* Since we only have minor numbers 46 - 49, there is a hard limit of 4 ports */
-#define UCC_MAX_UART    4
-
-/* The number of buffer descriptors for receiving characters. */
-#define RX_NUM_FIFO     4
-
-/* The number of buffer descriptors for transmitting characters. */
-#define TX_NUM_FIFO     4
-
-/* The maximum size of the character buffer for a single RX BD. */
-#define RX_BUF_SIZE     32
-
-/* The maximum size of the character buffer for a single TX BD. */
-#define TX_BUF_SIZE     32
-
-/*
- * The number of jiffies to wait after receiving a close command before the
- * device is actually closed.  This allows the last few characters to be
- * sent over the wire.
- */
-#define UCC_WAIT_CLOSING 100
-
-struct ucc_uart_pram {
-       struct ucc_slow_pram common;
-       u8 res1[8];             /* reserved */
-       __be16 maxidl;          /* Maximum idle chars */
-       __be16 idlc;            /* temp idle counter */
-       __be16 brkcr;           /* Break count register */
-       __be16 parec;           /* receive parity error counter */
-       __be16 frmec;           /* receive framing error counter */
-       __be16 nosec;           /* receive noise counter */
-       __be16 brkec;           /* receive break condition counter */
-       __be16 brkln;           /* last received break length */
-       __be16 uaddr[2];        /* UART address character 1 & 2 */
-       __be16 rtemp;           /* Temp storage */
-       __be16 toseq;           /* Transmit out of sequence char */
-       __be16 cchars[8];       /* control characters 1-8 */
-       __be16 rccm;            /* receive control character mask */
-       __be16 rccr;            /* receive control character register */
-       __be16 rlbc;            /* receive last break character */
-       __be16 res2;            /* reserved */
-       __be32 res3;            /* reserved, should be cleared */
-       u8 res4;                /* reserved, should be cleared */
-       u8 res5[3];             /* reserved, should be cleared */
-       __be32 res6;            /* reserved, should be cleared */
-       __be32 res7;            /* reserved, should be cleared */
-       __be32 res8;            /* reserved, should be cleared */
-       __be32 res9;            /* reserved, should be cleared */
-       __be32 res10;           /* reserved, should be cleared */
-       __be32 res11;           /* reserved, should be cleared */
-       __be32 res12;           /* reserved, should be cleared */
-       __be32 res13;           /* reserved, should be cleared */
-/* The rest is for Soft-UART only */
-       __be16 supsmr;          /* 0x90, Shadow UPSMR */
-       __be16 res92;           /* 0x92, reserved, initialize to 0 */
-       __be32 rx_state;        /* 0x94, RX state, initialize to 0 */
-       __be32 rx_cnt;          /* 0x98, RX count, initialize to 0 */
-       u8 rx_length;           /* 0x9C, Char length, set to 1+CL+PEN+1+SL */
-       u8 rx_bitmark;          /* 0x9D, reserved, initialize to 0 */
-       u8 rx_temp_dlst_qe;     /* 0x9E, reserved, initialize to 0 */
-       u8 res14[0xBC - 0x9F];  /* reserved */
-       __be32 dump_ptr;        /* 0xBC, Dump pointer */
-       __be32 rx_frame_rem;    /* 0xC0, reserved, initialize to 0 */
-       u8 rx_frame_rem_size;   /* 0xC4, reserved, initialize to 0 */
-       u8 tx_mode;             /* 0xC5, mode, 0=AHDLC, 1=UART */
-       __be16 tx_state;        /* 0xC6, TX state */
-       u8 res15[0xD0 - 0xC8];  /* reserved */
-       __be32 resD0;           /* 0xD0, reserved, initialize to 0 */
-       u8 resD4;               /* 0xD4, reserved, initialize to 0 */
-       __be16 resD5;           /* 0xD5, reserved, initialize to 0 */
-} __attribute__ ((packed));
-
-/* SUPSMR definitions, for Soft-UART only */
-#define UCC_UART_SUPSMR_SL             0x8000
-#define UCC_UART_SUPSMR_RPM_MASK       0x6000
-#define UCC_UART_SUPSMR_RPM_ODD        0x0000
-#define UCC_UART_SUPSMR_RPM_LOW        0x2000
-#define UCC_UART_SUPSMR_RPM_EVEN       0x4000
-#define UCC_UART_SUPSMR_RPM_HIGH       0x6000
-#define UCC_UART_SUPSMR_PEN            0x1000
-#define UCC_UART_SUPSMR_TPM_MASK       0x0C00
-#define UCC_UART_SUPSMR_TPM_ODD        0x0000
-#define UCC_UART_SUPSMR_TPM_LOW        0x0400
-#define UCC_UART_SUPSMR_TPM_EVEN       0x0800
-#define UCC_UART_SUPSMR_TPM_HIGH       0x0C00
-#define UCC_UART_SUPSMR_FRZ            0x0100
-#define UCC_UART_SUPSMR_UM_MASK        0x00c0
-#define UCC_UART_SUPSMR_UM_NORMAL       0x0000
-#define UCC_UART_SUPSMR_UM_MAN_MULTI    0x0040
-#define UCC_UART_SUPSMR_UM_AUTO_MULTI   0x00c0
-#define UCC_UART_SUPSMR_CL_MASK        0x0030
-#define UCC_UART_SUPSMR_CL_8           0x0030
-#define UCC_UART_SUPSMR_CL_7           0x0020
-#define UCC_UART_SUPSMR_CL_6           0x0010
-#define UCC_UART_SUPSMR_CL_5           0x0000
-
-#define UCC_UART_TX_STATE_AHDLC        0x00
-#define UCC_UART_TX_STATE_UART         0x01
-#define UCC_UART_TX_STATE_X1           0x00
-#define UCC_UART_TX_STATE_X16          0x80
-
-#define UCC_UART_PRAM_ALIGNMENT 0x100
-
-#define UCC_UART_SIZE_OF_BD     UCC_SLOW_SIZE_OF_BD
-#define NUM_CONTROL_CHARS       8
-
-/* Private per-port data structure */
-struct uart_qe_port {
-       struct uart_port port;
-       struct ucc_slow __iomem *uccp;
-       struct ucc_uart_pram __iomem *uccup;
-       struct ucc_slow_info us_info;
-       struct ucc_slow_private *us_private;
-       struct device_node *np;
-       unsigned int ucc_num;   /* First ucc is 0, not 1 */
-
-       u16 rx_nrfifos;
-       u16 rx_fifosize;
-       u16 tx_nrfifos;
-       u16 tx_fifosize;
-       int wait_closing;
-       u32 flags;
-       struct qe_bd *rx_bd_base;
-       struct qe_bd *rx_cur;
-       struct qe_bd *tx_bd_base;
-       struct qe_bd *tx_cur;
-       unsigned char *tx_buf;
-       unsigned char *rx_buf;
-       void *bd_virt;          /* virtual address of the BD buffers */
-       dma_addr_t bd_dma_addr; /* bus address of the BD buffers */
-       unsigned int bd_size;   /* size of BD buffer space */
-};
-
-static struct uart_driver ucc_uart_driver = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "ucc_uart",
-       .dev_name       = "ttyQE",
-       .major          = SERIAL_QE_MAJOR,
-       .minor          = SERIAL_QE_MINOR,
-       .nr             = UCC_MAX_UART,
-};
-
-/*
- * Virtual to physical address translation.
- *
- * Given the virtual address for a character buffer, this function returns
- * the physical (DMA) equivalent.
- */
-static inline dma_addr_t cpu2qe_addr(void *addr, struct uart_qe_port *qe_port)
-{
-       if (likely((addr >= qe_port->bd_virt)) &&
-           (addr < (qe_port->bd_virt + qe_port->bd_size)))
-               return qe_port->bd_dma_addr + (addr - qe_port->bd_virt);
-
-       /* something nasty happened */
-       printk(KERN_ERR "%s: addr=%p\n", __func__, addr);
-       BUG();
-       return 0;
-}
-
-/*
- * Physical to virtual address translation.
- *
- * Given the physical (DMA) address for a character buffer, this function
- * returns the virtual equivalent.
- */
-static inline void *qe2cpu_addr(dma_addr_t addr, struct uart_qe_port *qe_port)
-{
-       /* sanity check */
-       if (likely((addr >= qe_port->bd_dma_addr) &&
-                  (addr < (qe_port->bd_dma_addr + qe_port->bd_size))))
-               return qe_port->bd_virt + (addr - qe_port->bd_dma_addr);
-
-       /* something nasty happened */
-       printk(KERN_ERR "%s: addr=%x\n", __func__, addr);
-       BUG();
-       return NULL;
-}
-
-/*
- * Return 1 if the QE is done transmitting all buffers for this port
- *
- * This function scans each BD in sequence.  If we find a BD that is not
- * ready (READY=1), then we return 0 indicating that the QE is still sending
- * data.  If we reach the last BD (WRAP=1), then we know we've scanned
- * the entire list, and all BDs are done.
- */
-static unsigned int qe_uart_tx_empty(struct uart_port *port)
-{
-       struct uart_qe_port *qe_port =
-               container_of(port, struct uart_qe_port, port);
-       struct qe_bd *bdp = qe_port->tx_bd_base;
-
-       while (1) {
-               if (in_be16(&bdp->status) & BD_SC_READY)
-                       /* This BD is not done, so return "not done" */
-                       return 0;
-
-               if (in_be16(&bdp->status) & BD_SC_WRAP)
-                       /*
-                        * This BD is done and it's the last one, so return
-                        * "done"
-                        */
-                       return 1;
-
-               bdp++;
-       };
-}
-
-/*
- * Set the modem control lines
- *
- * Although the QE can control the modem control lines (e.g. CTS), we
- * don't need that support. This function must exist, however, otherwise
- * the kernel will panic.
- */
-void qe_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-}
-
-/*
- * Get the current modem control line status
- *
- * Although the QE can control the modem control lines (e.g. CTS), this
- * driver currently doesn't support that, so we always return Carrier
- * Detect, Data Set Ready, and Clear To Send.
- */
-static unsigned int qe_uart_get_mctrl(struct uart_port *port)
-{
-       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
-}
-
-/*
- * Disable the transmit interrupt.
- *
- * Although this function is called "stop_tx", it does not actually stop
- * transmission of data.  Instead, it tells the QE to not generate an
- * interrupt when the UCC is finished sending characters.
- */
-static void qe_uart_stop_tx(struct uart_port *port)
-{
-       struct uart_qe_port *qe_port =
-               container_of(port, struct uart_qe_port, port);
-
-       clrbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_TX);
-}
-
-/*
- * Transmit as many characters to the HW as possible.
- *
- * This function will attempt to stuff of all the characters from the
- * kernel's transmit buffer into TX BDs.
- *
- * A return value of non-zero indicates that it successfully stuffed all
- * characters from the kernel buffer.
- *
- * A return value of zero indicates that there are still characters in the
- * kernel's buffer that have not been transmitted, but there are no more BDs
- * available.  This function should be called again after a BD has been made
- * available.
- */
-static int qe_uart_tx_pump(struct uart_qe_port *qe_port)
-{
-       struct qe_bd *bdp;
-       unsigned char *p;
-       unsigned int count;
-       struct uart_port *port = &qe_port->port;
-       struct circ_buf *xmit = &port->state->xmit;
-
-       bdp = qe_port->rx_cur;
-
-       /* Handle xon/xoff */
-       if (port->x_char) {
-               /* Pick next descriptor and fill from buffer */
-               bdp = qe_port->tx_cur;
-
-               p = qe2cpu_addr(bdp->buf, qe_port);
-
-               *p++ = port->x_char;
-               out_be16(&bdp->length, 1);
-               setbits16(&bdp->status, BD_SC_READY);
-               /* Get next BD. */
-               if (in_be16(&bdp->status) & BD_SC_WRAP)
-                       bdp = qe_port->tx_bd_base;
-               else
-                       bdp++;
-               qe_port->tx_cur = bdp;
-
-               port->icount.tx++;
-               port->x_char = 0;
-               return 1;
-       }
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               qe_uart_stop_tx(port);
-               return 0;
-       }
-
-       /* Pick next descriptor and fill from buffer */
-       bdp = qe_port->tx_cur;
-
-       while (!(in_be16(&bdp->status) & BD_SC_READY) &&
-              (xmit->tail != xmit->head)) {
-               count = 0;
-               p = qe2cpu_addr(bdp->buf, qe_port);
-               while (count < qe_port->tx_fifosize) {
-                       *p++ = xmit->buf[xmit->tail];
-                       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-                       port->icount.tx++;
-                       count++;
-                       if (xmit->head == xmit->tail)
-                               break;
-               }
-
-               out_be16(&bdp->length, count);
-               setbits16(&bdp->status, BD_SC_READY);
-
-               /* Get next BD. */
-               if (in_be16(&bdp->status) & BD_SC_WRAP)
-                       bdp = qe_port->tx_bd_base;
-               else
-                       bdp++;
-       }
-       qe_port->tx_cur = bdp;
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (uart_circ_empty(xmit)) {
-               /* The kernel buffer is empty, so turn off TX interrupts.  We
-                  don't need to be told when the QE is finished transmitting
-                  the data. */
-               qe_uart_stop_tx(port);
-               return 0;
-       }
-
-       return 1;
-}
-
-/*
- * Start transmitting data
- *
- * This function will start transmitting any available data, if the port
- * isn't already transmitting data.
- */
-static void qe_uart_start_tx(struct uart_port *port)
-{
-       struct uart_qe_port *qe_port =
-               container_of(port, struct uart_qe_port, port);
-
-       /* If we currently are transmitting, then just return */
-       if (in_be16(&qe_port->uccp->uccm) & UCC_UART_UCCE_TX)
-               return;
-
-       /* Otherwise, pump the port and start transmission */
-       if (qe_uart_tx_pump(qe_port))
-               setbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_TX);
-}
-
-/*
- * Stop transmitting data
- */
-static void qe_uart_stop_rx(struct uart_port *port)
-{
-       struct uart_qe_port *qe_port =
-               container_of(port, struct uart_qe_port, port);
-
-       clrbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_RX);
-}
-
-/*
- * Enable status change interrupts
- *
- * We don't support status change interrupts, but we need to define this
- * function otherwise the kernel will panic.
- */
-static void qe_uart_enable_ms(struct uart_port *port)
-{
-}
-
-/* Start or stop sending  break signal
- *
- * This function controls the sending of a break signal.  If break_state=1,
- * then we start sending a break signal.  If break_state=0, then we stop
- * sending the break signal.
- */
-static void qe_uart_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_qe_port *qe_port =
-               container_of(port, struct uart_qe_port, port);
-
-       if (break_state)
-               ucc_slow_stop_tx(qe_port->us_private);
-       else
-               ucc_slow_restart_tx(qe_port->us_private);
-}
-
-/* ISR helper function for receiving character.
- *
- * This function is called by the ISR to handling receiving characters
- */
-static void qe_uart_int_rx(struct uart_qe_port *qe_port)
-{
-       int i;
-       unsigned char ch, *cp;
-       struct uart_port *port = &qe_port->port;
-       struct tty_struct *tty = port->state->port.tty;
-       struct qe_bd *bdp;
-       u16 status;
-       unsigned int flg;
-
-       /* Just loop through the closed BDs and copy the characters into
-        * the buffer.
-        */
-       bdp = qe_port->rx_cur;
-       while (1) {
-               status = in_be16(&bdp->status);
-
-               /* If this one is empty, then we assume we've read them all */
-               if (status & BD_SC_EMPTY)
-                       break;
-
-               /* get number of characters, and check space in RX buffer */
-               i = in_be16(&bdp->length);
-
-               /* If we don't have enough room in RX buffer for the entire BD,
-                * then we try later, which will be the next RX interrupt.
-                */
-               if (tty_buffer_request_room(tty, i) < i) {
-                       dev_dbg(port->dev, "ucc-uart: no room in RX buffer\n");
-                       return;
-               }
-
-               /* get pointer */
-               cp = qe2cpu_addr(bdp->buf, qe_port);
-
-               /* loop through the buffer */
-               while (i-- > 0) {
-                       ch = *cp++;
-                       port->icount.rx++;
-                       flg = TTY_NORMAL;
-
-                       if (!i && status &
-                           (BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV))
-                               goto handle_error;
-                       if (uart_handle_sysrq_char(port, ch))
-                               continue;
-
-error_return:
-                       tty_insert_flip_char(tty, ch, flg);
-
-               }
-
-               /* This BD is ready to be used again. Clear status. get next */
-               clrsetbits_be16(&bdp->status, BD_SC_BR | BD_SC_FR | BD_SC_PR |
-                       BD_SC_OV | BD_SC_ID, BD_SC_EMPTY);
-               if (in_be16(&bdp->status) & BD_SC_WRAP)
-                       bdp = qe_port->rx_bd_base;
-               else
-                       bdp++;
-
-       }
-
-       /* Write back buffer pointer */
-       qe_port->rx_cur = bdp;
-
-       /* Activate BH processing */
-       tty_flip_buffer_push(tty);
-
-       return;
-
-       /* Error processing */
-
-handle_error:
-       /* Statistics */
-       if (status & BD_SC_BR)
-               port->icount.brk++;
-       if (status & BD_SC_PR)
-               port->icount.parity++;
-       if (status & BD_SC_FR)
-               port->icount.frame++;
-       if (status & BD_SC_OV)
-               port->icount.overrun++;
-
-       /* Mask out ignored conditions */
-       status &= port->read_status_mask;
-
-       /* Handle the remaining ones */
-       if (status & BD_SC_BR)
-               flg = TTY_BREAK;
-       else if (status & BD_SC_PR)
-               flg = TTY_PARITY;
-       else if (status & BD_SC_FR)
-               flg = TTY_FRAME;
-
-       /* Overrun does not affect the current character ! */
-       if (status & BD_SC_OV)
-               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-#ifdef SUPPORT_SYSRQ
-       port->sysrq = 0;
-#endif
-       goto error_return;
-}
-
-/* Interrupt handler
- *
- * This interrupt handler is called after a BD is processed.
- */
-static irqreturn_t qe_uart_int(int irq, void *data)
-{
-       struct uart_qe_port *qe_port = (struct uart_qe_port *) data;
-       struct ucc_slow __iomem *uccp = qe_port->uccp;
-       u16 events;
-
-       /* Clear the interrupts */
-       events = in_be16(&uccp->ucce);
-       out_be16(&uccp->ucce, events);
-
-       if (events & UCC_UART_UCCE_BRKE)
-               uart_handle_break(&qe_port->port);
-
-       if (events & UCC_UART_UCCE_RX)
-               qe_uart_int_rx(qe_port);
-
-       if (events & UCC_UART_UCCE_TX)
-               qe_uart_tx_pump(qe_port);
-
-       return events ? IRQ_HANDLED : IRQ_NONE;
-}
-
-/* Initialize buffer descriptors
- *
- * This function initializes all of the RX and TX buffer descriptors.
- */
-static void qe_uart_initbd(struct uart_qe_port *qe_port)
-{
-       int i;
-       void *bd_virt;
-       struct qe_bd *bdp;
-
-       /* Set the physical address of the host memory buffers in the buffer
-        * descriptors, and the virtual address for us to work with.
-        */
-       bd_virt = qe_port->bd_virt;
-       bdp = qe_port->rx_bd_base;
-       qe_port->rx_cur = qe_port->rx_bd_base;
-       for (i = 0; i < (qe_port->rx_nrfifos - 1); i++) {
-               out_be16(&bdp->status, BD_SC_EMPTY | BD_SC_INTRPT);
-               out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port));
-               out_be16(&bdp->length, 0);
-               bd_virt += qe_port->rx_fifosize;
-               bdp++;
-       }
-
-       /* */
-       out_be16(&bdp->status, BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT);
-       out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port));
-       out_be16(&bdp->length, 0);
-
-       /* Set the physical address of the host memory
-        * buffers in the buffer descriptors, and the
-        * virtual address for us to work with.
-        */
-       bd_virt = qe_port->bd_virt +
-               L1_CACHE_ALIGN(qe_port->rx_nrfifos * qe_port->rx_fifosize);
-       qe_port->tx_cur = qe_port->tx_bd_base;
-       bdp = qe_port->tx_bd_base;
-       for (i = 0; i < (qe_port->tx_nrfifos - 1); i++) {
-               out_be16(&bdp->status, BD_SC_INTRPT);
-               out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port));
-               out_be16(&bdp->length, 0);
-               bd_virt += qe_port->tx_fifosize;
-               bdp++;
-       }
-
-       /* Loopback requires the preamble bit to be set on the first TX BD */
-#ifdef LOOPBACK
-       setbits16(&qe_port->tx_cur->status, BD_SC_P);
-#endif
-
-       out_be16(&bdp->status, BD_SC_WRAP | BD_SC_INTRPT);
-       out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port));
-       out_be16(&bdp->length, 0);
-}
-
-/*
- * Initialize a UCC for UART.
- *
- * This function configures a given UCC to be used as a UART device. Basic
- * UCC initialization is handled in qe_uart_request_port().  This function
- * does all the UART-specific stuff.
- */
-static void qe_uart_init_ucc(struct uart_qe_port *qe_port)
-{
-       u32 cecr_subblock;
-       struct ucc_slow __iomem *uccp = qe_port->uccp;
-       struct ucc_uart_pram *uccup = qe_port->uccup;
-
-       unsigned int i;
-
-       /* First, disable TX and RX in the UCC */
-       ucc_slow_disable(qe_port->us_private, COMM_DIR_RX_AND_TX);
-
-       /* Program the UCC UART parameter RAM */
-       out_8(&uccup->common.rbmr, UCC_BMR_GBL | UCC_BMR_BO_BE);
-       out_8(&uccup->common.tbmr, UCC_BMR_GBL | UCC_BMR_BO_BE);
-       out_be16(&uccup->common.mrblr, qe_port->rx_fifosize);
-       out_be16(&uccup->maxidl, 0x10);
-       out_be16(&uccup->brkcr, 1);
-       out_be16(&uccup->parec, 0);
-       out_be16(&uccup->frmec, 0);
-       out_be16(&uccup->nosec, 0);
-       out_be16(&uccup->brkec, 0);
-       out_be16(&uccup->uaddr[0], 0);
-       out_be16(&uccup->uaddr[1], 0);
-       out_be16(&uccup->toseq, 0);
-       for (i = 0; i < 8; i++)
-               out_be16(&uccup->cchars[i], 0xC000);
-       out_be16(&uccup->rccm, 0xc0ff);
-
-       /* Configure the GUMR registers for UART */
-       if (soft_uart) {
-               /* Soft-UART requires a 1X multiplier for TX */
-               clrsetbits_be32(&uccp->gumr_l,
-                       UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK |
-                       UCC_SLOW_GUMR_L_RDCR_MASK,
-                       UCC_SLOW_GUMR_L_MODE_UART | UCC_SLOW_GUMR_L_TDCR_1 |
-                       UCC_SLOW_GUMR_L_RDCR_16);
-
-               clrsetbits_be32(&uccp->gumr_h, UCC_SLOW_GUMR_H_RFW,
-                       UCC_SLOW_GUMR_H_TRX | UCC_SLOW_GUMR_H_TTX);
-       } else {
-               clrsetbits_be32(&uccp->gumr_l,
-                       UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK |
-                       UCC_SLOW_GUMR_L_RDCR_MASK,
-                       UCC_SLOW_GUMR_L_MODE_UART | UCC_SLOW_GUMR_L_TDCR_16 |
-                       UCC_SLOW_GUMR_L_RDCR_16);
-
-               clrsetbits_be32(&uccp->gumr_h,
-                       UCC_SLOW_GUMR_H_TRX | UCC_SLOW_GUMR_H_TTX,
-                       UCC_SLOW_GUMR_H_RFW);
-       }
-
-#ifdef LOOPBACK
-       clrsetbits_be32(&uccp->gumr_l, UCC_SLOW_GUMR_L_DIAG_MASK,
-               UCC_SLOW_GUMR_L_DIAG_LOOP);
-       clrsetbits_be32(&uccp->gumr_h,
-               UCC_SLOW_GUMR_H_CTSP | UCC_SLOW_GUMR_H_RSYN,
-               UCC_SLOW_GUMR_H_CDS);
-#endif
-
-       /* Disable rx interrupts  and clear all pending events.  */
-       out_be16(&uccp->uccm, 0);
-       out_be16(&uccp->ucce, 0xffff);
-       out_be16(&uccp->udsr, 0x7e7e);
-
-       /* Initialize UPSMR */
-       out_be16(&uccp->upsmr, 0);
-
-       if (soft_uart) {
-               out_be16(&uccup->supsmr, 0x30);
-               out_be16(&uccup->res92, 0);
-               out_be32(&uccup->rx_state, 0);
-               out_be32(&uccup->rx_cnt, 0);
-               out_8(&uccup->rx_bitmark, 0);
-               out_8(&uccup->rx_length, 10);
-               out_be32(&uccup->dump_ptr, 0x4000);
-               out_8(&uccup->rx_temp_dlst_qe, 0);
-               out_be32(&uccup->rx_frame_rem, 0);
-               out_8(&uccup->rx_frame_rem_size, 0);
-               /* Soft-UART requires TX to be 1X */
-               out_8(&uccup->tx_mode,
-                       UCC_UART_TX_STATE_UART | UCC_UART_TX_STATE_X1);
-               out_be16(&uccup->tx_state, 0);
-               out_8(&uccup->resD4, 0);
-               out_be16(&uccup->resD5, 0);
-
-               /* Set UART mode.
-                * Enable receive and transmit.
-                */
-
-               /* From the microcode errata:
-                * 1.GUMR_L register, set mode=0010 (QMC).
-                * 2.Set GUMR_H[17] bit. (UART/AHDLC mode).
-                * 3.Set GUMR_H[19:20] (Transparent mode)
-                * 4.Clear GUMR_H[26] (RFW)
-                * ...
-                * 6.Receiver must use 16x over sampling
-                */
-               clrsetbits_be32(&uccp->gumr_l,
-                       UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK |
-                       UCC_SLOW_GUMR_L_RDCR_MASK,
-                       UCC_SLOW_GUMR_L_MODE_QMC | UCC_SLOW_GUMR_L_TDCR_16 |
-                       UCC_SLOW_GUMR_L_RDCR_16);
-
-               clrsetbits_be32(&uccp->gumr_h,
-                       UCC_SLOW_GUMR_H_RFW | UCC_SLOW_GUMR_H_RSYN,
-                       UCC_SLOW_GUMR_H_SUART | UCC_SLOW_GUMR_H_TRX |
-                       UCC_SLOW_GUMR_H_TTX | UCC_SLOW_GUMR_H_TFL);
-
-#ifdef LOOPBACK
-               clrsetbits_be32(&uccp->gumr_l, UCC_SLOW_GUMR_L_DIAG_MASK,
-                               UCC_SLOW_GUMR_L_DIAG_LOOP);
-               clrbits32(&uccp->gumr_h, UCC_SLOW_GUMR_H_CTSP |
-                         UCC_SLOW_GUMR_H_CDS);
-#endif
-
-               cecr_subblock = ucc_slow_get_qe_cr_subblock(qe_port->ucc_num);
-               qe_issue_cmd(QE_INIT_TX_RX, cecr_subblock,
-                       QE_CR_PROTOCOL_UNSPECIFIED, 0);
-       } else {
-               cecr_subblock = ucc_slow_get_qe_cr_subblock(qe_port->ucc_num);
-               qe_issue_cmd(QE_INIT_TX_RX, cecr_subblock,
-                       QE_CR_PROTOCOL_UART, 0);
-       }
-}
-
-/*
- * Initialize the port.
- */
-static int qe_uart_startup(struct uart_port *port)
-{
-       struct uart_qe_port *qe_port =
-               container_of(port, struct uart_qe_port, port);
-       int ret;
-
-       /*
-        * If we're using Soft-UART mode, then we need to make sure the
-        * firmware has been uploaded first.
-        */
-       if (soft_uart && !firmware_loaded) {
-               dev_err(port->dev, "Soft-UART firmware not uploaded\n");
-               return -ENODEV;
-       }
-
-       qe_uart_initbd(qe_port);
-       qe_uart_init_ucc(qe_port);
-
-       /* Install interrupt handler. */
-       ret = request_irq(port->irq, qe_uart_int, IRQF_SHARED, "ucc-uart",
-               qe_port);
-       if (ret) {
-               dev_err(port->dev, "could not claim IRQ %u\n", port->irq);
-               return ret;
-       }
-
-       /* Startup rx-int */
-       setbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_RX);
-       ucc_slow_enable(qe_port->us_private, COMM_DIR_RX_AND_TX);
-
-       return 0;
-}
-
-/*
- * Shutdown the port.
- */
-static void qe_uart_shutdown(struct uart_port *port)
-{
-       struct uart_qe_port *qe_port =
-               container_of(port, struct uart_qe_port, port);
-       struct ucc_slow __iomem *uccp = qe_port->uccp;
-       unsigned int timeout = 20;
-
-       /* Disable RX and TX */
-
-       /* Wait for all the BDs marked sent */
-       while (!qe_uart_tx_empty(port)) {
-               if (!--timeout) {
-                       dev_warn(port->dev, "shutdown timeout\n");
-                       break;
-               }
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(2);
-       }
-
-       if (qe_port->wait_closing) {
-               /* Wait a bit longer */
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(qe_port->wait_closing);
-       }
-
-       /* Stop uarts */
-       ucc_slow_disable(qe_port->us_private, COMM_DIR_RX_AND_TX);
-       clrbits16(&uccp->uccm, UCC_UART_UCCE_TX | UCC_UART_UCCE_RX);
-
-       /* Shut them really down and reinit buffer descriptors */
-       ucc_slow_graceful_stop_tx(qe_port->us_private);
-       qe_uart_initbd(qe_port);
-
-       free_irq(port->irq, qe_port);
-}
-
-/*
- * Set the serial port parameters.
- */
-static void qe_uart_set_termios(struct uart_port *port,
-                               struct ktermios *termios, struct ktermios *old)
-{
-       struct uart_qe_port *qe_port =
-               container_of(port, struct uart_qe_port, port);
-       struct ucc_slow __iomem *uccp = qe_port->uccp;
-       unsigned int baud;
-       unsigned long flags;
-       u16 upsmr = in_be16(&uccp->upsmr);
-       struct ucc_uart_pram __iomem *uccup = qe_port->uccup;
-       u16 supsmr = in_be16(&uccup->supsmr);
-       u8 char_length = 2; /* 1 + CL + PEN + 1 + SL */
-
-       /* Character length programmed into the mode register is the
-        * sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
-        * 1 or 2 stop bits, minus 1.
-        * The value 'bits' counts this for us.
-        */
-
-       /* byte size */
-       upsmr &= UCC_UART_UPSMR_CL_MASK;
-       supsmr &= UCC_UART_SUPSMR_CL_MASK;
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               upsmr |= UCC_UART_UPSMR_CL_5;
-               supsmr |= UCC_UART_SUPSMR_CL_5;
-               char_length += 5;
-               break;
-       case CS6:
-               upsmr |= UCC_UART_UPSMR_CL_6;
-               supsmr |= UCC_UART_SUPSMR_CL_6;
-               char_length += 6;
-               break;
-       case CS7:
-               upsmr |= UCC_UART_UPSMR_CL_7;
-               supsmr |= UCC_UART_SUPSMR_CL_7;
-               char_length += 7;
-               break;
-       default:        /* case CS8 */
-               upsmr |= UCC_UART_UPSMR_CL_8;
-               supsmr |= UCC_UART_SUPSMR_CL_8;
-               char_length += 8;
-               break;
-       }
-
-       /* If CSTOPB is set, we want two stop bits */
-       if (termios->c_cflag & CSTOPB) {
-               upsmr |= UCC_UART_UPSMR_SL;
-               supsmr |= UCC_UART_SUPSMR_SL;
-               char_length++;  /* + SL */
-       }
-
-       if (termios->c_cflag & PARENB) {
-               upsmr |= UCC_UART_UPSMR_PEN;
-               supsmr |= UCC_UART_SUPSMR_PEN;
-               char_length++;  /* + PEN */
-
-               if (!(termios->c_cflag & PARODD)) {
-                       upsmr &= ~(UCC_UART_UPSMR_RPM_MASK |
-                                  UCC_UART_UPSMR_TPM_MASK);
-                       upsmr |= UCC_UART_UPSMR_RPM_EVEN |
-                               UCC_UART_UPSMR_TPM_EVEN;
-                       supsmr &= ~(UCC_UART_SUPSMR_RPM_MASK |
-                                   UCC_UART_SUPSMR_TPM_MASK);
-                       supsmr |= UCC_UART_SUPSMR_RPM_EVEN |
-                               UCC_UART_SUPSMR_TPM_EVEN;
-               }
-       }
-
-       /*
-        * Set up parity check flag
-        */
-       port->read_status_mask = BD_SC_EMPTY | BD_SC_OV;
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= BD_SC_FR | BD_SC_PR;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               port->read_status_mask |= BD_SC_BR;
-
-       /*
-        * Characters to ignore
-        */
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= BD_SC_PR | BD_SC_FR;
-       if (termios->c_iflag & IGNBRK) {
-               port->ignore_status_mask |= BD_SC_BR;
-               /*
-                * If we're ignore parity and break indicators, ignore
-                * overruns too.  (For real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       port->ignore_status_mask |= BD_SC_OV;
-       }
-       /*
-        * !!! ignore all characters if CREAD is not set
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               port->read_status_mask &= ~BD_SC_EMPTY;
-
-       baud = uart_get_baud_rate(port, termios, old, 0, 115200);
-
-       /* Do we really need a spinlock here? */
-       spin_lock_irqsave(&port->lock, flags);
-
-       out_be16(&uccp->upsmr, upsmr);
-       if (soft_uart) {
-               out_be16(&uccup->supsmr, supsmr);
-               out_8(&uccup->rx_length, char_length);
-
-               /* Soft-UART requires a 1X multiplier for TX */
-               qe_setbrg(qe_port->us_info.rx_clock, baud, 16);
-               qe_setbrg(qe_port->us_info.tx_clock, baud, 1);
-       } else {
-               qe_setbrg(qe_port->us_info.rx_clock, baud, 16);
-               qe_setbrg(qe_port->us_info.tx_clock, baud, 16);
-       }
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/*
- * Return a pointer to a string that describes what kind of port this is.
- */
-static const char *qe_uart_type(struct uart_port *port)
-{
-       return "QE";
-}
-
-/*
- * Allocate any memory and I/O resources required by the port.
- */
-static int qe_uart_request_port(struct uart_port *port)
-{
-       int ret;
-       struct uart_qe_port *qe_port =
-               container_of(port, struct uart_qe_port, port);
-       struct ucc_slow_info *us_info = &qe_port->us_info;
-       struct ucc_slow_private *uccs;
-       unsigned int rx_size, tx_size;
-       void *bd_virt;
-       dma_addr_t bd_dma_addr = 0;
-
-       ret = ucc_slow_init(us_info, &uccs);
-       if (ret) {
-               dev_err(port->dev, "could not initialize UCC%u\n",
-                      qe_port->ucc_num);
-               return ret;
-       }
-
-       qe_port->us_private = uccs;
-       qe_port->uccp = uccs->us_regs;
-       qe_port->uccup = (struct ucc_uart_pram *) uccs->us_pram;
-       qe_port->rx_bd_base = uccs->rx_bd;
-       qe_port->tx_bd_base = uccs->tx_bd;
-
-       /*
-        * Allocate the transmit and receive data buffers.
-        */
-
-       rx_size = L1_CACHE_ALIGN(qe_port->rx_nrfifos * qe_port->rx_fifosize);
-       tx_size = L1_CACHE_ALIGN(qe_port->tx_nrfifos * qe_port->tx_fifosize);
-
-       bd_virt = dma_alloc_coherent(port->dev, rx_size + tx_size, &bd_dma_addr,
-               GFP_KERNEL);
-       if (!bd_virt) {
-               dev_err(port->dev, "could not allocate buffer descriptors\n");
-               return -ENOMEM;
-       }
-
-       qe_port->bd_virt = bd_virt;
-       qe_port->bd_dma_addr = bd_dma_addr;
-       qe_port->bd_size = rx_size + tx_size;
-
-       qe_port->rx_buf = bd_virt;
-       qe_port->tx_buf = qe_port->rx_buf + rx_size;
-
-       return 0;
-}
-
-/*
- * Configure the port.
- *
- * We say we're a CPM-type port because that's mostly true.  Once the device
- * is configured, this driver operates almost identically to the CPM serial
- * driver.
- */
-static void qe_uart_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE) {
-               port->type = PORT_CPM;
-               qe_uart_request_port(port);
-       }
-}
-
-/*
- * Release any memory and I/O resources that were allocated in
- * qe_uart_request_port().
- */
-static void qe_uart_release_port(struct uart_port *port)
-{
-       struct uart_qe_port *qe_port =
-               container_of(port, struct uart_qe_port, port);
-       struct ucc_slow_private *uccs = qe_port->us_private;
-
-       dma_free_coherent(port->dev, qe_port->bd_size, qe_port->bd_virt,
-                         qe_port->bd_dma_addr);
-
-       ucc_slow_free(uccs);
-}
-
-/*
- * Verify that the data in serial_struct is suitable for this device.
- */
-static int qe_uart_verify_port(struct uart_port *port,
-                              struct serial_struct *ser)
-{
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_CPM)
-               return -EINVAL;
-
-       if (ser->irq < 0 || ser->irq >= nr_irqs)
-               return -EINVAL;
-
-       if (ser->baud_base < 9600)
-               return -EINVAL;
-
-       return 0;
-}
-/* UART operations
- *
- * Details on these functions can be found in Documentation/serial/driver
- */
-static struct uart_ops qe_uart_pops = {
-       .tx_empty       = qe_uart_tx_empty,
-       .set_mctrl      = qe_uart_set_mctrl,
-       .get_mctrl      = qe_uart_get_mctrl,
-       .stop_tx        = qe_uart_stop_tx,
-       .start_tx       = qe_uart_start_tx,
-       .stop_rx        = qe_uart_stop_rx,
-       .enable_ms      = qe_uart_enable_ms,
-       .break_ctl      = qe_uart_break_ctl,
-       .startup        = qe_uart_startup,
-       .shutdown       = qe_uart_shutdown,
-       .set_termios    = qe_uart_set_termios,
-       .type           = qe_uart_type,
-       .release_port   = qe_uart_release_port,
-       .request_port   = qe_uart_request_port,
-       .config_port    = qe_uart_config_port,
-       .verify_port    = qe_uart_verify_port,
-};
-
-/*
- * Obtain the SOC model number and revision level
- *
- * This function parses the device tree to obtain the SOC model.  It then
- * reads the SVR register to the revision.
- *
- * The device tree stores the SOC model two different ways.
- *
- * The new way is:
- *
- *             cpu@0 {
- *                     compatible = "PowerPC,8323";
- *                     device_type = "cpu";
- *                     ...
- *
- *
- * The old way is:
- *              PowerPC,8323@0 {
- *                     device_type = "cpu";
- *                     ...
- *
- * This code first checks the new way, and then the old way.
- */
-static unsigned int soc_info(unsigned int *rev_h, unsigned int *rev_l)
-{
-       struct device_node *np;
-       const char *soc_string;
-       unsigned int svr;
-       unsigned int soc;
-
-       /* Find the CPU node */
-       np = of_find_node_by_type(NULL, "cpu");
-       if (!np)
-               return 0;
-       /* Find the compatible property */
-       soc_string = of_get_property(np, "compatible", NULL);
-       if (!soc_string)
-               /* No compatible property, so try the name. */
-               soc_string = np->name;
-
-       /* Extract the SOC number from the "PowerPC," string */
-       if ((sscanf(soc_string, "PowerPC,%u", &soc) != 1) || !soc)
-               return 0;
-
-       /* Get the revision from the SVR */
-       svr = mfspr(SPRN_SVR);
-       *rev_h = (svr >> 4) & 0xf;
-       *rev_l = svr & 0xf;
-
-       return soc;
-}
-
-/*
- * requst_firmware_nowait() callback function
- *
- * This function is called by the kernel when a firmware is made available,
- * or if it times out waiting for the firmware.
- */
-static void uart_firmware_cont(const struct firmware *fw, void *context)
-{
-       struct qe_firmware *firmware;
-       struct device *dev = context;
-       int ret;
-
-       if (!fw) {
-               dev_err(dev, "firmware not found\n");
-               return;
-       }
-
-       firmware = (struct qe_firmware *) fw->data;
-
-       if (firmware->header.length != fw->size) {
-               dev_err(dev, "invalid firmware\n");
-               goto out;
-       }
-
-       ret = qe_upload_firmware(firmware);
-       if (ret) {
-               dev_err(dev, "could not load firmware\n");
-               goto out;
-       }
-
-       firmware_loaded = 1;
- out:
-       release_firmware(fw);
-}
-
-static int ucc_uart_probe(struct platform_device *ofdev,
-       const struct of_device_id *match)
-{
-       struct device_node *np = ofdev->dev.of_node;
-       const unsigned int *iprop;      /* Integer OF properties */
-       const char *sprop;      /* String OF properties */
-       struct uart_qe_port *qe_port = NULL;
-       struct resource res;
-       int ret;
-
-       /*
-        * Determine if we need Soft-UART mode
-        */
-       if (of_find_property(np, "soft-uart", NULL)) {
-               dev_dbg(&ofdev->dev, "using Soft-UART mode\n");
-               soft_uart = 1;
-       }
-
-       /*
-        * If we are using Soft-UART, determine if we need to upload the
-        * firmware, too.
-        */
-       if (soft_uart) {
-               struct qe_firmware_info *qe_fw_info;
-
-               qe_fw_info = qe_get_firmware_info();
-
-               /* Check if the firmware has been uploaded. */
-               if (qe_fw_info && strstr(qe_fw_info->id, "Soft-UART")) {
-                       firmware_loaded = 1;
-               } else {
-                       char filename[32];
-                       unsigned int soc;
-                       unsigned int rev_h;
-                       unsigned int rev_l;
-
-                       soc = soc_info(&rev_h, &rev_l);
-                       if (!soc) {
-                               dev_err(&ofdev->dev, "unknown CPU model\n");
-                               return -ENXIO;
-                       }
-                       sprintf(filename, "fsl_qe_ucode_uart_%u_%u%u.bin",
-                               soc, rev_h, rev_l);
-
-                       dev_info(&ofdev->dev, "waiting for firmware %s\n",
-                               filename);
-
-                       /*
-                        * We call request_firmware_nowait instead of
-                        * request_firmware so that the driver can load and
-                        * initialize the ports without holding up the rest of
-                        * the kernel.  If hotplug support is enabled in the
-                        * kernel, then we use it.
-                        */
-                       ret = request_firmware_nowait(THIS_MODULE,
-                               FW_ACTION_HOTPLUG, filename, &ofdev->dev,
-                               GFP_KERNEL, &ofdev->dev, uart_firmware_cont);
-                       if (ret) {
-                               dev_err(&ofdev->dev,
-                                       "could not load firmware %s\n",
-                                       filename);
-                               return ret;
-                       }
-               }
-       }
-
-       qe_port = kzalloc(sizeof(struct uart_qe_port), GFP_KERNEL);
-       if (!qe_port) {
-               dev_err(&ofdev->dev, "can't allocate QE port structure\n");
-               return -ENOMEM;
-       }
-
-       /* Search for IRQ and mapbase */
-       ret = of_address_to_resource(np, 0, &res);
-       if (ret) {
-               dev_err(&ofdev->dev, "missing 'reg' property in device tree\n");
-               kfree(qe_port);
-               return ret;
-       }
-       if (!res.start) {
-               dev_err(&ofdev->dev, "invalid 'reg' property in device tree\n");
-               kfree(qe_port);
-               return -EINVAL;
-       }
-       qe_port->port.mapbase = res.start;
-
-       /* Get the UCC number (device ID) */
-       /* UCCs are numbered 1-7 */
-       iprop = of_get_property(np, "cell-index", NULL);
-       if (!iprop) {
-               iprop = of_get_property(np, "device-id", NULL);
-               if (!iprop) {
-                       kfree(qe_port);
-                       dev_err(&ofdev->dev, "UCC is unspecified in "
-                               "device tree\n");
-                       return -EINVAL;
-               }
-       }
-
-       if ((*iprop < 1) || (*iprop > UCC_MAX_NUM)) {
-               dev_err(&ofdev->dev, "no support for UCC%u\n", *iprop);
-               kfree(qe_port);
-               return -ENODEV;
-       }
-       qe_port->ucc_num = *iprop - 1;
-
-       /*
-        * In the future, we should not require the BRG to be specified in the
-        * device tree.  If no clock-source is specified, then just pick a BRG
-        * to use.  This requires a new QE library function that manages BRG
-        * assignments.
-        */
-
-       sprop = of_get_property(np, "rx-clock-name", NULL);
-       if (!sprop) {
-               dev_err(&ofdev->dev, "missing rx-clock-name in device tree\n");
-               kfree(qe_port);
-               return -ENODEV;
-       }
-
-       qe_port->us_info.rx_clock = qe_clock_source(sprop);
-       if ((qe_port->us_info.rx_clock < QE_BRG1) ||
-           (qe_port->us_info.rx_clock > QE_BRG16)) {
-               dev_err(&ofdev->dev, "rx-clock-name must be a BRG for UART\n");
-               kfree(qe_port);
-               return -ENODEV;
-       }
-
-#ifdef LOOPBACK
-       /* In internal loopback mode, TX and RX must use the same clock */
-       qe_port->us_info.tx_clock = qe_port->us_info.rx_clock;
-#else
-       sprop = of_get_property(np, "tx-clock-name", NULL);
-       if (!sprop) {
-               dev_err(&ofdev->dev, "missing tx-clock-name in device tree\n");
-               kfree(qe_port);
-               return -ENODEV;
-       }
-       qe_port->us_info.tx_clock = qe_clock_source(sprop);
-#endif
-       if ((qe_port->us_info.tx_clock < QE_BRG1) ||
-           (qe_port->us_info.tx_clock > QE_BRG16)) {
-               dev_err(&ofdev->dev, "tx-clock-name must be a BRG for UART\n");
-               kfree(qe_port);
-               return -ENODEV;
-       }
-
-       /* Get the port number, numbered 0-3 */
-       iprop = of_get_property(np, "port-number", NULL);
-       if (!iprop) {
-               dev_err(&ofdev->dev, "missing port-number in device tree\n");
-               kfree(qe_port);
-               return -EINVAL;
-       }
-       qe_port->port.line = *iprop;
-       if (qe_port->port.line >= UCC_MAX_UART) {
-               dev_err(&ofdev->dev, "port-number must be 0-%u\n",
-                       UCC_MAX_UART - 1);
-               kfree(qe_port);
-               return -EINVAL;
-       }
-
-       qe_port->port.irq = irq_of_parse_and_map(np, 0);
-       if (qe_port->port.irq == NO_IRQ) {
-               dev_err(&ofdev->dev, "could not map IRQ for UCC%u\n",
-                      qe_port->ucc_num + 1);
-               kfree(qe_port);
-               return -EINVAL;
-       }
-
-       /*
-        * Newer device trees have an "fsl,qe" compatible property for the QE
-        * node, but we still need to support older device trees.
-        */
-       np = of_find_compatible_node(NULL, NULL, "fsl,qe");
-       if (!np) {
-               np = of_find_node_by_type(NULL, "qe");
-               if (!np) {
-                       dev_err(&ofdev->dev, "could not find 'qe' node\n");
-                       kfree(qe_port);
-                       return -EINVAL;
-               }
-       }
-
-       iprop = of_get_property(np, "brg-frequency", NULL);
-       if (!iprop) {
-               dev_err(&ofdev->dev,
-                      "missing brg-frequency in device tree\n");
-               kfree(qe_port);
-               return -EINVAL;
-       }
-
-       if (*iprop)
-               qe_port->port.uartclk = *iprop;
-       else {
-               /*
-                * Older versions of U-Boot do not initialize the brg-frequency
-                * property, so in this case we assume the BRG frequency is
-                * half the QE bus frequency.
-                */
-               iprop = of_get_property(np, "bus-frequency", NULL);
-               if (!iprop) {
-                       dev_err(&ofdev->dev,
-                               "missing QE bus-frequency in device tree\n");
-                       kfree(qe_port);
-                       return -EINVAL;
-               }
-               if (*iprop)
-                       qe_port->port.uartclk = *iprop / 2;
-               else {
-                       dev_err(&ofdev->dev,
-                               "invalid QE bus-frequency in device tree\n");
-                       kfree(qe_port);
-                       return -EINVAL;
-               }
-       }
-
-       spin_lock_init(&qe_port->port.lock);
-       qe_port->np = np;
-       qe_port->port.dev = &ofdev->dev;
-       qe_port->port.ops = &qe_uart_pops;
-       qe_port->port.iotype = UPIO_MEM;
-
-       qe_port->tx_nrfifos = TX_NUM_FIFO;
-       qe_port->tx_fifosize = TX_BUF_SIZE;
-       qe_port->rx_nrfifos = RX_NUM_FIFO;
-       qe_port->rx_fifosize = RX_BUF_SIZE;
-
-       qe_port->wait_closing = UCC_WAIT_CLOSING;
-       qe_port->port.fifosize = 512;
-       qe_port->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
-
-       qe_port->us_info.ucc_num = qe_port->ucc_num;
-       qe_port->us_info.regs = (phys_addr_t) res.start;
-       qe_port->us_info.irq = qe_port->port.irq;
-
-       qe_port->us_info.rx_bd_ring_len = qe_port->rx_nrfifos;
-       qe_port->us_info.tx_bd_ring_len = qe_port->tx_nrfifos;
-
-       /* Make sure ucc_slow_init() initializes both TX and RX */
-       qe_port->us_info.init_tx = 1;
-       qe_port->us_info.init_rx = 1;
-
-       /* Add the port to the uart sub-system.  This will cause
-        * qe_uart_config_port() to be called, so the us_info structure must
-        * be initialized.
-        */
-       ret = uart_add_one_port(&ucc_uart_driver, &qe_port->port);
-       if (ret) {
-               dev_err(&ofdev->dev, "could not add /dev/ttyQE%u\n",
-                      qe_port->port.line);
-               kfree(qe_port);
-               return ret;
-       }
-
-       dev_set_drvdata(&ofdev->dev, qe_port);
-
-       dev_info(&ofdev->dev, "UCC%u assigned to /dev/ttyQE%u\n",
-               qe_port->ucc_num + 1, qe_port->port.line);
-
-       /* Display the mknod command for this device */
-       dev_dbg(&ofdev->dev, "mknod command is 'mknod /dev/ttyQE%u c %u %u'\n",
-              qe_port->port.line, SERIAL_QE_MAJOR,
-              SERIAL_QE_MINOR + qe_port->port.line);
-
-       return 0;
-}
-
-static int ucc_uart_remove(struct platform_device *ofdev)
-{
-       struct uart_qe_port *qe_port = dev_get_drvdata(&ofdev->dev);
-
-       dev_info(&ofdev->dev, "removing /dev/ttyQE%u\n", qe_port->port.line);
-
-       uart_remove_one_port(&ucc_uart_driver, &qe_port->port);
-
-       dev_set_drvdata(&ofdev->dev, NULL);
-       kfree(qe_port);
-
-       return 0;
-}
-
-static struct of_device_id ucc_uart_match[] = {
-       {
-               .type = "serial",
-               .compatible = "ucc_uart",
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(of, ucc_uart_match);
-
-static struct of_platform_driver ucc_uart_of_driver = {
-       .driver = {
-               .name = "ucc_uart",
-               .owner = THIS_MODULE,
-               .of_match_table    = ucc_uart_match,
-       },
-       .probe          = ucc_uart_probe,
-       .remove         = ucc_uart_remove,
-};
-
-static int __init ucc_uart_init(void)
-{
-       int ret;
-
-       printk(KERN_INFO "Freescale QUICC Engine UART device driver\n");
-#ifdef LOOPBACK
-       printk(KERN_INFO "ucc-uart: Using loopback mode\n");
-#endif
-
-       ret = uart_register_driver(&ucc_uart_driver);
-       if (ret) {
-               printk(KERN_ERR "ucc-uart: could not register UART driver\n");
-               return ret;
-       }
-
-       ret = of_register_platform_driver(&ucc_uart_of_driver);
-       if (ret)
-               printk(KERN_ERR
-                      "ucc-uart: could not register platform driver\n");
-
-       return ret;
-}
-
-static void __exit ucc_uart_exit(void)
-{
-       printk(KERN_INFO
-              "Freescale QUICC Engine UART device driver unloading\n");
-
-       of_unregister_platform_driver(&ucc_uart_of_driver);
-       uart_unregister_driver(&ucc_uart_driver);
-}
-
-module_init(ucc_uart_init);
-module_exit(ucc_uart_exit);
-
-MODULE_DESCRIPTION("Freescale QUICC Engine (QE) UART");
-MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_QE_MAJOR);
-
diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c
deleted file mode 100644 (file)
index 3beb6ab..0000000
+++ /dev/null
@@ -1,978 +0,0 @@
-/*
- *  Driver for NEC VR4100 series Serial Interface Unit.
- *
- *  Copyright (C) 2004-2008  Yoichi Yuasa <yuasa@linux-mips.org>
- *
- *  Based on drivers/serial/8250.c, by Russell King.
- *
- *  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
- */
-
-#if defined(CONFIG_SERIAL_VR41XX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/console.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <linux/serial_reg.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-
-#include <asm/io.h>
-#include <asm/vr41xx/siu.h>
-#include <asm/vr41xx/vr41xx.h>
-
-#define SIU_BAUD_BASE  1152000
-#define SIU_MAJOR      204
-#define SIU_MINOR_BASE 82
-
-#define RX_MAX_COUNT   256
-#define TX_MAX_COUNT   15
-
-#define SIUIRSEL       0x08
- #define TMICMODE      0x20
- #define TMICTX                0x10
- #define IRMSEL                0x0c
- #define IRMSEL_HP     0x08
- #define IRMSEL_TEMIC  0x04
- #define IRMSEL_SHARP  0x00
- #define IRUSESEL      0x02
- #define SIRSEL                0x01
-
-static struct uart_port siu_uart_ports[SIU_PORTS_MAX] = {
-       [0 ... SIU_PORTS_MAX-1] = {
-               .lock   = __SPIN_LOCK_UNLOCKED(siu_uart_ports->lock),
-               .irq    = -1,
-       },
-};
-
-#ifdef CONFIG_SERIAL_VR41XX_CONSOLE
-static uint8_t lsr_break_flag[SIU_PORTS_MAX];
-#endif
-
-#define siu_read(port, offset)         readb((port)->membase + (offset))
-#define siu_write(port, offset, value) writeb((value), (port)->membase + (offset))
-
-void vr41xx_select_siu_interface(siu_interface_t interface)
-{
-       struct uart_port *port;
-       unsigned long flags;
-       uint8_t irsel;
-
-       port = &siu_uart_ports[0];
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       irsel = siu_read(port, SIUIRSEL);
-       if (interface == SIU_INTERFACE_IRDA)
-               irsel |= SIRSEL;
-       else
-               irsel &= ~SIRSEL;
-       siu_write(port, SIUIRSEL, irsel);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-EXPORT_SYMBOL_GPL(vr41xx_select_siu_interface);
-
-void vr41xx_use_irda(irda_use_t use)
-{
-       struct uart_port *port;
-       unsigned long flags;
-       uint8_t irsel;
-
-       port = &siu_uart_ports[0];
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       irsel = siu_read(port, SIUIRSEL);
-       if (use == FIR_USE_IRDA)
-               irsel |= IRUSESEL;
-       else
-               irsel &= ~IRUSESEL;
-       siu_write(port, SIUIRSEL, irsel);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-EXPORT_SYMBOL_GPL(vr41xx_use_irda);
-
-void vr41xx_select_irda_module(irda_module_t module, irda_speed_t speed)
-{
-       struct uart_port *port;
-       unsigned long flags;
-       uint8_t irsel;
-
-       port = &siu_uart_ports[0];
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       irsel = siu_read(port, SIUIRSEL);
-       irsel &= ~(IRMSEL | TMICTX | TMICMODE);
-       switch (module) {
-       case SHARP_IRDA:
-               irsel |= IRMSEL_SHARP;
-               break;
-       case TEMIC_IRDA:
-               irsel |= IRMSEL_TEMIC | TMICMODE;
-               if (speed == IRDA_TX_4MBPS)
-                       irsel |= TMICTX;
-               break;
-       case HP_IRDA:
-               irsel |= IRMSEL_HP;
-               break;
-       default:
-               break;
-       }
-       siu_write(port, SIUIRSEL, irsel);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-EXPORT_SYMBOL_GPL(vr41xx_select_irda_module);
-
-static inline void siu_clear_fifo(struct uart_port *port)
-{
-       siu_write(port, UART_FCR, UART_FCR_ENABLE_FIFO);
-       siu_write(port, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
-                                 UART_FCR_CLEAR_XMIT);
-       siu_write(port, UART_FCR, 0);
-}
-
-static inline unsigned long siu_port_size(struct uart_port *port)
-{
-       switch (port->type) {
-       case PORT_VR41XX_SIU:
-               return 11UL;
-       case PORT_VR41XX_DSIU:
-               return 8UL;
-       }
-
-       return 0;
-}
-
-static inline unsigned int siu_check_type(struct uart_port *port)
-{
-       if (port->line == 0)
-               return PORT_VR41XX_SIU;
-       if (port->line == 1 && port->irq != -1)
-               return PORT_VR41XX_DSIU;
-
-       return PORT_UNKNOWN;
-}
-
-static inline const char *siu_type_name(struct uart_port *port)
-{
-       switch (port->type) {
-       case PORT_VR41XX_SIU:
-               return "SIU";
-       case PORT_VR41XX_DSIU:
-               return "DSIU";
-       }
-
-       return NULL;
-}
-
-static unsigned int siu_tx_empty(struct uart_port *port)
-{
-       uint8_t lsr;
-
-       lsr = siu_read(port, UART_LSR);
-       if (lsr & UART_LSR_TEMT)
-               return TIOCSER_TEMT;
-
-       return 0;
-}
-
-static void siu_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       uint8_t mcr = 0;
-
-       if (mctrl & TIOCM_DTR)
-               mcr |= UART_MCR_DTR;
-       if (mctrl & TIOCM_RTS)
-               mcr |= UART_MCR_RTS;
-       if (mctrl & TIOCM_OUT1)
-               mcr |= UART_MCR_OUT1;
-       if (mctrl & TIOCM_OUT2)
-               mcr |= UART_MCR_OUT2;
-       if (mctrl & TIOCM_LOOP)
-               mcr |= UART_MCR_LOOP;
-
-       siu_write(port, UART_MCR, mcr);
-}
-
-static unsigned int siu_get_mctrl(struct uart_port *port)
-{
-       uint8_t msr;
-       unsigned int mctrl = 0;
-
-       msr = siu_read(port, UART_MSR);
-       if (msr & UART_MSR_DCD)
-               mctrl |= TIOCM_CAR;
-       if (msr & UART_MSR_RI)
-               mctrl |= TIOCM_RNG;
-       if (msr & UART_MSR_DSR)
-               mctrl |= TIOCM_DSR;
-       if (msr & UART_MSR_CTS)
-               mctrl |= TIOCM_CTS;
-
-       return mctrl;
-}
-
-static void siu_stop_tx(struct uart_port *port)
-{
-       unsigned long flags;
-       uint8_t ier;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       ier = siu_read(port, UART_IER);
-       ier &= ~UART_IER_THRI;
-       siu_write(port, UART_IER, ier);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void siu_start_tx(struct uart_port *port)
-{
-       unsigned long flags;
-       uint8_t ier;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       ier = siu_read(port, UART_IER);
-       ier |= UART_IER_THRI;
-       siu_write(port, UART_IER, ier);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void siu_stop_rx(struct uart_port *port)
-{
-       unsigned long flags;
-       uint8_t ier;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       ier = siu_read(port, UART_IER);
-       ier &= ~UART_IER_RLSI;
-       siu_write(port, UART_IER, ier);
-
-       port->read_status_mask &= ~UART_LSR_DR;
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void siu_enable_ms(struct uart_port *port)
-{
-       unsigned long flags;
-       uint8_t ier;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       ier = siu_read(port, UART_IER);
-       ier |= UART_IER_MSI;
-       siu_write(port, UART_IER, ier);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void siu_break_ctl(struct uart_port *port, int ctl)
-{
-       unsigned long flags;
-       uint8_t lcr;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       lcr = siu_read(port, UART_LCR);
-       if (ctl == -1)
-               lcr |= UART_LCR_SBC;
-       else
-               lcr &= ~UART_LCR_SBC;
-       siu_write(port, UART_LCR, lcr);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static inline void receive_chars(struct uart_port *port, uint8_t *status)
-{
-       struct tty_struct *tty;
-       uint8_t lsr, ch;
-       char flag;
-       int max_count = RX_MAX_COUNT;
-
-       tty = port->state->port.tty;
-       lsr = *status;
-
-       do {
-               ch = siu_read(port, UART_RX);
-               port->icount.rx++;
-               flag = TTY_NORMAL;
-
-#ifdef CONFIG_SERIAL_VR41XX_CONSOLE
-               lsr |= lsr_break_flag[port->line];
-               lsr_break_flag[port->line] = 0;
-#endif
-               if (unlikely(lsr & (UART_LSR_BI | UART_LSR_FE |
-                                   UART_LSR_PE | UART_LSR_OE))) {
-                       if (lsr & UART_LSR_BI) {
-                               lsr &= ~(UART_LSR_FE | UART_LSR_PE);
-                               port->icount.brk++;
-
-                               if (uart_handle_break(port))
-                                       goto ignore_char;
-                       }
-
-                       if (lsr & UART_LSR_FE)
-                               port->icount.frame++;
-                       if (lsr & UART_LSR_PE)
-                               port->icount.parity++;
-                       if (lsr & UART_LSR_OE)
-                               port->icount.overrun++;
-
-                       lsr &= port->read_status_mask;
-                       if (lsr & UART_LSR_BI)
-                               flag = TTY_BREAK;
-                       if (lsr & UART_LSR_FE)
-                               flag = TTY_FRAME;
-                       if (lsr & UART_LSR_PE)
-                               flag = TTY_PARITY;
-               }
-
-               if (uart_handle_sysrq_char(port, ch))
-                       goto ignore_char;
-
-               uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
-
-       ignore_char:
-               lsr = siu_read(port, UART_LSR);
-       } while ((lsr & UART_LSR_DR) && (max_count-- > 0));
-
-       tty_flip_buffer_push(tty);
-
-       *status = lsr;
-}
-
-static inline void check_modem_status(struct uart_port *port)
-{
-       uint8_t msr;
-
-       msr = siu_read(port, UART_MSR);
-       if ((msr & UART_MSR_ANY_DELTA) == 0)
-               return;
-       if (msr & UART_MSR_DDCD)
-               uart_handle_dcd_change(port, msr & UART_MSR_DCD);
-       if (msr & UART_MSR_TERI)
-               port->icount.rng++;
-       if (msr & UART_MSR_DDSR)
-               port->icount.dsr++;
-       if (msr & UART_MSR_DCTS)
-               uart_handle_cts_change(port, msr & UART_MSR_CTS);
-
-       wake_up_interruptible(&port->state->port.delta_msr_wait);
-}
-
-static inline void transmit_chars(struct uart_port *port)
-{
-       struct circ_buf *xmit;
-       int max_count = TX_MAX_COUNT;
-
-       xmit = &port->state->xmit;
-
-       if (port->x_char) {
-               siu_write(port, UART_TX, port->x_char);
-               port->icount.tx++;
-               port->x_char = 0;
-               return;
-       }
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               siu_stop_tx(port);
-               return;
-       }
-
-       do {
-               siu_write(port, UART_TX, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (max_count-- > 0);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (uart_circ_empty(xmit))
-               siu_stop_tx(port);
-}
-
-static irqreturn_t siu_interrupt(int irq, void *dev_id)
-{
-       struct uart_port *port;
-       uint8_t iir, lsr;
-
-       port = (struct uart_port *)dev_id;
-
-       iir = siu_read(port, UART_IIR);
-       if (iir & UART_IIR_NO_INT)
-               return IRQ_NONE;
-
-       lsr = siu_read(port, UART_LSR);
-       if (lsr & UART_LSR_DR)
-               receive_chars(port, &lsr);
-
-       check_modem_status(port);
-
-       if (lsr & UART_LSR_THRE)
-               transmit_chars(port);
-
-       return IRQ_HANDLED;
-}
-
-static int siu_startup(struct uart_port *port)
-{
-       int retval;
-
-       if (port->membase == NULL)
-               return -ENODEV;
-
-       siu_clear_fifo(port);
-
-       (void)siu_read(port, UART_LSR);
-       (void)siu_read(port, UART_RX);
-       (void)siu_read(port, UART_IIR);
-       (void)siu_read(port, UART_MSR);
-
-       if (siu_read(port, UART_LSR) == 0xff)
-               return -ENODEV;
-
-       retval = request_irq(port->irq, siu_interrupt, 0, siu_type_name(port), port);
-       if (retval)
-               return retval;
-
-       if (port->type == PORT_VR41XX_DSIU)
-               vr41xx_enable_dsiuint(DSIUINT_ALL);
-
-       siu_write(port, UART_LCR, UART_LCR_WLEN8);
-
-       spin_lock_irq(&port->lock);
-       siu_set_mctrl(port, port->mctrl);
-       spin_unlock_irq(&port->lock);
-
-       siu_write(port, UART_IER, UART_IER_RLSI | UART_IER_RDI);
-
-       (void)siu_read(port, UART_LSR);
-       (void)siu_read(port, UART_RX);
-       (void)siu_read(port, UART_IIR);
-       (void)siu_read(port, UART_MSR);
-
-       return 0;
-}
-
-static void siu_shutdown(struct uart_port *port)
-{
-       unsigned long flags;
-       uint8_t lcr;
-
-       siu_write(port, UART_IER, 0);
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       port->mctrl &= ~TIOCM_OUT2;
-       siu_set_mctrl(port, port->mctrl);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       lcr = siu_read(port, UART_LCR);
-       lcr &= ~UART_LCR_SBC;
-       siu_write(port, UART_LCR, lcr);
-
-       siu_clear_fifo(port);
-
-       (void)siu_read(port, UART_RX);
-
-       if (port->type == PORT_VR41XX_DSIU)
-               vr41xx_disable_dsiuint(DSIUINT_ALL);
-
-       free_irq(port->irq, port);
-}
-
-static void siu_set_termios(struct uart_port *port, struct ktermios *new,
-                            struct ktermios *old)
-{
-       tcflag_t c_cflag, c_iflag;
-       uint8_t lcr, fcr, ier;
-       unsigned int baud, quot;
-       unsigned long flags;
-
-       c_cflag = new->c_cflag;
-       switch (c_cflag & CSIZE) {
-       case CS5:
-               lcr = UART_LCR_WLEN5;
-               break;
-       case CS6:
-               lcr = UART_LCR_WLEN6;
-               break;
-       case CS7:
-               lcr = UART_LCR_WLEN7;
-               break;
-       default:
-               lcr = UART_LCR_WLEN8;
-               break;
-       }
-
-       if (c_cflag & CSTOPB)
-               lcr |= UART_LCR_STOP;
-       if (c_cflag & PARENB)
-               lcr |= UART_LCR_PARITY;
-       if ((c_cflag & PARODD) != PARODD)
-               lcr |= UART_LCR_EPAR;
-       if (c_cflag & CMSPAR)
-               lcr |= UART_LCR_SPAR;
-
-       baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
-       quot = uart_get_divisor(port, baud);
-
-       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       uart_update_timeout(port, c_cflag, baud);
-
-       c_iflag = new->c_iflag;
-
-       port->read_status_mask = UART_LSR_THRE | UART_LSR_OE | UART_LSR_DR;
-       if (c_iflag & INPCK)
-               port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (c_iflag & (BRKINT | PARMRK))
-               port->read_status_mask |= UART_LSR_BI;
-
-       port->ignore_status_mask = 0;
-       if (c_iflag & IGNPAR)
-               port->ignore_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (c_iflag & IGNBRK) {
-               port->ignore_status_mask |= UART_LSR_BI;
-               if (c_iflag & IGNPAR)
-                       port->ignore_status_mask |= UART_LSR_OE;
-       }
-
-       if ((c_cflag & CREAD) == 0)
-               port->ignore_status_mask |= UART_LSR_DR;
-
-       ier = siu_read(port, UART_IER);
-       ier &= ~UART_IER_MSI;
-       if (UART_ENABLE_MS(port, c_cflag))
-               ier |= UART_IER_MSI;
-       siu_write(port, UART_IER, ier);
-
-       siu_write(port, UART_LCR, lcr | UART_LCR_DLAB);
-
-       siu_write(port, UART_DLL, (uint8_t)quot);
-       siu_write(port, UART_DLM, (uint8_t)(quot >> 8));
-
-       siu_write(port, UART_LCR, lcr);
-
-       siu_write(port, UART_FCR, fcr);
-
-       siu_set_mctrl(port, port->mctrl);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void siu_pm(struct uart_port *port, unsigned int state, unsigned int oldstate)
-{
-       switch (state) {
-       case 0:
-               switch (port->type) {
-               case PORT_VR41XX_SIU:
-                       vr41xx_supply_clock(SIU_CLOCK);
-                       break;
-               case PORT_VR41XX_DSIU:
-                       vr41xx_supply_clock(DSIU_CLOCK);
-                       break;
-               }
-               break;
-       case 3:
-               switch (port->type) {
-               case PORT_VR41XX_SIU:
-                       vr41xx_mask_clock(SIU_CLOCK);
-                       break;
-               case PORT_VR41XX_DSIU:
-                       vr41xx_mask_clock(DSIU_CLOCK);
-                       break;
-               }
-               break;
-       }
-}
-
-static const char *siu_type(struct uart_port *port)
-{
-       return siu_type_name(port);
-}
-
-static void siu_release_port(struct uart_port *port)
-{
-       unsigned long size;
-
-       if (port->flags & UPF_IOREMAP) {
-               iounmap(port->membase);
-               port->membase = NULL;
-       }
-
-       size = siu_port_size(port);
-       release_mem_region(port->mapbase, size);
-}
-
-static int siu_request_port(struct uart_port *port)
-{
-       unsigned long size;
-       struct resource *res;
-
-       size = siu_port_size(port);
-       res = request_mem_region(port->mapbase, size, siu_type_name(port));
-       if (res == NULL)
-               return -EBUSY;
-
-       if (port->flags & UPF_IOREMAP) {
-               port->membase = ioremap(port->mapbase, size);
-               if (port->membase == NULL) {
-                       release_resource(res);
-                       return -ENOMEM;
-               }
-       }
-
-       return 0;
-}
-
-static void siu_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE) {
-               port->type = siu_check_type(port);
-               (void)siu_request_port(port);
-       }
-}
-
-static int siu_verify_port(struct uart_port *port, struct serial_struct *serial)
-{
-       if (port->type != PORT_VR41XX_SIU && port->type != PORT_VR41XX_DSIU)
-               return -EINVAL;
-       if (port->irq != serial->irq)
-               return -EINVAL;
-       if (port->iotype != serial->io_type)
-               return -EINVAL;
-       if (port->mapbase != (unsigned long)serial->iomem_base)
-               return -EINVAL;
-
-       return 0;
-}
-
-static struct uart_ops siu_uart_ops = {
-       .tx_empty       = siu_tx_empty,
-       .set_mctrl      = siu_set_mctrl,
-       .get_mctrl      = siu_get_mctrl,
-       .stop_tx        = siu_stop_tx,
-       .start_tx       = siu_start_tx,
-       .stop_rx        = siu_stop_rx,
-       .enable_ms      = siu_enable_ms,
-       .break_ctl      = siu_break_ctl,
-       .startup        = siu_startup,
-       .shutdown       = siu_shutdown,
-       .set_termios    = siu_set_termios,
-       .pm             = siu_pm,
-       .type           = siu_type,
-       .release_port   = siu_release_port,
-       .request_port   = siu_request_port,
-       .config_port    = siu_config_port,
-       .verify_port    = siu_verify_port,
-};
-
-static int siu_init_ports(struct platform_device *pdev)
-{
-       struct uart_port *port;
-       struct resource *res;
-       int *type = pdev->dev.platform_data;
-       int i;
-
-       if (!type)
-               return 0;
-
-       port = siu_uart_ports;
-       for (i = 0; i < SIU_PORTS_MAX; i++) {
-               port->type = type[i];
-               if (port->type == PORT_UNKNOWN)
-                       continue;
-               port->irq = platform_get_irq(pdev, i);
-               port->uartclk = SIU_BAUD_BASE * 16;
-               port->fifosize = 16;
-               port->regshift = 0;
-               port->iotype = UPIO_MEM;
-               port->flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
-               port->line = i;
-               res = platform_get_resource(pdev, IORESOURCE_MEM, i);
-               port->mapbase = res->start;
-               port++;
-       }
-
-       return i;
-}
-
-#ifdef CONFIG_SERIAL_VR41XX_CONSOLE
-
-#define BOTH_EMPTY     (UART_LSR_TEMT | UART_LSR_THRE)
-
-static void wait_for_xmitr(struct uart_port *port)
-{
-       int timeout = 10000;
-       uint8_t lsr, msr;
-
-       do {
-               lsr = siu_read(port, UART_LSR);
-               if (lsr & UART_LSR_BI)
-                       lsr_break_flag[port->line] = UART_LSR_BI;
-
-               if ((lsr & BOTH_EMPTY) == BOTH_EMPTY)
-                       break;
-       } while (timeout-- > 0);
-
-       if (port->flags & UPF_CONS_FLOW) {
-               timeout = 1000000;
-
-               do {
-                       msr = siu_read(port, UART_MSR);
-                       if ((msr & UART_MSR_CTS) != 0)
-                               break;
-               } while (timeout-- > 0);
-       }
-}
-
-static void siu_console_putchar(struct uart_port *port, int ch)
-{
-       wait_for_xmitr(port);
-       siu_write(port, UART_TX, ch);
-}
-
-static void siu_console_write(struct console *con, const char *s, unsigned count)
-{
-       struct uart_port *port;
-       uint8_t ier;
-
-       port = &siu_uart_ports[con->index];
-
-       ier = siu_read(port, UART_IER);
-       siu_write(port, UART_IER, 0);
-
-       uart_console_write(port, s, count, siu_console_putchar);
-
-       wait_for_xmitr(port);
-       siu_write(port, UART_IER, ier);
-}
-
-static int __init siu_console_setup(struct console *con, char *options)
-{
-       struct uart_port *port;
-       int baud = 9600;
-       int parity = 'n';
-       int bits = 8;
-       int flow = 'n';
-
-       if (con->index >= SIU_PORTS_MAX)
-               con->index = 0;
-
-       port = &siu_uart_ports[con->index];
-       if (port->membase == NULL) {
-               if (port->mapbase == 0)
-                       return -ENODEV;
-               port->membase = ioremap(port->mapbase, siu_port_size(port));
-       }
-
-       if (port->type == PORT_VR41XX_SIU)
-               vr41xx_select_siu_interface(SIU_INTERFACE_RS232C);
-
-       if (options != NULL)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(port, con, baud, parity, bits, flow);
-}
-
-static struct uart_driver siu_uart_driver;
-
-static struct console siu_console = {
-       .name   = "ttyVR",
-       .write  = siu_console_write,
-       .device = uart_console_device,
-       .setup  = siu_console_setup,
-       .flags  = CON_PRINTBUFFER,
-       .index  = -1,
-       .data   = &siu_uart_driver,
-};
-
-static int __devinit siu_console_init(void)
-{
-       struct uart_port *port;
-       int i;
-
-       for (i = 0; i < SIU_PORTS_MAX; i++) {
-               port = &siu_uart_ports[i];
-               port->ops = &siu_uart_ops;
-       }
-
-       register_console(&siu_console);
-
-       return 0;
-}
-
-console_initcall(siu_console_init);
-
-void __init vr41xx_siu_early_setup(struct uart_port *port)
-{
-       if (port->type == PORT_UNKNOWN)
-               return;
-
-       siu_uart_ports[port->line].line = port->line;
-       siu_uart_ports[port->line].type = port->type;
-       siu_uart_ports[port->line].uartclk = SIU_BAUD_BASE * 16;
-       siu_uart_ports[port->line].mapbase = port->mapbase;
-       siu_uart_ports[port->line].mapbase = port->mapbase;
-       siu_uart_ports[port->line].ops = &siu_uart_ops;
-}
-
-#define SERIAL_VR41XX_CONSOLE  &siu_console
-#else
-#define SERIAL_VR41XX_CONSOLE  NULL
-#endif
-
-static struct uart_driver siu_uart_driver = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "SIU",
-       .dev_name       = "ttyVR",
-       .major          = SIU_MAJOR,
-       .minor          = SIU_MINOR_BASE,
-       .cons           = SERIAL_VR41XX_CONSOLE,
-};
-
-static int __devinit siu_probe(struct platform_device *dev)
-{
-       struct uart_port *port;
-       int num, i, retval;
-
-       num = siu_init_ports(dev);
-       if (num <= 0)
-               return -ENODEV;
-
-       siu_uart_driver.nr = num;
-       retval = uart_register_driver(&siu_uart_driver);
-       if (retval)
-               return retval;
-
-       for (i = 0; i < num; i++) {
-               port = &siu_uart_ports[i];
-               port->ops = &siu_uart_ops;
-               port->dev = &dev->dev;
-
-               retval = uart_add_one_port(&siu_uart_driver, port);
-               if (retval < 0) {
-                       port->dev = NULL;
-                       break;
-               }
-       }
-
-       if (i == 0 && retval < 0) {
-               uart_unregister_driver(&siu_uart_driver);
-               return retval;
-       }
-
-       return 0;
-}
-
-static int __devexit siu_remove(struct platform_device *dev)
-{
-       struct uart_port *port;
-       int i;
-
-       for (i = 0; i < siu_uart_driver.nr; i++) {
-               port = &siu_uart_ports[i];
-               if (port->dev == &dev->dev) {
-                       uart_remove_one_port(&siu_uart_driver, port);
-                       port->dev = NULL;
-               }
-       }
-
-       uart_unregister_driver(&siu_uart_driver);
-
-       return 0;
-}
-
-static int siu_suspend(struct platform_device *dev, pm_message_t state)
-{
-       struct uart_port *port;
-       int i;
-
-       for (i = 0; i < siu_uart_driver.nr; i++) {
-               port = &siu_uart_ports[i];
-               if ((port->type == PORT_VR41XX_SIU ||
-                    port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev)
-                       uart_suspend_port(&siu_uart_driver, port);
-
-       }
-
-       return 0;
-}
-
-static int siu_resume(struct platform_device *dev)
-{
-       struct uart_port *port;
-       int i;
-
-       for (i = 0; i < siu_uart_driver.nr; i++) {
-               port = &siu_uart_ports[i];
-               if ((port->type == PORT_VR41XX_SIU ||
-                    port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev)
-                       uart_resume_port(&siu_uart_driver, port);
-       }
-
-       return 0;
-}
-
-static struct platform_driver siu_device_driver = {
-       .probe          = siu_probe,
-       .remove         = __devexit_p(siu_remove),
-       .suspend        = siu_suspend,
-       .resume         = siu_resume,
-       .driver         = {
-               .name   = "SIU",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init vr41xx_siu_init(void)
-{
-       return platform_driver_register(&siu_device_driver);
-}
-
-static void __exit vr41xx_siu_exit(void)
-{
-       platform_driver_unregister(&siu_device_driver);
-}
-
-module_init(vr41xx_siu_init);
-module_exit(vr41xx_siu_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:SIU");
diff --git a/drivers/serial/vt8500_serial.c b/drivers/serial/vt8500_serial.c
deleted file mode 100644 (file)
index 322bf56..0000000
+++ /dev/null
@@ -1,648 +0,0 @@
-/*
- * drivers/serial/vt8500_serial.c
- *
- * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
- *
- * Based on msm_serial.c, which is:
- * Copyright (C) 2007 Google, Inc.
- * Author: Robert Love <rlove@google.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- */
-
-#if defined(CONFIG_SERIAL_VT8500_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-# define SUPPORT_SYSRQ
-#endif
-
-#include <linux/hrtimer.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
-#include <linux/irq.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/slab.h>
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-
-/*
- * UART Register offsets
- */
-
-#define VT8500_URTDR           0x0000  /* Transmit data */
-#define VT8500_URRDR           0x0004  /* Receive data */
-#define VT8500_URDIV           0x0008  /* Clock/Baud rate divisor */
-#define VT8500_URLCR           0x000C  /* Line control */
-#define VT8500_URICR           0x0010  /* IrDA control */
-#define VT8500_URIER           0x0014  /* Interrupt enable */
-#define VT8500_URISR           0x0018  /* Interrupt status */
-#define VT8500_URUSR           0x001c  /* UART status */
-#define VT8500_URFCR           0x0020  /* FIFO control */
-#define VT8500_URFIDX          0x0024  /* FIFO index */
-#define VT8500_URBKR           0x0028  /* Break signal count */
-#define VT8500_URTOD           0x002c  /* Time out divisor */
-#define VT8500_TXFIFO          0x1000  /* Transmit FIFO (16x8) */
-#define VT8500_RXFIFO          0x1020  /* Receive FIFO (16x10) */
-
-/*
- * Interrupt enable and status bits
- */
-
-#define TXDE   (1 << 0)        /* Tx Data empty */
-#define RXDF   (1 << 1)        /* Rx Data full */
-#define TXFAE  (1 << 2)        /* Tx FIFO almost empty */
-#define TXFE   (1 << 3)        /* Tx FIFO empty */
-#define RXFAF  (1 << 4)        /* Rx FIFO almost full */
-#define RXFF   (1 << 5)        /* Rx FIFO full */
-#define TXUDR  (1 << 6)        /* Tx underrun */
-#define RXOVER (1 << 7)        /* Rx overrun */
-#define PER    (1 << 8)        /* Parity error */
-#define FER    (1 << 9)        /* Frame error */
-#define TCTS   (1 << 10)       /* Toggle of CTS */
-#define RXTOUT (1 << 11)       /* Rx timeout */
-#define BKDONE (1 << 12)       /* Break signal done */
-#define ERR    (1 << 13)       /* AHB error response */
-
-#define RX_FIFO_INTS   (RXFAF | RXFF | RXOVER | PER | FER | RXTOUT)
-#define TX_FIFO_INTS   (TXFAE | TXFE | TXUDR)
-
-struct vt8500_port {
-       struct uart_port        uart;
-       char                    name[16];
-       struct clk              *clk;
-       unsigned int            ier;
-};
-
-static inline void vt8500_write(struct uart_port *port, unsigned int val,
-                            unsigned int off)
-{
-       writel(val, port->membase + off);
-}
-
-static inline unsigned int vt8500_read(struct uart_port *port, unsigned int off)
-{
-       return readl(port->membase + off);
-}
-
-static void vt8500_stop_tx(struct uart_port *port)
-{
-       struct vt8500_port *vt8500_port = container_of(port,
-                                                      struct vt8500_port,
-                                                      uart);
-
-       vt8500_port->ier &= ~TX_FIFO_INTS;
-       vt8500_write(port, vt8500_port->ier, VT8500_URIER);
-}
-
-static void vt8500_stop_rx(struct uart_port *port)
-{
-       struct vt8500_port *vt8500_port = container_of(port,
-                                                      struct vt8500_port,
-                                                      uart);
-
-       vt8500_port->ier &= ~RX_FIFO_INTS;
-       vt8500_write(port, vt8500_port->ier, VT8500_URIER);
-}
-
-static void vt8500_enable_ms(struct uart_port *port)
-{
-       struct vt8500_port *vt8500_port = container_of(port,
-                                                      struct vt8500_port,
-                                                      uart);
-
-       vt8500_port->ier |= TCTS;
-       vt8500_write(port, vt8500_port->ier, VT8500_URIER);
-}
-
-static void handle_rx(struct uart_port *port)
-{
-       struct tty_struct *tty = tty_port_tty_get(&port->state->port);
-       if (!tty) {
-               /* Discard data: no tty available */
-               int count = (vt8500_read(port, VT8500_URFIDX) & 0x1f00) >> 8;
-               u16 ch;
-               while (count--)
-                       ch = readw(port->membase + VT8500_RXFIFO);
-               return;
-       }
-
-       /*
-        * Handle overrun
-        */
-       if ((vt8500_read(port, VT8500_URISR) & RXOVER)) {
-               port->icount.overrun++;
-               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-       }
-
-       /* and now the main RX loop */
-       while (vt8500_read(port, VT8500_URFIDX) & 0x1f00) {
-               unsigned int c;
-               char flag = TTY_NORMAL;
-
-               c = readw(port->membase + VT8500_RXFIFO) & 0x3ff;
-
-               /* Mask conditions we're ignorning. */
-               c &= ~port->read_status_mask;
-
-               if (c & FER) {
-                       port->icount.frame++;
-                       flag = TTY_FRAME;
-               } else if (c & PER) {
-                       port->icount.parity++;
-                       flag = TTY_PARITY;
-               }
-               port->icount.rx++;
-
-               if (!uart_handle_sysrq_char(port, c))
-                       tty_insert_flip_char(tty, c, flag);
-       }
-
-       tty_flip_buffer_push(tty);
-       tty_kref_put(tty);
-}
-
-static void handle_tx(struct uart_port *port)
-{
-       struct circ_buf *xmit = &port->state->xmit;
-
-       if (port->x_char) {
-               writeb(port->x_char, port->membase + VT8500_TXFIFO);
-               port->icount.tx++;
-               port->x_char = 0;
-       }
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               vt8500_stop_tx(port);
-               return;
-       }
-
-       while ((vt8500_read(port, VT8500_URFIDX) & 0x1f) < 16) {
-               if (uart_circ_empty(xmit))
-                       break;
-
-               writeb(xmit->buf[xmit->tail], port->membase + VT8500_TXFIFO);
-
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (uart_circ_empty(xmit))
-               vt8500_stop_tx(port);
-}
-
-static void vt8500_start_tx(struct uart_port *port)
-{
-       struct vt8500_port *vt8500_port = container_of(port,
-                                                      struct vt8500_port,
-                                                      uart);
-
-       vt8500_port->ier &= ~TX_FIFO_INTS;
-       vt8500_write(port, vt8500_port->ier, VT8500_URIER);
-       handle_tx(port);
-       vt8500_port->ier |= TX_FIFO_INTS;
-       vt8500_write(port, vt8500_port->ier, VT8500_URIER);
-}
-
-static void handle_delta_cts(struct uart_port *port)
-{
-       port->icount.cts++;
-       wake_up_interruptible(&port->state->port.delta_msr_wait);
-}
-
-static irqreturn_t vt8500_irq(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       unsigned long isr;
-
-       spin_lock(&port->lock);
-       isr = vt8500_read(port, VT8500_URISR);
-
-       /* Acknowledge active status bits */
-       vt8500_write(port, isr, VT8500_URISR);
-
-       if (isr & RX_FIFO_INTS)
-               handle_rx(port);
-       if (isr & TX_FIFO_INTS)
-               handle_tx(port);
-       if (isr & TCTS)
-               handle_delta_cts(port);
-
-       spin_unlock(&port->lock);
-
-       return IRQ_HANDLED;
-}
-
-static unsigned int vt8500_tx_empty(struct uart_port *port)
-{
-       return (vt8500_read(port, VT8500_URFIDX) & 0x1f) < 16 ?
-                                               TIOCSER_TEMT : 0;
-}
-
-static unsigned int vt8500_get_mctrl(struct uart_port *port)
-{
-       unsigned int usr;
-
-       usr = vt8500_read(port, VT8500_URUSR);
-       if (usr & (1 << 4))
-               return TIOCM_CTS;
-       else
-               return 0;
-}
-
-static void vt8500_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-}
-
-static void vt8500_break_ctl(struct uart_port *port, int break_ctl)
-{
-       if (break_ctl)
-               vt8500_write(port, vt8500_read(port, VT8500_URLCR) | (1 << 9),
-                            VT8500_URLCR);
-}
-
-static int vt8500_set_baud_rate(struct uart_port *port, unsigned int baud)
-{
-       unsigned long div;
-       unsigned int loops = 1000;
-
-       div = vt8500_read(port, VT8500_URDIV) & ~(0x3ff);
-
-       if (unlikely((baud < 900) || (baud > 921600)))
-               div |= 7;
-       else
-               div |= (921600 / baud) - 1;
-
-       while ((vt8500_read(port, VT8500_URUSR) & (1 << 5)) && --loops)
-               cpu_relax();
-       vt8500_write(port, div, VT8500_URDIV);
-
-       return baud;
-}
-
-static int vt8500_startup(struct uart_port *port)
-{
-       struct vt8500_port *vt8500_port =
-                       container_of(port, struct vt8500_port, uart);
-       int ret;
-
-       snprintf(vt8500_port->name, sizeof(vt8500_port->name),
-                "vt8500_serial%d", port->line);
-
-       ret = request_irq(port->irq, vt8500_irq, IRQF_TRIGGER_HIGH,
-                         vt8500_port->name, port);
-       if (unlikely(ret))
-               return ret;
-
-       vt8500_write(port, 0x03, VT8500_URLCR); /* enable TX & RX */
-
-       return 0;
-}
-
-static void vt8500_shutdown(struct uart_port *port)
-{
-       struct vt8500_port *vt8500_port =
-                       container_of(port, struct vt8500_port, uart);
-
-       vt8500_port->ier = 0;
-
-       /* disable interrupts and FIFOs */
-       vt8500_write(&vt8500_port->uart, 0, VT8500_URIER);
-       vt8500_write(&vt8500_port->uart, 0x880, VT8500_URFCR);
-       free_irq(port->irq, port);
-}
-
-static void vt8500_set_termios(struct uart_port *port,
-                              struct ktermios *termios,
-                              struct ktermios *old)
-{
-       struct vt8500_port *vt8500_port =
-                       container_of(port, struct vt8500_port, uart);
-       unsigned long flags;
-       unsigned int baud, lcr;
-       unsigned int loops = 1000;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /* calculate and set baud rate */
-       baud = uart_get_baud_rate(port, termios, old, 900, 921600);
-       baud = vt8500_set_baud_rate(port, baud);
-       if (tty_termios_baud_rate(termios))
-               tty_termios_encode_baud_rate(termios, baud, baud);
-
-       /* calculate parity */
-       lcr = vt8500_read(&vt8500_port->uart, VT8500_URLCR);
-       lcr &= ~((1 << 5) | (1 << 4));
-       if (termios->c_cflag & PARENB) {
-               lcr |= (1 << 4);
-               termios->c_cflag &= ~CMSPAR;
-               if (termios->c_cflag & PARODD)
-                       lcr |= (1 << 5);
-       }
-
-       /* calculate bits per char */
-       lcr &= ~(1 << 2);
-       switch (termios->c_cflag & CSIZE) {
-       case CS7:
-               break;
-       case CS8:
-       default:
-               lcr |= (1 << 2);
-               termios->c_cflag &= ~CSIZE;
-               termios->c_cflag |= CS8;
-               break;
-       }
-
-       /* calculate stop bits */
-       lcr &= ~(1 << 3);
-       if (termios->c_cflag & CSTOPB)
-               lcr |= (1 << 3);
-
-       /* set parity, bits per char, and stop bit */
-       vt8500_write(&vt8500_port->uart, lcr, VT8500_URLCR);
-
-       /* Configure status bits to ignore based on termio flags. */
-       port->read_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->read_status_mask = FER | PER;
-
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       /* Reset FIFOs */
-       vt8500_write(&vt8500_port->uart, 0x88c, VT8500_URFCR);
-       while ((vt8500_read(&vt8500_port->uart, VT8500_URFCR) & 0xc)
-                                                       && --loops)
-               cpu_relax();
-
-       /* Every possible FIFO-related interrupt */
-       vt8500_port->ier = RX_FIFO_INTS | TX_FIFO_INTS;
-
-       /*
-        * CTS flow control
-        */
-       if (UART_ENABLE_MS(&vt8500_port->uart, termios->c_cflag))
-               vt8500_port->ier |= TCTS;
-
-       vt8500_write(&vt8500_port->uart, 0x881, VT8500_URFCR);
-       vt8500_write(&vt8500_port->uart, vt8500_port->ier, VT8500_URIER);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *vt8500_type(struct uart_port *port)
-{
-       struct vt8500_port *vt8500_port =
-                       container_of(port, struct vt8500_port, uart);
-       return vt8500_port->name;
-}
-
-static void vt8500_release_port(struct uart_port *port)
-{
-}
-
-static int vt8500_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-static void vt8500_config_port(struct uart_port *port, int flags)
-{
-       port->type = PORT_VT8500;
-}
-
-static int vt8500_verify_port(struct uart_port *port,
-                             struct serial_struct *ser)
-{
-       if (unlikely(ser->type != PORT_UNKNOWN && ser->type != PORT_VT8500))
-               return -EINVAL;
-       if (unlikely(port->irq != ser->irq))
-               return -EINVAL;
-       return 0;
-}
-
-static struct vt8500_port *vt8500_uart_ports[4];
-static struct uart_driver vt8500_uart_driver;
-
-#ifdef CONFIG_SERIAL_VT8500_CONSOLE
-
-static inline void wait_for_xmitr(struct uart_port *port)
-{
-       unsigned int status, tmout = 10000;
-
-       /* Wait up to 10ms for the character(s) to be sent. */
-       do {
-               status = vt8500_read(port, VT8500_URFIDX);
-
-               if (--tmout == 0)
-                       break;
-               udelay(1);
-       } while (status & 0x10);
-}
-
-static void vt8500_console_putchar(struct uart_port *port, int c)
-{
-       wait_for_xmitr(port);
-       writeb(c, port->membase + VT8500_TXFIFO);
-}
-
-static void vt8500_console_write(struct console *co, const char *s,
-                             unsigned int count)
-{
-       struct vt8500_port *vt8500_port = vt8500_uart_ports[co->index];
-       unsigned long ier;
-
-       BUG_ON(co->index < 0 || co->index >= vt8500_uart_driver.nr);
-
-       ier = vt8500_read(&vt8500_port->uart, VT8500_URIER);
-       vt8500_write(&vt8500_port->uart, VT8500_URIER, 0);
-
-       uart_console_write(&vt8500_port->uart, s, count,
-                          vt8500_console_putchar);
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and switch back to FIFO
-        */
-       wait_for_xmitr(&vt8500_port->uart);
-       vt8500_write(&vt8500_port->uart, VT8500_URIER, ier);
-}
-
-static int __init vt8500_console_setup(struct console *co, char *options)
-{
-       struct vt8500_port *vt8500_port;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       if (unlikely(co->index >= vt8500_uart_driver.nr || co->index < 0))
-               return -ENXIO;
-
-       vt8500_port = vt8500_uart_ports[co->index];
-
-       if (!vt8500_port)
-               return -ENODEV;
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(&vt8500_port->uart,
-                                co, baud, parity, bits, flow);
-}
-
-static struct console vt8500_console = {
-       .name = "ttyWMT",
-       .write = vt8500_console_write,
-       .device = uart_console_device,
-       .setup = vt8500_console_setup,
-       .flags = CON_PRINTBUFFER,
-       .index = -1,
-       .data = &vt8500_uart_driver,
-};
-
-#define VT8500_CONSOLE (&vt8500_console)
-
-#else
-#define VT8500_CONSOLE NULL
-#endif
-
-static struct uart_ops vt8500_uart_pops = {
-       .tx_empty       = vt8500_tx_empty,
-       .set_mctrl      = vt8500_set_mctrl,
-       .get_mctrl      = vt8500_get_mctrl,
-       .stop_tx        = vt8500_stop_tx,
-       .start_tx       = vt8500_start_tx,
-       .stop_rx        = vt8500_stop_rx,
-       .enable_ms      = vt8500_enable_ms,
-       .break_ctl      = vt8500_break_ctl,
-       .startup        = vt8500_startup,
-       .shutdown       = vt8500_shutdown,
-       .set_termios    = vt8500_set_termios,
-       .type           = vt8500_type,
-       .release_port   = vt8500_release_port,
-       .request_port   = vt8500_request_port,
-       .config_port    = vt8500_config_port,
-       .verify_port    = vt8500_verify_port,
-};
-
-static struct uart_driver vt8500_uart_driver = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "vt8500_serial",
-       .dev_name       = "ttyWMT",
-       .nr             = 6,
-       .cons           = VT8500_CONSOLE,
-};
-
-static int __init vt8500_serial_probe(struct platform_device *pdev)
-{
-       struct vt8500_port *vt8500_port;
-       struct resource *mmres, *irqres;
-       int ret;
-
-       mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!mmres || !irqres)
-               return -ENODEV;
-
-       vt8500_port = kzalloc(sizeof(struct vt8500_port), GFP_KERNEL);
-       if (!vt8500_port)
-               return -ENOMEM;
-
-       vt8500_port->uart.type = PORT_VT8500;
-       vt8500_port->uart.iotype = UPIO_MEM;
-       vt8500_port->uart.mapbase = mmres->start;
-       vt8500_port->uart.irq = irqres->start;
-       vt8500_port->uart.fifosize = 16;
-       vt8500_port->uart.ops = &vt8500_uart_pops;
-       vt8500_port->uart.line = pdev->id;
-       vt8500_port->uart.dev = &pdev->dev;
-       vt8500_port->uart.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
-       vt8500_port->uart.uartclk = 24000000;
-
-       snprintf(vt8500_port->name, sizeof(vt8500_port->name),
-                "VT8500 UART%d", pdev->id);
-
-       vt8500_port->uart.membase = ioremap(mmres->start,
-                                           mmres->end - mmres->start + 1);
-       if (!vt8500_port->uart.membase) {
-               ret = -ENOMEM;
-               goto err;
-       }
-
-       vt8500_uart_ports[pdev->id] = vt8500_port;
-
-       uart_add_one_port(&vt8500_uart_driver, &vt8500_port->uart);
-
-       platform_set_drvdata(pdev, vt8500_port);
-
-       return 0;
-
-err:
-       kfree(vt8500_port);
-       return ret;
-}
-
-static int __devexit vt8500_serial_remove(struct platform_device *pdev)
-{
-       struct vt8500_port *vt8500_port = platform_get_drvdata(pdev);
-
-       platform_set_drvdata(pdev, NULL);
-       uart_remove_one_port(&vt8500_uart_driver, &vt8500_port->uart);
-       kfree(vt8500_port);
-
-       return 0;
-}
-
-static struct platform_driver vt8500_platform_driver = {
-       .probe  = vt8500_serial_probe,
-       .remove = vt8500_serial_remove,
-       .driver = {
-               .name = "vt8500_serial",
-               .owner = THIS_MODULE,
-       },
-};
-
-static int __init vt8500_serial_init(void)
-{
-       int ret;
-
-       ret = uart_register_driver(&vt8500_uart_driver);
-       if (unlikely(ret))
-               return ret;
-
-       ret = platform_driver_register(&vt8500_platform_driver);
-
-       if (unlikely(ret))
-               uart_unregister_driver(&vt8500_uart_driver);
-
-       return ret;
-}
-
-static void __exit vt8500_serial_exit(void)
-{
-#ifdef CONFIG_SERIAL_VT8500_CONSOLE
-       unregister_console(&vt8500_console);
-#endif
-       platform_driver_unregister(&vt8500_platform_driver);
-       uart_unregister_driver(&vt8500_uart_driver);
-}
-
-module_init(vt8500_serial_init);
-module_exit(vt8500_serial_exit);
-
-MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>");
-MODULE_DESCRIPTION("Driver for vt8500 serial device");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/zs.c b/drivers/serial/zs.c
deleted file mode 100644 (file)
index 1a7fd3e..0000000
+++ /dev/null
@@ -1,1304 +0,0 @@
-/*
- * zs.c: Serial port driver for IOASIC DECstations.
- *
- * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
- * Derived from drivers/macintosh/macserial.c by Harald Koerfgen.
- *
- * DECstation changes
- * Copyright (C) 1998-2000 Harald Koerfgen
- * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007  Maciej W. Rozycki
- *
- * For the rest of the code the original Copyright applies:
- * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- *
- *
- * Note: for IOASIC systems the wiring is as follows:
- *
- * mouse/keyboard:
- * DIN-7 MJ-4  signal        SCC
- * 2     1     TxD       <-  A.TxD
- * 3     4     RxD       ->  A.RxD
- *
- * EIA-232/EIA-423:
- * DB-25 MMJ-6 signal        SCC
- * 2     2     TxD       <-  B.TxD
- * 3     5     RxD       ->  B.RxD
- * 4           RTS       <- ~A.RTS
- * 5           CTS       -> ~B.CTS
- * 6     6     DSR       -> ~A.SYNC
- * 8           CD        -> ~B.DCD
- * 12          DSRS(DCE) -> ~A.CTS  (*)
- * 15          TxC       ->  B.TxC
- * 17          RxC       ->  B.RxC
- * 20    1     DTR       <- ~A.DTR
- * 22          RI        -> ~A.DCD
- * 23          DSRS(DTE) <- ~B.RTS
- *
- * (*) EIA-232 defines the signal at this pin to be SCD, while DSRS(DCE)
- *     is shared with DSRS(DTE) at pin 23.
- *
- * As you can immediately notice the wiring of the RTS, DTR and DSR signals
- * is a bit odd.  This makes the handling of port B unnecessarily
- * complicated and prevents the use of some automatic modes of operation.
- */
-
-#if defined(CONFIG_SERIAL_ZS_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/bug.h>
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
-#include <linux/irqflags.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <linux/spinlock.h>
-#include <linux/sysrq.h>
-#include <linux/tty.h>
-#include <linux/types.h>
-
-#include <asm/atomic.h>
-#include <asm/system.h>
-
-#include <asm/dec/interrupts.h>
-#include <asm/dec/ioasic_addrs.h>
-#include <asm/dec/system.h>
-
-#include "zs.h"
-
-
-MODULE_AUTHOR("Maciej W. Rozycki <macro@linux-mips.org>");
-MODULE_DESCRIPTION("DECstation Z85C30 serial driver");
-MODULE_LICENSE("GPL");
-
-
-static char zs_name[] __initdata = "DECstation Z85C30 serial driver version ";
-static char zs_version[] __initdata = "0.10";
-
-/*
- * It would be nice to dynamically allocate everything that
- * depends on ZS_NUM_SCCS, so we could support any number of
- * Z85C30s, but for now...
- */
-#define ZS_NUM_SCCS    2               /* Max # of ZS chips supported.  */
-#define ZS_NUM_CHAN    2               /* 2 channels per chip.  */
-#define ZS_CHAN_A      0               /* Index of the channel A.  */
-#define ZS_CHAN_B      1               /* Index of the channel B.  */
-#define ZS_CHAN_IO_SIZE 8              /* IOMEM space size.  */
-#define ZS_CHAN_IO_STRIDE 4            /* Register alignment.  */
-#define ZS_CHAN_IO_OFFSET 1            /* The SCC resides on the high byte
-                                          of the 16-bit IOBUS.  */
-#define ZS_CLOCK        7372800        /* Z85C30 PCLK input clock rate.  */
-
-#define to_zport(uport) container_of(uport, struct zs_port, port)
-
-struct zs_parms {
-       resource_size_t scc[ZS_NUM_SCCS];
-       int irq[ZS_NUM_SCCS];
-};
-
-static struct zs_scc zs_sccs[ZS_NUM_SCCS];
-
-static u8 zs_init_regs[ZS_NUM_REGS] __initdata = {
-       0,                              /* write 0 */
-       PAR_SPEC,                       /* write 1 */
-       0,                              /* write 2 */
-       0,                              /* write 3 */
-       X16CLK | SB1,                   /* write 4 */
-       0,                              /* write 5 */
-       0, 0, 0,                        /* write 6, 7, 8 */
-       MIE | DLC | NV,                 /* write 9 */
-       NRZ,                            /* write 10 */
-       TCBR | RCBR,                    /* write 11 */
-       0, 0,                           /* BRG time constant, write 12 + 13 */
-       BRSRC | BRENABL,                /* write 14 */
-       0,                              /* write 15 */
-};
-
-/*
- * Debugging.
- */
-#undef ZS_DEBUG_REGS
-
-
-/*
- * Reading and writing Z85C30 registers.
- */
-static void recovery_delay(void)
-{
-       udelay(2);
-}
-
-static u8 read_zsreg(struct zs_port *zport, int reg)
-{
-       void __iomem *control = zport->port.membase + ZS_CHAN_IO_OFFSET;
-       u8 retval;
-
-       if (reg != 0) {
-               writeb(reg & 0xf, control);
-               fast_iob();
-               recovery_delay();
-       }
-       retval = readb(control);
-       recovery_delay();
-       return retval;
-}
-
-static void write_zsreg(struct zs_port *zport, int reg, u8 value)
-{
-       void __iomem *control = zport->port.membase + ZS_CHAN_IO_OFFSET;
-
-       if (reg != 0) {
-               writeb(reg & 0xf, control);
-               fast_iob(); recovery_delay();
-       }
-       writeb(value, control);
-       fast_iob();
-       recovery_delay();
-       return;
-}
-
-static u8 read_zsdata(struct zs_port *zport)
-{
-       void __iomem *data = zport->port.membase +
-                            ZS_CHAN_IO_STRIDE + ZS_CHAN_IO_OFFSET;
-       u8 retval;
-
-       retval = readb(data);
-       recovery_delay();
-       return retval;
-}
-
-static void write_zsdata(struct zs_port *zport, u8 value)
-{
-       void __iomem *data = zport->port.membase +
-                            ZS_CHAN_IO_STRIDE + ZS_CHAN_IO_OFFSET;
-
-       writeb(value, data);
-       fast_iob();
-       recovery_delay();
-       return;
-}
-
-#ifdef ZS_DEBUG_REGS
-void zs_dump(void)
-{
-       struct zs_port *zport;
-       int i, j;
-
-       for (i = 0; i < ZS_NUM_SCCS * ZS_NUM_CHAN; i++) {
-               zport = &zs_sccs[i / ZS_NUM_CHAN].zport[i % ZS_NUM_CHAN];
-
-               if (!zport->scc)
-                       continue;
-
-               for (j = 0; j < 16; j++)
-                       printk("W%-2d = 0x%02x\t", j, zport->regs[j]);
-               printk("\n");
-               for (j = 0; j < 16; j++)
-                       printk("R%-2d = 0x%02x\t", j, read_zsreg(zport, j));
-               printk("\n\n");
-       }
-}
-#endif
-
-
-static void zs_spin_lock_cond_irq(spinlock_t *lock, int irq)
-{
-       if (irq)
-               spin_lock_irq(lock);
-       else
-               spin_lock(lock);
-}
-
-static void zs_spin_unlock_cond_irq(spinlock_t *lock, int irq)
-{
-       if (irq)
-               spin_unlock_irq(lock);
-       else
-               spin_unlock(lock);
-}
-
-static int zs_receive_drain(struct zs_port *zport)
-{
-       int loops = 10000;
-
-       while ((read_zsreg(zport, R0) & Rx_CH_AV) && --loops)
-               read_zsdata(zport);
-       return loops;
-}
-
-static int zs_transmit_drain(struct zs_port *zport, int irq)
-{
-       struct zs_scc *scc = zport->scc;
-       int loops = 10000;
-
-       while (!(read_zsreg(zport, R0) & Tx_BUF_EMP) && --loops) {
-               zs_spin_unlock_cond_irq(&scc->zlock, irq);
-               udelay(2);
-               zs_spin_lock_cond_irq(&scc->zlock, irq);
-       }
-       return loops;
-}
-
-static int zs_line_drain(struct zs_port *zport, int irq)
-{
-       struct zs_scc *scc = zport->scc;
-       int loops = 10000;
-
-       while (!(read_zsreg(zport, R1) & ALL_SNT) && --loops) {
-               zs_spin_unlock_cond_irq(&scc->zlock, irq);
-               udelay(2);
-               zs_spin_lock_cond_irq(&scc->zlock, irq);
-       }
-       return loops;
-}
-
-
-static void load_zsregs(struct zs_port *zport, u8 *regs, int irq)
-{
-       /* Let the current transmission finish.  */
-       zs_line_drain(zport, irq);
-       /* Load 'em up.  */
-       write_zsreg(zport, R3, regs[3] & ~RxENABLE);
-       write_zsreg(zport, R5, regs[5] & ~TxENAB);
-       write_zsreg(zport, R4, regs[4]);
-       write_zsreg(zport, R9, regs[9]);
-       write_zsreg(zport, R1, regs[1]);
-       write_zsreg(zport, R2, regs[2]);
-       write_zsreg(zport, R10, regs[10]);
-       write_zsreg(zport, R14, regs[14] & ~BRENABL);
-       write_zsreg(zport, R11, regs[11]);
-       write_zsreg(zport, R12, regs[12]);
-       write_zsreg(zport, R13, regs[13]);
-       write_zsreg(zport, R14, regs[14]);
-       write_zsreg(zport, R15, regs[15]);
-       if (regs[3] & RxENABLE)
-               write_zsreg(zport, R3, regs[3]);
-       if (regs[5] & TxENAB)
-               write_zsreg(zport, R5, regs[5]);
-       return;
-}
-
-
-/*
- * Status handling routines.
- */
-
-/*
- * zs_tx_empty() -- get the transmitter empty status
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- *         is emptied.  On bus types like RS485, the transmitter must
- *         release the bus after transmitting.  This must be done when
- *         the transmit shift register is empty, not be done when the
- *         transmit holding register is empty.  This functionality
- *         allows an RS485 driver to be written in user space.
- */
-static unsigned int zs_tx_empty(struct uart_port *uport)
-{
-       struct zs_port *zport = to_zport(uport);
-       struct zs_scc *scc = zport->scc;
-       unsigned long flags;
-       u8 status;
-
-       spin_lock_irqsave(&scc->zlock, flags);
-       status = read_zsreg(zport, R1);
-       spin_unlock_irqrestore(&scc->zlock, flags);
-
-       return status & ALL_SNT ? TIOCSER_TEMT : 0;
-}
-
-static unsigned int zs_raw_get_ab_mctrl(struct zs_port *zport_a,
-                                       struct zs_port *zport_b)
-{
-       u8 status_a, status_b;
-       unsigned int mctrl;
-
-       status_a = read_zsreg(zport_a, R0);
-       status_b = read_zsreg(zport_b, R0);
-
-       mctrl = ((status_b & CTS) ? TIOCM_CTS : 0) |
-               ((status_b & DCD) ? TIOCM_CAR : 0) |
-               ((status_a & DCD) ? TIOCM_RNG : 0) |
-               ((status_a & SYNC_HUNT) ? TIOCM_DSR : 0);
-
-       return mctrl;
-}
-
-static unsigned int zs_raw_get_mctrl(struct zs_port *zport)
-{
-       struct zs_port *zport_a = &zport->scc->zport[ZS_CHAN_A];
-
-       return zport != zport_a ? zs_raw_get_ab_mctrl(zport_a, zport) : 0;
-}
-
-static unsigned int zs_raw_xor_mctrl(struct zs_port *zport)
-{
-       struct zs_port *zport_a = &zport->scc->zport[ZS_CHAN_A];
-       unsigned int mmask, mctrl, delta;
-       u8 mask_a, mask_b;
-
-       if (zport == zport_a)
-               return 0;
-
-       mask_a = zport_a->regs[15];
-       mask_b = zport->regs[15];
-
-       mmask = ((mask_b & CTSIE) ? TIOCM_CTS : 0) |
-               ((mask_b & DCDIE) ? TIOCM_CAR : 0) |
-               ((mask_a & DCDIE) ? TIOCM_RNG : 0) |
-               ((mask_a & SYNCIE) ? TIOCM_DSR : 0);
-
-       mctrl = zport->mctrl;
-       if (mmask) {
-               mctrl &= ~mmask;
-               mctrl |= zs_raw_get_ab_mctrl(zport_a, zport) & mmask;
-       }
-
-       delta = mctrl ^ zport->mctrl;
-       if (delta)
-               zport->mctrl = mctrl;
-
-       return delta;
-}
-
-static unsigned int zs_get_mctrl(struct uart_port *uport)
-{
-       struct zs_port *zport = to_zport(uport);
-       struct zs_scc *scc = zport->scc;
-       unsigned int mctrl;
-
-       spin_lock(&scc->zlock);
-       mctrl = zs_raw_get_mctrl(zport);
-       spin_unlock(&scc->zlock);
-
-       return mctrl;
-}
-
-static void zs_set_mctrl(struct uart_port *uport, unsigned int mctrl)
-{
-       struct zs_port *zport = to_zport(uport);
-       struct zs_scc *scc = zport->scc;
-       struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
-       u8 oldloop, newloop;
-
-       spin_lock(&scc->zlock);
-       if (zport != zport_a) {
-               if (mctrl & TIOCM_DTR)
-                       zport_a->regs[5] |= DTR;
-               else
-                       zport_a->regs[5] &= ~DTR;
-               if (mctrl & TIOCM_RTS)
-                       zport_a->regs[5] |= RTS;
-               else
-                       zport_a->regs[5] &= ~RTS;
-               write_zsreg(zport_a, R5, zport_a->regs[5]);
-       }
-
-       /* Rarely modified, so don't poke at hardware unless necessary. */
-       oldloop = zport->regs[14];
-       newloop = oldloop;
-       if (mctrl & TIOCM_LOOP)
-               newloop |= LOOPBAK;
-       else
-               newloop &= ~LOOPBAK;
-       if (newloop != oldloop) {
-               zport->regs[14] = newloop;
-               write_zsreg(zport, R14, zport->regs[14]);
-       }
-       spin_unlock(&scc->zlock);
-}
-
-static void zs_raw_stop_tx(struct zs_port *zport)
-{
-       write_zsreg(zport, R0, RES_Tx_P);
-       zport->tx_stopped = 1;
-}
-
-static void zs_stop_tx(struct uart_port *uport)
-{
-       struct zs_port *zport = to_zport(uport);
-       struct zs_scc *scc = zport->scc;
-
-       spin_lock(&scc->zlock);
-       zs_raw_stop_tx(zport);
-       spin_unlock(&scc->zlock);
-}
-
-static void zs_raw_transmit_chars(struct zs_port *);
-
-static void zs_start_tx(struct uart_port *uport)
-{
-       struct zs_port *zport = to_zport(uport);
-       struct zs_scc *scc = zport->scc;
-
-       spin_lock(&scc->zlock);
-       if (zport->tx_stopped) {
-               zs_transmit_drain(zport, 0);
-               zport->tx_stopped = 0;
-               zs_raw_transmit_chars(zport);
-       }
-       spin_unlock(&scc->zlock);
-}
-
-static void zs_stop_rx(struct uart_port *uport)
-{
-       struct zs_port *zport = to_zport(uport);
-       struct zs_scc *scc = zport->scc;
-       struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
-
-       spin_lock(&scc->zlock);
-       zport->regs[15] &= ~BRKIE;
-       zport->regs[1] &= ~(RxINT_MASK | TxINT_ENAB);
-       zport->regs[1] |= RxINT_DISAB;
-
-       if (zport != zport_a) {
-               /* A-side DCD tracks RI and SYNC tracks DSR.  */
-               zport_a->regs[15] &= ~(DCDIE | SYNCIE);
-               write_zsreg(zport_a, R15, zport_a->regs[15]);
-               if (!(zport_a->regs[15] & BRKIE)) {
-                       zport_a->regs[1] &= ~EXT_INT_ENAB;
-                       write_zsreg(zport_a, R1, zport_a->regs[1]);
-               }
-
-               /* This-side DCD tracks DCD and CTS tracks CTS.  */
-               zport->regs[15] &= ~(DCDIE | CTSIE);
-               zport->regs[1] &= ~EXT_INT_ENAB;
-       } else {
-               /* DCD tracks RI and SYNC tracks DSR for the B side.  */
-               if (!(zport->regs[15] & (DCDIE | SYNCIE)))
-                       zport->regs[1] &= ~EXT_INT_ENAB;
-       }
-
-       write_zsreg(zport, R15, zport->regs[15]);
-       write_zsreg(zport, R1, zport->regs[1]);
-       spin_unlock(&scc->zlock);
-}
-
-static void zs_enable_ms(struct uart_port *uport)
-{
-       struct zs_port *zport = to_zport(uport);
-       struct zs_scc *scc = zport->scc;
-       struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
-
-       if (zport == zport_a)
-               return;
-
-       spin_lock(&scc->zlock);
-
-       /* Clear Ext interrupts if not being handled already.  */
-       if (!(zport_a->regs[1] & EXT_INT_ENAB))
-               write_zsreg(zport_a, R0, RES_EXT_INT);
-
-       /* A-side DCD tracks RI and SYNC tracks DSR.  */
-       zport_a->regs[1] |= EXT_INT_ENAB;
-       zport_a->regs[15] |= DCDIE | SYNCIE;
-
-       /* This-side DCD tracks DCD and CTS tracks CTS.  */
-       zport->regs[15] |= DCDIE | CTSIE;
-
-       zs_raw_xor_mctrl(zport);
-
-       write_zsreg(zport_a, R1, zport_a->regs[1]);
-       write_zsreg(zport_a, R15, zport_a->regs[15]);
-       write_zsreg(zport, R15, zport->regs[15]);
-       spin_unlock(&scc->zlock);
-}
-
-static void zs_break_ctl(struct uart_port *uport, int break_state)
-{
-       struct zs_port *zport = to_zport(uport);
-       struct zs_scc *scc = zport->scc;
-       unsigned long flags;
-
-       spin_lock_irqsave(&scc->zlock, flags);
-       if (break_state == -1)
-               zport->regs[5] |= SND_BRK;
-       else
-               zport->regs[5] &= ~SND_BRK;
-       write_zsreg(zport, R5, zport->regs[5]);
-       spin_unlock_irqrestore(&scc->zlock, flags);
-}
-
-
-/*
- * Interrupt handling routines.
- */
-#define Rx_BRK 0x0100                  /* BREAK event software flag.  */
-#define Rx_SYS 0x0200                  /* SysRq event software flag.  */
-
-static void zs_receive_chars(struct zs_port *zport)
-{
-       struct uart_port *uport = &zport->port;
-       struct zs_scc *scc = zport->scc;
-       struct uart_icount *icount;
-       unsigned int avail, status, ch, flag;
-       int count;
-
-       for (count = 16; count; count--) {
-               spin_lock(&scc->zlock);
-               avail = read_zsreg(zport, R0) & Rx_CH_AV;
-               spin_unlock(&scc->zlock);
-               if (!avail)
-                       break;
-
-               spin_lock(&scc->zlock);
-               status = read_zsreg(zport, R1) & (Rx_OVR | FRM_ERR | PAR_ERR);
-               ch = read_zsdata(zport);
-               spin_unlock(&scc->zlock);
-
-               flag = TTY_NORMAL;
-
-               icount = &uport->icount;
-               icount->rx++;
-
-               /* Handle the null char got when BREAK is removed.  */
-               if (!ch)
-                       status |= zport->tty_break;
-               if (unlikely(status &
-                            (Rx_OVR | FRM_ERR | PAR_ERR | Rx_SYS | Rx_BRK))) {
-                       zport->tty_break = 0;
-
-                       /* Reset the error indication.  */
-                       if (status & (Rx_OVR | FRM_ERR | PAR_ERR)) {
-                               spin_lock(&scc->zlock);
-                               write_zsreg(zport, R0, ERR_RES);
-                               spin_unlock(&scc->zlock);
-                       }
-
-                       if (status & (Rx_SYS | Rx_BRK)) {
-                               icount->brk++;
-                               /* SysRq discards the null char.  */
-                               if (status & Rx_SYS)
-                                       continue;
-                       } else if (status & FRM_ERR)
-                               icount->frame++;
-                       else if (status & PAR_ERR)
-                               icount->parity++;
-                       if (status & Rx_OVR)
-                               icount->overrun++;
-
-                       status &= uport->read_status_mask;
-                       if (status & Rx_BRK)
-                               flag = TTY_BREAK;
-                       else if (status & FRM_ERR)
-                               flag = TTY_FRAME;
-                       else if (status & PAR_ERR)
-                               flag = TTY_PARITY;
-               }
-
-               if (uart_handle_sysrq_char(uport, ch))
-                       continue;
-
-               uart_insert_char(uport, status, Rx_OVR, ch, flag);
-       }
-
-       tty_flip_buffer_push(uport->state->port.tty);
-}
-
-static void zs_raw_transmit_chars(struct zs_port *zport)
-{
-       struct circ_buf *xmit = &zport->port.state->xmit;
-
-       /* XON/XOFF chars.  */
-       if (zport->port.x_char) {
-               write_zsdata(zport, zport->port.x_char);
-               zport->port.icount.tx++;
-               zport->port.x_char = 0;
-               return;
-       }
-
-       /* If nothing to do or stopped or hardware stopped.  */
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&zport->port)) {
-               zs_raw_stop_tx(zport);
-               return;
-       }
-
-       /* Send char.  */
-       write_zsdata(zport, xmit->buf[xmit->tail]);
-       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-       zport->port.icount.tx++;
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&zport->port);
-
-       /* Are we are done?  */
-       if (uart_circ_empty(xmit))
-               zs_raw_stop_tx(zport);
-}
-
-static void zs_transmit_chars(struct zs_port *zport)
-{
-       struct zs_scc *scc = zport->scc;
-
-       spin_lock(&scc->zlock);
-       zs_raw_transmit_chars(zport);
-       spin_unlock(&scc->zlock);
-}
-
-static void zs_status_handle(struct zs_port *zport, struct zs_port *zport_a)
-{
-       struct uart_port *uport = &zport->port;
-       struct zs_scc *scc = zport->scc;
-       unsigned int delta;
-       u8 status, brk;
-
-       spin_lock(&scc->zlock);
-
-       /* Get status from Read Register 0.  */
-       status = read_zsreg(zport, R0);
-
-       if (zport->regs[15] & BRKIE) {
-               brk = status & BRK_ABRT;
-               if (brk && !zport->brk) {
-                       spin_unlock(&scc->zlock);
-                       if (uart_handle_break(uport))
-                               zport->tty_break = Rx_SYS;
-                       else
-                               zport->tty_break = Rx_BRK;
-                       spin_lock(&scc->zlock);
-               }
-               zport->brk = brk;
-       }
-
-       if (zport != zport_a) {
-               delta = zs_raw_xor_mctrl(zport);
-               spin_unlock(&scc->zlock);
-
-               if (delta & TIOCM_CTS)
-                       uart_handle_cts_change(uport,
-                                              zport->mctrl & TIOCM_CTS);
-               if (delta & TIOCM_CAR)
-                       uart_handle_dcd_change(uport,
-                                              zport->mctrl & TIOCM_CAR);
-               if (delta & TIOCM_RNG)
-                       uport->icount.dsr++;
-               if (delta & TIOCM_DSR)
-                       uport->icount.rng++;
-
-               if (delta)
-                       wake_up_interruptible(&uport->state->port.delta_msr_wait);
-
-               spin_lock(&scc->zlock);
-       }
-
-       /* Clear the status condition...  */
-       write_zsreg(zport, R0, RES_EXT_INT);
-
-       spin_unlock(&scc->zlock);
-}
-
-/*
- * This is the Z85C30 driver's generic interrupt routine.
- */
-static irqreturn_t zs_interrupt(int irq, void *dev_id)
-{
-       struct zs_scc *scc = dev_id;
-       struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
-       struct zs_port *zport_b = &scc->zport[ZS_CHAN_B];
-       irqreturn_t status = IRQ_NONE;
-       u8 zs_intreg;
-       int count;
-
-       /*
-        * NOTE: The read register 3, which holds the irq status,
-        *       does so for both channels on each chip.  Although
-        *       the status value itself must be read from the A
-        *       channel and is only valid when read from channel A.
-        *       Yes... broken hardware...
-        */
-       for (count = 16; count; count--) {
-               spin_lock(&scc->zlock);
-               zs_intreg = read_zsreg(zport_a, R3);
-               spin_unlock(&scc->zlock);
-               if (!zs_intreg)
-                       break;
-
-               /*
-                * We do not like losing characters, so we prioritise
-                * interrupt sources a little bit differently than
-                * the SCC would, was it allowed to.
-                */
-               if (zs_intreg & CHBRxIP)
-                       zs_receive_chars(zport_b);
-               if (zs_intreg & CHARxIP)
-                       zs_receive_chars(zport_a);
-               if (zs_intreg & CHBEXT)
-                       zs_status_handle(zport_b, zport_a);
-               if (zs_intreg & CHAEXT)
-                       zs_status_handle(zport_a, zport_a);
-               if (zs_intreg & CHBTxIP)
-                       zs_transmit_chars(zport_b);
-               if (zs_intreg & CHATxIP)
-                       zs_transmit_chars(zport_a);
-
-               status = IRQ_HANDLED;
-       }
-
-       return status;
-}
-
-
-/*
- * Finally, routines used to initialize the serial port.
- */
-static int zs_startup(struct uart_port *uport)
-{
-       struct zs_port *zport = to_zport(uport);
-       struct zs_scc *scc = zport->scc;
-       unsigned long flags;
-       int irq_guard;
-       int ret;
-
-       irq_guard = atomic_add_return(1, &scc->irq_guard);
-       if (irq_guard == 1) {
-               ret = request_irq(zport->port.irq, zs_interrupt,
-                                 IRQF_SHARED, "scc", scc);
-               if (ret) {
-                       atomic_add(-1, &scc->irq_guard);
-                       printk(KERN_ERR "zs: can't get irq %d\n",
-                              zport->port.irq);
-                       return ret;
-               }
-       }
-
-       spin_lock_irqsave(&scc->zlock, flags);
-
-       /* Clear the receive FIFO.  */
-       zs_receive_drain(zport);
-
-       /* Clear the interrupt registers.  */
-       write_zsreg(zport, R0, ERR_RES);
-       write_zsreg(zport, R0, RES_Tx_P);
-       /* But Ext only if not being handled already.  */
-       if (!(zport->regs[1] & EXT_INT_ENAB))
-               write_zsreg(zport, R0, RES_EXT_INT);
-
-       /* Finally, enable sequencing and interrupts.  */
-       zport->regs[1] &= ~RxINT_MASK;
-       zport->regs[1] |= RxINT_ALL | TxINT_ENAB | EXT_INT_ENAB;
-       zport->regs[3] |= RxENABLE;
-       zport->regs[15] |= BRKIE;
-       write_zsreg(zport, R1, zport->regs[1]);
-       write_zsreg(zport, R3, zport->regs[3]);
-       write_zsreg(zport, R5, zport->regs[5]);
-       write_zsreg(zport, R15, zport->regs[15]);
-
-       /* Record the current state of RR0.  */
-       zport->mctrl = zs_raw_get_mctrl(zport);
-       zport->brk = read_zsreg(zport, R0) & BRK_ABRT;
-
-       zport->tx_stopped = 1;
-
-       spin_unlock_irqrestore(&scc->zlock, flags);
-
-       return 0;
-}
-
-static void zs_shutdown(struct uart_port *uport)
-{
-       struct zs_port *zport = to_zport(uport);
-       struct zs_scc *scc = zport->scc;
-       unsigned long flags;
-       int irq_guard;
-
-       spin_lock_irqsave(&scc->zlock, flags);
-
-       zport->regs[3] &= ~RxENABLE;
-       write_zsreg(zport, R5, zport->regs[5]);
-       write_zsreg(zport, R3, zport->regs[3]);
-
-       spin_unlock_irqrestore(&scc->zlock, flags);
-
-       irq_guard = atomic_add_return(-1, &scc->irq_guard);
-       if (!irq_guard)
-               free_irq(zport->port.irq, scc);
-}
-
-
-static void zs_reset(struct zs_port *zport)
-{
-       struct zs_scc *scc = zport->scc;
-       int irq;
-       unsigned long flags;
-
-       spin_lock_irqsave(&scc->zlock, flags);
-       irq = !irqs_disabled_flags(flags);
-       if (!scc->initialised) {
-               /* Reset the pointer first, just in case...  */
-               read_zsreg(zport, R0);
-               /* And let the current transmission finish.  */
-               zs_line_drain(zport, irq);
-               write_zsreg(zport, R9, FHWRES);
-               udelay(10);
-               write_zsreg(zport, R9, 0);
-               scc->initialised = 1;
-       }
-       load_zsregs(zport, zport->regs, irq);
-       spin_unlock_irqrestore(&scc->zlock, flags);
-}
-
-static void zs_set_termios(struct uart_port *uport, struct ktermios *termios,
-                          struct ktermios *old_termios)
-{
-       struct zs_port *zport = to_zport(uport);
-       struct zs_scc *scc = zport->scc;
-       struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
-       int irq;
-       unsigned int baud, brg;
-       unsigned long flags;
-
-       spin_lock_irqsave(&scc->zlock, flags);
-       irq = !irqs_disabled_flags(flags);
-
-       /* Byte size.  */
-       zport->regs[3] &= ~RxNBITS_MASK;
-       zport->regs[5] &= ~TxNBITS_MASK;
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               zport->regs[3] |= Rx5;
-               zport->regs[5] |= Tx5;
-               break;
-       case CS6:
-               zport->regs[3] |= Rx6;
-               zport->regs[5] |= Tx6;
-               break;
-       case CS7:
-               zport->regs[3] |= Rx7;
-               zport->regs[5] |= Tx7;
-               break;
-       case CS8:
-       default:
-               zport->regs[3] |= Rx8;
-               zport->regs[5] |= Tx8;
-               break;
-       }
-
-       /* Parity and stop bits.  */
-       zport->regs[4] &= ~(XCLK_MASK | SB_MASK | PAR_ENA | PAR_EVEN);
-       if (termios->c_cflag & CSTOPB)
-               zport->regs[4] |= SB2;
-       else
-               zport->regs[4] |= SB1;
-       if (termios->c_cflag & PARENB)
-               zport->regs[4] |= PAR_ENA;
-       if (!(termios->c_cflag & PARODD))
-               zport->regs[4] |= PAR_EVEN;
-       switch (zport->clk_mode) {
-       case 64:
-               zport->regs[4] |= X64CLK;
-               break;
-       case 32:
-               zport->regs[4] |= X32CLK;
-               break;
-       case 16:
-               zport->regs[4] |= X16CLK;
-               break;
-       case 1:
-               zport->regs[4] |= X1CLK;
-               break;
-       default:
-               BUG();
-       }
-
-       baud = uart_get_baud_rate(uport, termios, old_termios, 0,
-                                 uport->uartclk / zport->clk_mode / 4);
-
-       brg = ZS_BPS_TO_BRG(baud, uport->uartclk / zport->clk_mode);
-       zport->regs[12] = brg & 0xff;
-       zport->regs[13] = (brg >> 8) & 0xff;
-
-       uart_update_timeout(uport, termios->c_cflag, baud);
-
-       uport->read_status_mask = Rx_OVR;
-       if (termios->c_iflag & INPCK)
-               uport->read_status_mask |= FRM_ERR | PAR_ERR;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               uport->read_status_mask |= Rx_BRK;
-
-       uport->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               uport->ignore_status_mask |= FRM_ERR | PAR_ERR;
-       if (termios->c_iflag & IGNBRK) {
-               uport->ignore_status_mask |= Rx_BRK;
-               if (termios->c_iflag & IGNPAR)
-                       uport->ignore_status_mask |= Rx_OVR;
-       }
-
-       if (termios->c_cflag & CREAD)
-               zport->regs[3] |= RxENABLE;
-       else
-               zport->regs[3] &= ~RxENABLE;
-
-       if (zport != zport_a) {
-               if (!(termios->c_cflag & CLOCAL)) {
-                       zport->regs[15] |= DCDIE;
-               } else
-                       zport->regs[15] &= ~DCDIE;
-               if (termios->c_cflag & CRTSCTS) {
-                       zport->regs[15] |= CTSIE;
-               } else
-                       zport->regs[15] &= ~CTSIE;
-               zs_raw_xor_mctrl(zport);
-       }
-
-       /* Load up the new values.  */
-       load_zsregs(zport, zport->regs, irq);
-
-       spin_unlock_irqrestore(&scc->zlock, flags);
-}
-
-/*
- * Hack alert!
- * Required solely so that the initial PROM-based console
- * works undisturbed in parallel with this one.
- */
-static void zs_pm(struct uart_port *uport, unsigned int state,
-                 unsigned int oldstate)
-{
-       struct zs_port *zport = to_zport(uport);
-
-       if (state < 3)
-               zport->regs[5] |= TxENAB;
-       else
-               zport->regs[5] &= ~TxENAB;
-       write_zsreg(zport, R5, zport->regs[5]);
-}
-
-
-static const char *zs_type(struct uart_port *uport)
-{
-       return "Z85C30 SCC";
-}
-
-static void zs_release_port(struct uart_port *uport)
-{
-       iounmap(uport->membase);
-       uport->membase = 0;
-       release_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE);
-}
-
-static int zs_map_port(struct uart_port *uport)
-{
-       if (!uport->membase)
-               uport->membase = ioremap_nocache(uport->mapbase,
-                                                ZS_CHAN_IO_SIZE);
-       if (!uport->membase) {
-               printk(KERN_ERR "zs: Cannot map MMIO\n");
-               return -ENOMEM;
-       }
-       return 0;
-}
-
-static int zs_request_port(struct uart_port *uport)
-{
-       int ret;
-
-       if (!request_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE, "scc")) {
-               printk(KERN_ERR "zs: Unable to reserve MMIO resource\n");
-               return -EBUSY;
-       }
-       ret = zs_map_port(uport);
-       if (ret) {
-               release_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE);
-               return ret;
-       }
-       return 0;
-}
-
-static void zs_config_port(struct uart_port *uport, int flags)
-{
-       struct zs_port *zport = to_zport(uport);
-
-       if (flags & UART_CONFIG_TYPE) {
-               if (zs_request_port(uport))
-                       return;
-
-               uport->type = PORT_ZS;
-
-               zs_reset(zport);
-       }
-}
-
-static int zs_verify_port(struct uart_port *uport, struct serial_struct *ser)
-{
-       struct zs_port *zport = to_zport(uport);
-       int ret = 0;
-
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_ZS)
-               ret = -EINVAL;
-       if (ser->irq != uport->irq)
-               ret = -EINVAL;
-       if (ser->baud_base != uport->uartclk / zport->clk_mode / 4)
-               ret = -EINVAL;
-       return ret;
-}
-
-
-static struct uart_ops zs_ops = {
-       .tx_empty       = zs_tx_empty,
-       .set_mctrl      = zs_set_mctrl,
-       .get_mctrl      = zs_get_mctrl,
-       .stop_tx        = zs_stop_tx,
-       .start_tx       = zs_start_tx,
-       .stop_rx        = zs_stop_rx,
-       .enable_ms      = zs_enable_ms,
-       .break_ctl      = zs_break_ctl,
-       .startup        = zs_startup,
-       .shutdown       = zs_shutdown,
-       .set_termios    = zs_set_termios,
-       .pm             = zs_pm,
-       .type           = zs_type,
-       .release_port   = zs_release_port,
-       .request_port   = zs_request_port,
-       .config_port    = zs_config_port,
-       .verify_port    = zs_verify_port,
-};
-
-/*
- * Initialize Z85C30 port structures.
- */
-static int __init zs_probe_sccs(void)
-{
-       static int probed;
-       struct zs_parms zs_parms;
-       int chip, side, irq;
-       int n_chips = 0;
-       int i;
-
-       if (probed)
-               return 0;
-
-       irq = dec_interrupt[DEC_IRQ_SCC0];
-       if (irq >= 0) {
-               zs_parms.scc[n_chips] = IOASIC_SCC0;
-               zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC0];
-               n_chips++;
-       }
-       irq = dec_interrupt[DEC_IRQ_SCC1];
-       if (irq >= 0) {
-               zs_parms.scc[n_chips] = IOASIC_SCC1;
-               zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC1];
-               n_chips++;
-       }
-       if (!n_chips)
-               return -ENXIO;
-
-       probed = 1;
-
-       for (chip = 0; chip < n_chips; chip++) {
-               spin_lock_init(&zs_sccs[chip].zlock);
-               for (side = 0; side < ZS_NUM_CHAN; side++) {
-                       struct zs_port *zport = &zs_sccs[chip].zport[side];
-                       struct uart_port *uport = &zport->port;
-
-                       zport->scc      = &zs_sccs[chip];
-                       zport->clk_mode = 16;
-
-                       uport->irq      = zs_parms.irq[chip];
-                       uport->uartclk  = ZS_CLOCK;
-                       uport->fifosize = 1;
-                       uport->iotype   = UPIO_MEM;
-                       uport->flags    = UPF_BOOT_AUTOCONF;
-                       uport->ops      = &zs_ops;
-                       uport->line     = chip * ZS_NUM_CHAN + side;
-                       uport->mapbase  = dec_kn_slot_base +
-                                         zs_parms.scc[chip] +
-                                         (side ^ ZS_CHAN_B) * ZS_CHAN_IO_SIZE;
-
-                       for (i = 0; i < ZS_NUM_REGS; i++)
-                               zport->regs[i] = zs_init_regs[i];
-               }
-       }
-
-       return 0;
-}
-
-
-#ifdef CONFIG_SERIAL_ZS_CONSOLE
-static void zs_console_putchar(struct uart_port *uport, int ch)
-{
-       struct zs_port *zport = to_zport(uport);
-       struct zs_scc *scc = zport->scc;
-       int irq;
-       unsigned long flags;
-
-       spin_lock_irqsave(&scc->zlock, flags);
-       irq = !irqs_disabled_flags(flags);
-       if (zs_transmit_drain(zport, irq))
-               write_zsdata(zport, ch);
-       spin_unlock_irqrestore(&scc->zlock, flags);
-}
-
-/*
- * Print a string to the serial port trying not to disturb
- * any possible real use of the port...
- */
-static void zs_console_write(struct console *co, const char *s,
-                            unsigned int count)
-{
-       int chip = co->index / ZS_NUM_CHAN, side = co->index % ZS_NUM_CHAN;
-       struct zs_port *zport = &zs_sccs[chip].zport[side];
-       struct zs_scc *scc = zport->scc;
-       unsigned long flags;
-       u8 txint, txenb;
-       int irq;
-
-       /* Disable transmit interrupts and enable the transmitter. */
-       spin_lock_irqsave(&scc->zlock, flags);
-       txint = zport->regs[1];
-       txenb = zport->regs[5];
-       if (txint & TxINT_ENAB) {
-               zport->regs[1] = txint & ~TxINT_ENAB;
-               write_zsreg(zport, R1, zport->regs[1]);
-       }
-       if (!(txenb & TxENAB)) {
-               zport->regs[5] = txenb | TxENAB;
-               write_zsreg(zport, R5, zport->regs[5]);
-       }
-       spin_unlock_irqrestore(&scc->zlock, flags);
-
-       uart_console_write(&zport->port, s, count, zs_console_putchar);
-
-       /* Restore transmit interrupts and the transmitter enable. */
-       spin_lock_irqsave(&scc->zlock, flags);
-       irq = !irqs_disabled_flags(flags);
-       zs_line_drain(zport, irq);
-       if (!(txenb & TxENAB)) {
-               zport->regs[5] &= ~TxENAB;
-               write_zsreg(zport, R5, zport->regs[5]);
-       }
-       if (txint & TxINT_ENAB) {
-               zport->regs[1] |= TxINT_ENAB;
-               write_zsreg(zport, R1, zport->regs[1]);
-       }
-       spin_unlock_irqrestore(&scc->zlock, flags);
-}
-
-/*
- * Setup serial console baud/bits/parity.  We do two things here:
- * - construct a cflag setting for the first uart_open()
- * - initialise the serial port
- * Return non-zero if we didn't find a serial port.
- */
-static int __init zs_console_setup(struct console *co, char *options)
-{
-       int chip = co->index / ZS_NUM_CHAN, side = co->index % ZS_NUM_CHAN;
-       struct zs_port *zport = &zs_sccs[chip].zport[side];
-       struct uart_port *uport = &zport->port;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-       int ret;
-
-       ret = zs_map_port(uport);
-       if (ret)
-               return ret;
-
-       zs_reset(zport);
-       zs_pm(uport, 0, -1);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       return uart_set_options(uport, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver zs_reg;
-static struct console zs_console = {
-       .name   = "ttyS",
-       .write  = zs_console_write,
-       .device = uart_console_device,
-       .setup  = zs_console_setup,
-       .flags  = CON_PRINTBUFFER,
-       .index  = -1,
-       .data   = &zs_reg,
-};
-
-/*
- *     Register console.
- */
-static int __init zs_serial_console_init(void)
-{
-       int ret;
-
-       ret = zs_probe_sccs();
-       if (ret)
-               return ret;
-       register_console(&zs_console);
-
-       return 0;
-}
-
-console_initcall(zs_serial_console_init);
-
-#define SERIAL_ZS_CONSOLE      &zs_console
-#else
-#define SERIAL_ZS_CONSOLE      NULL
-#endif /* CONFIG_SERIAL_ZS_CONSOLE */
-
-static struct uart_driver zs_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "serial",
-       .dev_name               = "ttyS",
-       .major                  = TTY_MAJOR,
-       .minor                  = 64,
-       .nr                     = ZS_NUM_SCCS * ZS_NUM_CHAN,
-       .cons                   = SERIAL_ZS_CONSOLE,
-};
-
-/* zs_init inits the driver. */
-static int __init zs_init(void)
-{
-       int i, ret;
-
-       pr_info("%s%s\n", zs_name, zs_version);
-
-       /* Find out how many Z85C30 SCCs we have.  */
-       ret = zs_probe_sccs();
-       if (ret)
-               return ret;
-
-       ret = uart_register_driver(&zs_reg);
-       if (ret)
-               return ret;
-
-       for (i = 0; i < ZS_NUM_SCCS * ZS_NUM_CHAN; i++) {
-               struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN];
-               struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN];
-               struct uart_port *uport = &zport->port;
-
-               if (zport->scc)
-                       uart_add_one_port(&zs_reg, uport);
-       }
-
-       return 0;
-}
-
-static void __exit zs_exit(void)
-{
-       int i;
-
-       for (i = ZS_NUM_SCCS * ZS_NUM_CHAN - 1; i >= 0; i--) {
-               struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN];
-               struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN];
-               struct uart_port *uport = &zport->port;
-
-               if (zport->scc)
-                       uart_remove_one_port(&zs_reg, uport);
-       }
-
-       uart_unregister_driver(&zs_reg);
-}
-
-module_init(zs_init);
-module_exit(zs_exit);
diff --git a/drivers/serial/zs.h b/drivers/serial/zs.h
deleted file mode 100644 (file)
index aa921b5..0000000
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * zs.h: Definitions for the DECstation Z85C30 serial driver.
- *
- * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
- * Adapted from drivers/macintosh/macserial.h by Harald Koerfgen.
- *
- * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 2004, 2005, 2007  Maciej W. Rozycki
- */
-#ifndef _SERIAL_ZS_H
-#define _SERIAL_ZS_H
-
-#ifdef __KERNEL__
-
-#define ZS_NUM_REGS 16
-
-/*
- * This is our internal structure for each serial port's state.
- */
-struct zs_port {
-       struct zs_scc   *scc;                   /* Containing SCC.  */
-       struct uart_port port;                  /* Underlying UART.  */
-
-       int             clk_mode;               /* May be 1, 16, 32, or 64.  */
-
-       unsigned int    tty_break;              /* Set on BREAK condition.  */
-       int             tx_stopped;             /* Output is suspended.  */
-
-       unsigned int    mctrl;                  /* State of modem lines.  */
-       u8              brk;                    /* BREAK state from RR0.  */
-
-       u8              regs[ZS_NUM_REGS];      /* Channel write registers.  */
-};
-
-/*
- * Per-SCC state for locking and the interrupt handler.
- */
-struct zs_scc {
-       struct zs_port  zport[2];
-       spinlock_t      zlock;
-       atomic_t        irq_guard;
-       int             initialised;
-};
-
-#endif /* __KERNEL__ */
-
-/*
- * Conversion routines to/from brg time constants from/to bits per second.
- */
-#define ZS_BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
-#define ZS_BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
-
-/*
- * The Zilog register set.
- */
-
-/* Write Register 0 (Command) */
-#define R0             0       /* Register selects */
-#define R1             1
-#define R2             2
-#define R3             3
-#define R4             4
-#define R5             5
-#define R6             6
-#define R7             7
-#define R8             8
-#define R9             9
-#define R10            10
-#define R11            11
-#define R12            12
-#define R13            13
-#define R14            14
-#define R15            15
-
-#define NULLCODE       0       /* Null Code */
-#define POINT_HIGH     0x8     /* Select upper half of registers */
-#define RES_EXT_INT    0x10    /* Reset Ext. Status Interrupts */
-#define SEND_ABORT     0x18    /* HDLC Abort */
-#define RES_RxINT_FC   0x20    /* Reset RxINT on First Character */
-#define RES_Tx_P       0x28    /* Reset TxINT Pending */
-#define ERR_RES                0x30    /* Error Reset */
-#define RES_H_IUS      0x38    /* Reset highest IUS */
-
-#define RES_Rx_CRC     0x40    /* Reset Rx CRC Checker */
-#define RES_Tx_CRC     0x80    /* Reset Tx CRC Checker */
-#define RES_EOM_L      0xC0    /* Reset EOM latch */
-
-/* Write Register 1 (Tx/Rx/Ext Int Enable and WAIT/DMA Commands) */
-#define EXT_INT_ENAB   0x1     /* Ext Int Enable */
-#define TxINT_ENAB     0x2     /* Tx Int Enable */
-#define PAR_SPEC       0x4     /* Parity is special condition */
-
-#define RxINT_DISAB    0       /* Rx Int Disable */
-#define RxINT_FCERR    0x8     /* Rx Int on First Character Only or Error */
-#define RxINT_ALL      0x10    /* Int on all Rx Characters or error */
-#define RxINT_ERR      0x18    /* Int on error only */
-#define RxINT_MASK     0x18
-
-#define WT_RDY_RT      0x20    /* Wait/Ready on R/T */
-#define WT_FN_RDYFN    0x40    /* Wait/FN/Ready FN */
-#define WT_RDY_ENAB    0x80    /* Wait/Ready Enable */
-
-/* Write Register 2 (Interrupt Vector) */
-
-/* Write Register 3 (Receive Parameters and Control) */
-#define RxENABLE       0x1     /* Rx Enable */
-#define SYNC_L_INH     0x2     /* Sync Character Load Inhibit */
-#define ADD_SM         0x4     /* Address Search Mode (SDLC) */
-#define RxCRC_ENAB     0x8     /* Rx CRC Enable */
-#define ENT_HM         0x10    /* Enter Hunt Mode */
-#define AUTO_ENAB      0x20    /* Auto Enables */
-#define Rx5            0x0     /* Rx 5 Bits/Character */
-#define Rx7            0x40    /* Rx 7 Bits/Character */
-#define Rx6            0x80    /* Rx 6 Bits/Character */
-#define Rx8            0xc0    /* Rx 8 Bits/Character */
-#define RxNBITS_MASK   0xc0
-
-/* Write Register 4 (Transmit/Receive Miscellaneous Parameters and Modes) */
-#define PAR_ENA                0x1     /* Parity Enable */
-#define PAR_EVEN       0x2     /* Parity Even/Odd* */
-
-#define SYNC_ENAB      0       /* Sync Modes Enable */
-#define SB1            0x4     /* 1 stop bit/char */
-#define SB15           0x8     /* 1.5 stop bits/char */
-#define SB2            0xc     /* 2 stop bits/char */
-#define SB_MASK                0xc
-
-#define MONSYNC                0       /* 8 Bit Sync character */
-#define BISYNC         0x10    /* 16 bit sync character */
-#define SDLC           0x20    /* SDLC Mode (01111110 Sync Flag) */
-#define EXTSYNC                0x30    /* External Sync Mode */
-
-#define X1CLK          0x0     /* x1 clock mode */
-#define X16CLK         0x40    /* x16 clock mode */
-#define X32CLK         0x80    /* x32 clock mode */
-#define X64CLK         0xc0    /* x64 clock mode */
-#define XCLK_MASK      0xc0
-
-/* Write Register 5 (Transmit Parameters and Controls) */
-#define TxCRC_ENAB     0x1     /* Tx CRC Enable */
-#define RTS            0x2     /* RTS */
-#define SDLC_CRC       0x4     /* SDLC/CRC-16 */
-#define TxENAB         0x8     /* Tx Enable */
-#define SND_BRK                0x10    /* Send Break */
-#define Tx5            0x0     /* Tx 5 bits (or less)/character */
-#define Tx7            0x20    /* Tx 7 bits/character */
-#define Tx6            0x40    /* Tx 6 bits/character */
-#define Tx8            0x60    /* Tx 8 bits/character */
-#define TxNBITS_MASK   0x60
-#define DTR            0x80    /* DTR */
-
-/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
-
-/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
-
-/* Write Register 8 (Transmit Buffer) */
-
-/* Write Register 9 (Master Interrupt Control) */
-#define VIS            1       /* Vector Includes Status */
-#define NV             2       /* No Vector */
-#define DLC            4       /* Disable Lower Chain */
-#define MIE            8       /* Master Interrupt Enable */
-#define STATHI         0x10    /* Status high */
-#define SOFTACK                0x20    /* Software Interrupt Acknowledge */
-#define NORESET                0       /* No reset on write to R9 */
-#define CHRB           0x40    /* Reset channel B */
-#define CHRA           0x80    /* Reset channel A */
-#define FHWRES         0xc0    /* Force hardware reset */
-
-/* Write Register 10 (Miscellaneous Transmitter/Receiver Control Bits) */
-#define BIT6           1       /* 6 bit/8bit sync */
-#define LOOPMODE       2       /* SDLC Loop mode */
-#define ABUNDER                4       /* Abort/flag on SDLC xmit underrun */
-#define MARKIDLE       8       /* Mark/flag on idle */
-#define GAOP           0x10    /* Go active on poll */
-#define NRZ            0       /* NRZ mode */
-#define NRZI           0x20    /* NRZI mode */
-#define FM1            0x40    /* FM1 (transition = 1) */
-#define FM0            0x60    /* FM0 (transition = 0) */
-#define CRCPS          0x80    /* CRC Preset I/O */
-
-/* Write Register 11 (Clock Mode Control) */
-#define TRxCXT         0       /* TRxC = Xtal output */
-#define TRxCTC         1       /* TRxC = Transmit clock */
-#define TRxCBR         2       /* TRxC = BR Generator Output */
-#define TRxCDP         3       /* TRxC = DPLL output */
-#define TRxCOI         4       /* TRxC O/I */
-#define TCRTxCP                0       /* Transmit clock = RTxC pin */
-#define TCTRxCP                8       /* Transmit clock = TRxC pin */
-#define TCBR           0x10    /* Transmit clock = BR Generator output */
-#define TCDPLL         0x18    /* Transmit clock = DPLL output */
-#define RCRTxCP                0       /* Receive clock = RTxC pin */
-#define RCTRxCP                0x20    /* Receive clock = TRxC pin */
-#define RCBR           0x40    /* Receive clock = BR Generator output */
-#define RCDPLL         0x60    /* Receive clock = DPLL output */
-#define RTxCX          0x80    /* RTxC Xtal/No Xtal */
-
-/* Write Register 12 (Lower Byte of Baud Rate Generator Time Constant) */
-
-/* Write Register 13 (Upper Byte of Baud Rate Generator Time Constant) */
-
-/* Write Register 14 (Miscellaneous Control Bits) */
-#define BRENABL                1       /* Baud rate generator enable */
-#define BRSRC          2       /* Baud rate generator source */
-#define DTRREQ         4       /* DTR/Request function */
-#define AUTOECHO       8       /* Auto Echo */
-#define LOOPBAK                0x10    /* Local loopback */
-#define SEARCH         0x20    /* Enter search mode */
-#define RMC            0x40    /* Reset missing clock */
-#define DISDPLL                0x60    /* Disable DPLL */
-#define SSBR           0x80    /* Set DPLL source = BR generator */
-#define SSRTxC         0xa0    /* Set DPLL source = RTxC */
-#define SFMM           0xc0    /* Set FM mode */
-#define SNRZI          0xe0    /* Set NRZI mode */
-
-/* Write Register 15 (External/Status Interrupt Control) */
-#define WR7P_EN                1       /* WR7 Prime SDLC Feature Enable */
-#define ZCIE           2       /* Zero count IE */
-#define DCDIE          8       /* DCD IE */
-#define SYNCIE         0x10    /* Sync/hunt IE */
-#define CTSIE          0x20    /* CTS IE */
-#define TxUIE          0x40    /* Tx Underrun/EOM IE */
-#define BRKIE          0x80    /* Break/Abort IE */
-
-
-/* Read Register 0 (Transmit/Receive Buffer Status and External Status) */
-#define Rx_CH_AV       0x1     /* Rx Character Available */
-#define ZCOUNT         0x2     /* Zero count */
-#define Tx_BUF_EMP     0x4     /* Tx Buffer empty */
-#define DCD            0x8     /* DCD */
-#define SYNC_HUNT      0x10    /* Sync/hunt */
-#define CTS            0x20    /* CTS */
-#define TxEOM          0x40    /* Tx underrun */
-#define BRK_ABRT       0x80    /* Break/Abort */
-
-/* Read Register 1 (Special Receive Condition Status) */
-#define ALL_SNT                0x1     /* All sent */
-/* Residue Data for 8 Rx bits/char programmed */
-#define RES3           0x8     /* 0/3 */
-#define RES4           0x4     /* 0/4 */
-#define RES5           0xc     /* 0/5 */
-#define RES6           0x2     /* 0/6 */
-#define RES7           0xa     /* 0/7 */
-#define RES8           0x6     /* 0/8 */
-#define RES18          0xe     /* 1/8 */
-#define RES28          0x0     /* 2/8 */
-/* Special Rx Condition Interrupts */
-#define PAR_ERR                0x10    /* Parity Error */
-#define Rx_OVR         0x20    /* Rx Overrun Error */
-#define FRM_ERR                0x40    /* CRC/Framing Error */
-#define END_FR         0x80    /* End of Frame (SDLC) */
-
-/* Read Register 2 (Interrupt Vector (WR2) -- channel A).  */
-
-/* Read Register 2 (Modified Interrupt Vector -- channel B).  */
-
-/* Read Register 3 (Interrupt Pending Bits -- channel A only).  */
-#define CHBEXT         0x1     /* Channel B Ext/Stat IP */
-#define CHBTxIP                0x2     /* Channel B Tx IP */
-#define CHBRxIP                0x4     /* Channel B Rx IP */
-#define CHAEXT         0x8     /* Channel A Ext/Stat IP */
-#define CHATxIP                0x10    /* Channel A Tx IP */
-#define CHARxIP                0x20    /* Channel A Rx IP */
-
-/* Read Register 6 (SDLC FIFO Status and Byte Count LSB) */
-
-/* Read Register 7 (SDLC FIFO Status and Byte Count MSB) */
-
-/* Read Register 8 (Receive Data) */
-
-/* Read Register 10 (Miscellaneous Status Bits) */
-#define ONLOOP         2       /* On loop */
-#define LOOPSEND       0x10    /* Loop sending */
-#define CLK2MIS                0x40    /* Two clocks missing */
-#define CLK1MIS                0x80    /* One clock missing */
-
-/* Read Register 12 (Lower Byte of Baud Rate Generator Constant (WR12)) */
-
-/* Read Register 13 (Upper Byte of Baud Rate Generator Constant (WR13) */
-
-/* Read Register 15 (External/Status Interrupt Control (WR15)) */
-
-#endif /* _SERIAL_ZS_H */
index d3685f071b8dea2d901b5ae8f761d851fa4fff00..396277216e4ffdddf37e48d595e5a865b6546e46 100644 (file)
@@ -10,3 +10,4 @@ obj-$(CONFIG_R3964)           += n_r3964.o
 
 obj-y                          += vt/
 obj-$(CONFIG_HVC_DRIVER)       += hvc/
+obj-y                          += serial/
diff --git a/drivers/tty/serial/21285.c b/drivers/tty/serial/21285.c
new file mode 100644 (file)
index 0000000..d89aa38
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+ * linux/drivers/serial/21285.c
+ *
+ * Driver for the serial port on the 21285 StrongArm-110 core logic chip.
+ *
+ * Based on drivers/char/serial.c
+ */
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/device.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/dec21285.h>
+#include <mach/hardware.h>
+
+#define BAUD_BASE              (mem_fclk_21285/64)
+
+#define SERIAL_21285_NAME      "ttyFB"
+#define SERIAL_21285_MAJOR     204
+#define SERIAL_21285_MINOR     4
+
+#define RXSTAT_DUMMY_READ      0x80000000
+#define RXSTAT_FRAME           (1 << 0)
+#define RXSTAT_PARITY          (1 << 1)
+#define RXSTAT_OVERRUN         (1 << 2)
+#define RXSTAT_ANYERR          (RXSTAT_FRAME|RXSTAT_PARITY|RXSTAT_OVERRUN)
+
+#define H_UBRLCR_BREAK         (1 << 0)
+#define H_UBRLCR_PARENB                (1 << 1)
+#define H_UBRLCR_PAREVN                (1 << 2)
+#define H_UBRLCR_STOPB         (1 << 3)
+#define H_UBRLCR_FIFO          (1 << 4)
+
+static const char serial21285_name[] = "Footbridge UART";
+
+#define tx_enabled(port)       ((port)->unused[0])
+#define rx_enabled(port)       ((port)->unused[1])
+
+/*
+ * The documented expression for selecting the divisor is:
+ *  BAUD_BASE / baud - 1
+ * However, typically BAUD_BASE is not divisible by baud, so
+ * we want to select the divisor that gives us the minimum
+ * error.  Therefore, we want:
+ *  int(BAUD_BASE / baud - 0.5) ->
+ *  int(BAUD_BASE / baud - (baud >> 1) / baud) ->
+ *  int((BAUD_BASE - (baud >> 1)) / baud)
+ */
+
+static void serial21285_stop_tx(struct uart_port *port)
+{
+       if (tx_enabled(port)) {
+               disable_irq_nosync(IRQ_CONTX);
+               tx_enabled(port) = 0;
+       }
+}
+
+static void serial21285_start_tx(struct uart_port *port)
+{
+       if (!tx_enabled(port)) {
+               enable_irq(IRQ_CONTX);
+               tx_enabled(port) = 1;
+       }
+}
+
+static void serial21285_stop_rx(struct uart_port *port)
+{
+       if (rx_enabled(port)) {
+               disable_irq_nosync(IRQ_CONRX);
+               rx_enabled(port) = 0;
+       }
+}
+
+static void serial21285_enable_ms(struct uart_port *port)
+{
+}
+
+static irqreturn_t serial21285_rx_chars(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       struct tty_struct *tty = port->state->port.tty;
+       unsigned int status, ch, flag, rxs, max_count = 256;
+
+       status = *CSR_UARTFLG;
+       while (!(status & 0x10) && max_count--) {
+               ch = *CSR_UARTDR;
+               flag = TTY_NORMAL;
+               port->icount.rx++;
+
+               rxs = *CSR_RXSTAT | RXSTAT_DUMMY_READ;
+               if (unlikely(rxs & RXSTAT_ANYERR)) {
+                       if (rxs & RXSTAT_PARITY)
+                               port->icount.parity++;
+                       else if (rxs & RXSTAT_FRAME)
+                               port->icount.frame++;
+                       if (rxs & RXSTAT_OVERRUN)
+                               port->icount.overrun++;
+
+                       rxs &= port->read_status_mask;
+
+                       if (rxs & RXSTAT_PARITY)
+                               flag = TTY_PARITY;
+                       else if (rxs & RXSTAT_FRAME)
+                               flag = TTY_FRAME;
+               }
+
+               uart_insert_char(port, rxs, RXSTAT_OVERRUN, ch, flag);
+
+               status = *CSR_UARTFLG;
+       }
+       tty_flip_buffer_push(tty);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t serial21285_tx_chars(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       struct circ_buf *xmit = &port->state->xmit;
+       int count = 256;
+
+       if (port->x_char) {
+               *CSR_UARTDR = port->x_char;
+               port->icount.tx++;
+               port->x_char = 0;
+               goto out;
+       }
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               serial21285_stop_tx(port);
+               goto out;
+       }
+
+       do {
+               *CSR_UARTDR = xmit->buf[xmit->tail];
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (--count > 0 && !(*CSR_UARTFLG & 0x20));
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit))
+               serial21285_stop_tx(port);
+
+ out:
+       return IRQ_HANDLED;
+}
+
+static unsigned int serial21285_tx_empty(struct uart_port *port)
+{
+       return (*CSR_UARTFLG & 8) ? 0 : TIOCSER_TEMT;
+}
+
+/* no modem control lines */
+static unsigned int serial21285_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+static void serial21285_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static void serial21285_break_ctl(struct uart_port *port, int break_state)
+{
+       unsigned long flags;
+       unsigned int h_lcr;
+
+       spin_lock_irqsave(&port->lock, flags);
+       h_lcr = *CSR_H_UBRLCR;
+       if (break_state)
+               h_lcr |= H_UBRLCR_BREAK;
+       else
+               h_lcr &= ~H_UBRLCR_BREAK;
+       *CSR_H_UBRLCR = h_lcr;
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int serial21285_startup(struct uart_port *port)
+{
+       int ret;
+
+       tx_enabled(port) = 1;
+       rx_enabled(port) = 1;
+
+       ret = request_irq(IRQ_CONRX, serial21285_rx_chars, 0,
+                         serial21285_name, port);
+       if (ret == 0) {
+               ret = request_irq(IRQ_CONTX, serial21285_tx_chars, 0,
+                                 serial21285_name, port);
+               if (ret)
+                       free_irq(IRQ_CONRX, port);
+       }
+
+       return ret;
+}
+
+static void serial21285_shutdown(struct uart_port *port)
+{
+       free_irq(IRQ_CONTX, port);
+       free_irq(IRQ_CONRX, port);
+}
+
+static void
+serial21285_set_termios(struct uart_port *port, struct ktermios *termios,
+                       struct ktermios *old)
+{
+       unsigned long flags;
+       unsigned int baud, quot, h_lcr, b;
+
+       /*
+        * We don't support modem control lines.
+        */
+       termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR);
+       termios->c_cflag |= CLOCAL;
+
+       /*
+        * We don't support BREAK character recognition.
+        */
+       termios->c_iflag &= ~(IGNBRK | BRKINT);
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
+       quot = uart_get_divisor(port, baud);
+       b = port->uartclk / (16 * quot);
+       tty_termios_encode_baud_rate(termios, b, b);
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               h_lcr = 0x00;
+               break;
+       case CS6:
+               h_lcr = 0x20;
+               break;
+       case CS7:
+               h_lcr = 0x40;
+               break;
+       default: /* CS8 */
+               h_lcr = 0x60;
+               break;
+       }
+
+       if (termios->c_cflag & CSTOPB)
+               h_lcr |= H_UBRLCR_STOPB;
+       if (termios->c_cflag & PARENB) {
+               h_lcr |= H_UBRLCR_PARENB;
+               if (!(termios->c_cflag & PARODD))
+                       h_lcr |= H_UBRLCR_PAREVN;
+       }
+
+       if (port->fifosize)
+               h_lcr |= H_UBRLCR_FIFO;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       /*
+        * Which character status flags are we interested in?
+        */
+       port->read_status_mask = RXSTAT_OVERRUN;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY;
+
+       /*
+        * Which character status flags should we ignore?
+        */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY;
+       if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= RXSTAT_OVERRUN;
+
+       /*
+        * Ignore all characters if CREAD is not set.
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               port->ignore_status_mask |= RXSTAT_DUMMY_READ;
+
+       quot -= 1;
+
+       *CSR_UARTCON = 0;
+       *CSR_L_UBRLCR = quot & 0xff;
+       *CSR_M_UBRLCR = (quot >> 8) & 0x0f;
+       *CSR_H_UBRLCR = h_lcr;
+       *CSR_UARTCON = 1;
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *serial21285_type(struct uart_port *port)
+{
+       return port->type == PORT_21285 ? "DC21285" : NULL;
+}
+
+static void serial21285_release_port(struct uart_port *port)
+{
+       release_mem_region(port->mapbase, 32);
+}
+
+static int serial21285_request_port(struct uart_port *port)
+{
+       return request_mem_region(port->mapbase, 32, serial21285_name)
+                        != NULL ? 0 : -EBUSY;
+}
+
+static void serial21285_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE && serial21285_request_port(port) == 0)
+               port->type = PORT_21285;
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int serial21285_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       int ret = 0;
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_21285)
+               ret = -EINVAL;
+       if (ser->irq != NO_IRQ)
+               ret = -EINVAL;
+       if (ser->baud_base != port->uartclk / 16)
+               ret = -EINVAL;
+       return ret;
+}
+
+static struct uart_ops serial21285_ops = {
+       .tx_empty       = serial21285_tx_empty,
+       .get_mctrl      = serial21285_get_mctrl,
+       .set_mctrl      = serial21285_set_mctrl,
+       .stop_tx        = serial21285_stop_tx,
+       .start_tx       = serial21285_start_tx,
+       .stop_rx        = serial21285_stop_rx,
+       .enable_ms      = serial21285_enable_ms,
+       .break_ctl      = serial21285_break_ctl,
+       .startup        = serial21285_startup,
+       .shutdown       = serial21285_shutdown,
+       .set_termios    = serial21285_set_termios,
+       .type           = serial21285_type,
+       .release_port   = serial21285_release_port,
+       .request_port   = serial21285_request_port,
+       .config_port    = serial21285_config_port,
+       .verify_port    = serial21285_verify_port,
+};
+
+static struct uart_port serial21285_port = {
+       .mapbase        = 0x42000160,
+       .iotype         = UPIO_MEM,
+       .irq            = NO_IRQ,
+       .fifosize       = 16,
+       .ops            = &serial21285_ops,
+       .flags          = UPF_BOOT_AUTOCONF,
+};
+
+static void serial21285_setup_ports(void)
+{
+       serial21285_port.uartclk = mem_fclk_21285 / 4;
+}
+
+#ifdef CONFIG_SERIAL_21285_CONSOLE
+static void serial21285_console_putchar(struct uart_port *port, int ch)
+{
+       while (*CSR_UARTFLG & 0x20)
+               barrier();
+       *CSR_UARTDR = ch;
+}
+
+static void
+serial21285_console_write(struct console *co, const char *s,
+                         unsigned int count)
+{
+       uart_console_write(&serial21285_port, s, count, serial21285_console_putchar);
+}
+
+static void __init
+serial21285_get_options(struct uart_port *port, int *baud,
+                       int *parity, int *bits)
+{
+       if (*CSR_UARTCON == 1) {
+               unsigned int tmp;
+
+               tmp = *CSR_H_UBRLCR;
+               switch (tmp & 0x60) {
+               case 0x00:
+                       *bits = 5;
+                       break;
+               case 0x20:
+                       *bits = 6;
+                       break;
+               case 0x40:
+                       *bits = 7;
+                       break;
+               default:
+               case 0x60:
+                       *bits = 8;
+                       break;
+               }
+
+               if (tmp & H_UBRLCR_PARENB) {
+                       *parity = 'o';
+                       if (tmp & H_UBRLCR_PAREVN)
+                               *parity = 'e';
+               }
+
+               tmp = *CSR_L_UBRLCR | (*CSR_M_UBRLCR << 8);
+
+               *baud = port->uartclk / (16 * (tmp + 1));
+       }
+}
+
+static int __init serial21285_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port = &serial21285_port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (machine_is_personal_server())
+               baud = 57600;
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               serial21285_get_options(port, &baud, &parity, &bits);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver serial21285_reg;
+
+static struct console serial21285_console =
+{
+       .name           = SERIAL_21285_NAME,
+       .write          = serial21285_console_write,
+       .device         = uart_console_device,
+       .setup          = serial21285_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &serial21285_reg,
+};
+
+static int __init rs285_console_init(void)
+{
+       serial21285_setup_ports();
+       register_console(&serial21285_console);
+       return 0;
+}
+console_initcall(rs285_console_init);
+
+#define SERIAL_21285_CONSOLE   &serial21285_console
+#else
+#define SERIAL_21285_CONSOLE   NULL
+#endif
+
+static struct uart_driver serial21285_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "ttyFB",
+       .dev_name               = "ttyFB",
+       .major                  = SERIAL_21285_MAJOR,
+       .minor                  = SERIAL_21285_MINOR,
+       .nr                     = 1,
+       .cons                   = SERIAL_21285_CONSOLE,
+};
+
+static int __init serial21285_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "Serial: 21285 driver\n");
+
+       serial21285_setup_ports();
+
+       ret = uart_register_driver(&serial21285_reg);
+       if (ret == 0)
+               uart_add_one_port(&serial21285_reg, &serial21285_port);
+
+       return ret;
+}
+
+static void __exit serial21285_exit(void)
+{
+       uart_remove_one_port(&serial21285_reg, &serial21285_port);
+       uart_unregister_driver(&serial21285_reg);
+}
+
+module_init(serial21285_init);
+module_exit(serial21285_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Intel Footbridge (21285) serial driver");
+MODULE_ALIAS_CHARDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR);
diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c
new file mode 100644 (file)
index 0000000..be0ebce
--- /dev/null
@@ -0,0 +1,1472 @@
+/* 68328serial.c: Serial port driver for 68328 microcontroller
+ *
+ * Copyright (C) 1995       David S. Miller    <davem@caip.rutgers.edu>
+ * Copyright (C) 1998       Kenneth Albanowski <kjahds@kjahds.com>
+ * Copyright (C) 1998, 1999 D. Jeff Dionne     <jeff@uclinux.org>
+ * Copyright (C) 1999       Vladimir Gurevich  <vgurevic@cisco.com>
+ * Copyright (C) 2002-2003  David McCullough   <davidm@snapgear.com>
+ * Copyright (C) 2002       Greg Ungerer       <gerg@snapgear.com>
+ *
+ * VZ Support/Fixes             Evan Stawnyczy <e@lineo.ca>
+ * Multiple UART support        Daniel Potts <danielp@cse.unsw.edu.au>
+ * Power management support     Daniel Potts <danielp@cse.unsw.edu.au>
+ * VZ Second Serial Port enable Phil Wilshire
+ * 2.4/2.5 port                 David McCullough
+ */
+
+#include <asm/dbg.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.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/mm.h>
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/reboot.h>
+#include <linux/keyboard.h>
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/gfp.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/delay.h>
+#include <asm/uaccess.h>
+
+/* (es) */
+/* note: perhaps we can murge these files, so that you can just
+ *      define 1 of them, and they can sort that out for themselves
+ */
+#if defined(CONFIG_M68EZ328)
+#include <asm/MC68EZ328.h>
+#else
+#if defined(CONFIG_M68VZ328)
+#include <asm/MC68VZ328.h>
+#else
+#include <asm/MC68328.h>
+#endif /* CONFIG_M68VZ328 */
+#endif /* CONFIG_M68EZ328 */
+
+#include "68328serial.h"
+
+/* Turn off usage of real serial interrupt code, to "support" Copilot */
+#ifdef CONFIG_XCOPILOT_BUGS
+#undef USE_INTS
+#else
+#define USE_INTS
+#endif
+
+static struct m68k_serial m68k_soft[NR_PORTS];
+
+static unsigned int uart_irqs[NR_PORTS] = UART_IRQ_DEFNS;
+
+/* multiple ports are contiguous in memory */
+m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR;
+
+struct tty_struct m68k_ttys;
+struct m68k_serial *m68k_consinfo = 0;
+
+#define M68K_CLOCK (16667000) /* FIXME: 16MHz is likely wrong */
+
+struct tty_driver *serial_driver;
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+/* Debugging... DEBUG_INTR is bad to use when one of the zs
+ * lines is your console ;(
+ */
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+
+#define RS_ISR_PASS_LIMIT 256
+
+static void change_speed(struct m68k_serial *info);
+
+/*
+ *     Setup for console. Argument comes from the boot command line.
+ */
+
+/* note: this is messy, but it works, again, perhaps defined somewhere else?*/
+#ifdef CONFIG_M68VZ328
+#define CONSOLE_BAUD_RATE      19200
+#define DEFAULT_CBAUD          B19200
+#endif
+
+
+#ifndef CONSOLE_BAUD_RATE
+#define        CONSOLE_BAUD_RATE       9600
+#define        DEFAULT_CBAUD           B9600
+#endif
+
+
+static int m68328_console_initted = 0;
+static int m68328_console_baud    = CONSOLE_BAUD_RATE;
+static int m68328_console_cbaud   = DEFAULT_CBAUD;
+
+
+static inline int serial_paranoia_check(struct m68k_serial *info,
+                                       char *name, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+       static const char *badmagic =
+               "Warning: bad magic number for serial struct %s in %s\n";
+       static const char *badinfo =
+               "Warning: null m68k_serial for %s in %s\n";
+
+       if (!info) {
+               printk(badinfo, name, routine);
+               return 1;
+       }
+       if (info->magic != SERIAL_MAGIC) {
+               printk(badmagic, name, routine);
+               return 1;
+       }
+#endif
+       return 0;
+}
+
+/*
+ * This is used to figure out the divisor speeds and the timeouts
+ */
+static int baud_table[] = {
+       0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+       9600, 19200, 38400, 57600, 115200, 0 };
+
+/* Sets or clears DTR/RTS on the requested line */
+static inline void m68k_rtsdtr(struct m68k_serial *ss, int set)
+{
+       if (set) {
+               /* set the RTS/CTS line */
+       } else {
+               /* clear it */
+       }
+       return;
+}
+
+/* Utility routines */
+static inline int get_baud(struct m68k_serial *ss)
+{
+       unsigned long result = 115200;
+       unsigned short int baud = uart_addr[ss->line].ubaud;
+       if (GET_FIELD(baud, UBAUD_PRESCALER) == 0x38) result = 38400;
+       result >>= GET_FIELD(baud, UBAUD_DIVIDE);
+
+       return result;
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ * ------------------------------------------------------------
+ */
+static void rs_stop(struct tty_struct *tty)
+{
+       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+       m68328_uart *uart = &uart_addr[info->line];
+       unsigned long flags;
+
+       if (serial_paranoia_check(info, tty->name, "rs_stop"))
+               return;
+       
+       local_irq_save(flags);
+       uart->ustcnt &= ~USTCNT_TXEN;
+       local_irq_restore(flags);
+}
+
+static int rs_put_char(char ch)
+{
+        int flags, loops = 0;
+
+        local_irq_save(flags);
+
+       while (!(UTX & UTX_TX_AVAIL) && (loops < 1000)) {
+               loops++;
+               udelay(5);
+        }
+
+       UTX_TXDATA = ch;
+        udelay(5);
+        local_irq_restore(flags);
+        return 1;
+}
+
+static void rs_start(struct tty_struct *tty)
+{
+       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+       m68328_uart *uart = &uart_addr[info->line];
+       unsigned long flags;
+       
+       if (serial_paranoia_check(info, tty->name, "rs_start"))
+               return;
+       
+       local_irq_save(flags);
+       if (info->xmit_cnt && info->xmit_buf && !(uart->ustcnt & USTCNT_TXEN)) {
+#ifdef USE_INTS
+               uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK;
+#else
+               uart->ustcnt |= USTCNT_TXEN;
+#endif
+       }
+       local_irq_restore(flags);
+}
+
+/* Drop into either the boot monitor or kadb upon receiving a break
+ * from keyboard/console input.
+ */
+static void batten_down_hatches(void)
+{
+       /* Drop into the debugger */
+}
+
+static void status_handle(struct m68k_serial *info, unsigned short status)
+{
+#if 0
+       if(status & DCD) {
+               if((info->port.tty->termios->c_cflag & CRTSCTS) &&
+                  ((info->curregs[3] & AUTO_ENAB)==0)) {
+                       info->curregs[3] |= AUTO_ENAB;
+                       info->pendregs[3] |= AUTO_ENAB;
+                       write_zsreg(info->m68k_channel, 3, info->curregs[3]);
+               }
+       } else {
+               if((info->curregs[3] & AUTO_ENAB)) {
+                       info->curregs[3] &= ~AUTO_ENAB;
+                       info->pendregs[3] &= ~AUTO_ENAB;
+                       write_zsreg(info->m68k_channel, 3, info->curregs[3]);
+               }
+       }
+#endif
+       /* If this is console input and this is a
+        * 'break asserted' status change interrupt
+        * see if we can drop into the debugger
+        */
+       if((status & URX_BREAK) && info->break_abort)
+               batten_down_hatches();
+       return;
+}
+
+static void receive_chars(struct m68k_serial *info, unsigned short rx)
+{
+       struct tty_struct *tty = info->port.tty;
+       m68328_uart *uart = &uart_addr[info->line];
+       unsigned char ch, flag;
+
+       /*
+        * This do { } while() loop will get ALL chars out of Rx FIFO 
+         */
+#ifndef CONFIG_XCOPILOT_BUGS
+       do {
+#endif 
+               ch = GET_FIELD(rx, URX_RXDATA);
+       
+               if(info->is_cons) {
+                       if(URX_BREAK & rx) { /* whee, break received */
+                               status_handle(info, rx);
+                               return;
+#ifdef CONFIG_MAGIC_SYSRQ
+                       } else if (ch == 0x10) { /* ^P */
+                               show_state();
+                               show_free_areas();
+                               show_buffers();
+/*                             show_net_buffers(); */
+                               return;
+                       } else if (ch == 0x12) { /* ^R */
+                               emergency_restart();
+                               return;
+#endif /* CONFIG_MAGIC_SYSRQ */
+                       }
+               }
+
+               if(!tty)
+                       goto clear_and_exit;
+               
+               flag = TTY_NORMAL;
+
+               if(rx & URX_PARITY_ERROR) {
+                       flag = TTY_PARITY;
+                       status_handle(info, rx);
+               } else if(rx & URX_OVRUN) {
+                       flag = TTY_OVERRUN;
+                       status_handle(info, rx);
+               } else if(rx & URX_FRAME_ERROR) {
+                       flag = TTY_FRAME;
+                       status_handle(info, rx);
+               }
+               tty_insert_flip_char(tty, ch, flag);
+#ifndef CONFIG_XCOPILOT_BUGS
+       } while((rx = uart->urx.w) & URX_DATA_READY);
+#endif
+
+       tty_schedule_flip(tty);
+
+clear_and_exit:
+       return;
+}
+
+static void transmit_chars(struct m68k_serial *info)
+{
+       m68328_uart *uart = &uart_addr[info->line];
+
+       if (info->x_char) {
+               /* Send next char */
+               uart->utx.b.txdata = info->x_char;
+               info->x_char = 0;
+               goto clear_and_return;
+       }
+
+       if((info->xmit_cnt <= 0) || info->port.tty->stopped) {
+               /* That's peculiar... TX ints off */
+               uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
+               goto clear_and_return;
+       }
+
+       /* Send char */
+       uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
+       info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+       info->xmit_cnt--;
+
+       if (info->xmit_cnt < WAKEUP_CHARS)
+               schedule_work(&info->tqueue);
+
+       if(info->xmit_cnt <= 0) {
+               /* All done for now... TX ints off */
+               uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
+               goto clear_and_return;
+       }
+
+clear_and_return:
+       /* Clear interrupt (should be auto)*/
+       return;
+}
+
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+irqreturn_t rs_interrupt(int irq, void *dev_id)
+{
+       struct m68k_serial *info = dev_id;
+       m68328_uart *uart;
+       unsigned short rx;
+       unsigned short tx;
+
+       uart = &uart_addr[info->line];
+       rx = uart->urx.w;
+
+#ifdef USE_INTS
+       tx = uart->utx.w;
+
+       if (rx & URX_DATA_READY) receive_chars(info, rx);
+       if (tx & UTX_TX_AVAIL)   transmit_chars(info);
+#else
+       receive_chars(info, rx);                
+#endif
+       return IRQ_HANDLED;
+}
+
+static void do_softint(struct work_struct *work)
+{
+       struct m68k_serial      *info = container_of(work, struct m68k_serial, tqueue);
+       struct tty_struct       *tty;
+       
+       tty = info->port.tty;
+       if (!tty)
+               return;
+#if 0
+       if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+               tty_wakeup(tty);
+       }
+#endif   
+}
+
+/*
+ * This routine is called from the scheduler tqueue when the interrupt
+ * routine has signalled that a hangup has occurred.  The path of
+ * hangup processing is:
+ *
+ *     serial interrupt routine -> (scheduler tqueue) ->
+ *     do_serial_hangup() -> tty->hangup() -> rs_hangup()
+ * 
+ */
+static void do_serial_hangup(struct work_struct *work)
+{
+       struct m68k_serial      *info = container_of(work, struct m68k_serial, tqueue_hangup);
+       struct tty_struct       *tty;
+       
+       tty = info->port.tty;
+       if (!tty)
+               return;
+
+       tty_hangup(tty);
+}
+
+
+static int startup(struct m68k_serial * info)
+{
+       m68328_uart *uart = &uart_addr[info->line];
+       unsigned long flags;
+       
+       if (info->flags & S_INITIALIZED)
+               return 0;
+
+       if (!info->xmit_buf) {
+               info->xmit_buf = (unsigned char *) __get_free_page(GFP_KERNEL);
+               if (!info->xmit_buf)
+                       return -ENOMEM;
+       }
+
+       local_irq_save(flags);
+
+       /*
+        * Clear the FIFO buffers and disable them
+        * (they will be reenabled in change_speed())
+        */
+
+       uart->ustcnt = USTCNT_UEN;
+       info->xmit_fifo_size = 1;
+       uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_TXEN;
+       (void)uart->urx.w;
+
+       /*
+        * Finally, enable sequencing and interrupts
+        */
+#ifdef USE_INTS
+       uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | 
+                 USTCNT_RX_INTR_MASK | USTCNT_TX_INTR_MASK;
+#else
+       uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK;
+#endif
+
+       if (info->port.tty)
+               clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
+       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+       /*
+        * and set the speed of the serial port
+        */
+
+       change_speed(info);
+
+       info->flags |= S_INITIALIZED;
+       local_irq_restore(flags);
+       return 0;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(struct m68k_serial * info)
+{
+       m68328_uart *uart = &uart_addr[info->line];
+       unsigned long   flags;
+
+       uart->ustcnt = 0; /* All off! */
+       if (!(info->flags & S_INITIALIZED))
+               return;
+
+       local_irq_save(flags);
+       
+       if (info->xmit_buf) {
+               free_page((unsigned long) info->xmit_buf);
+               info->xmit_buf = 0;
+       }
+
+       if (info->port.tty)
+               set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+       
+       info->flags &= ~S_INITIALIZED;
+       local_irq_restore(flags);
+}
+
+struct {
+       int divisor, prescale;
+}
+#ifndef CONFIG_M68VZ328
+ hw_baud_table[18] = {
+       {0,0}, /* 0 */
+       {0,0}, /* 50 */
+       {0,0}, /* 75 */
+       {0,0}, /* 110 */
+       {0,0}, /* 134 */
+       {0,0}, /* 150 */
+       {0,0}, /* 200 */
+       {7,0x26}, /* 300 */
+       {6,0x26}, /* 600 */
+       {5,0x26}, /* 1200 */
+       {0,0}, /* 1800 */
+       {4,0x26}, /* 2400 */
+       {3,0x26}, /* 4800 */
+       {2,0x26}, /* 9600 */
+       {1,0x26}, /* 19200 */
+       {0,0x26}, /* 38400 */
+       {1,0x38}, /* 57600 */
+       {0,0x38}, /* 115200 */
+};
+#else
+ hw_baud_table[18] = {
+                 {0,0}, /* 0 */
+                 {0,0}, /* 50 */
+                 {0,0}, /* 75 */
+                 {0,0}, /* 110 */
+                 {0,0}, /* 134 */
+                 {0,0}, /* 150 */
+                 {0,0}, /* 200 */
+                 {0,0}, /* 300 */
+                 {7,0x26}, /* 600 */
+                 {6,0x26}, /* 1200 */
+                 {0,0}, /* 1800 */
+                 {5,0x26}, /* 2400 */
+                 {4,0x26}, /* 4800 */
+                 {3,0x26}, /* 9600 */
+                 {2,0x26}, /* 19200 */
+                 {1,0x26}, /* 38400 */
+                 {0,0x26}, /* 57600 */
+                 {1,0x38}, /* 115200 */
+}; 
+#endif
+/* rate = 1036800 / ((65 - prescale) * (1<<divider)) */
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void change_speed(struct m68k_serial *info)
+{
+       m68328_uart *uart = &uart_addr[info->line];
+       unsigned short port;
+       unsigned short ustcnt;
+       unsigned cflag;
+       int     i;
+
+       if (!info->port.tty || !info->port.tty->termios)
+               return;
+       cflag = info->port.tty->termios->c_cflag;
+       if (!(port = info->port))
+               return;
+
+       ustcnt = uart->ustcnt;
+       uart->ustcnt = ustcnt & ~USTCNT_TXEN;
+
+       i = cflag & CBAUD;
+        if (i & CBAUDEX) {
+                i = (i & ~CBAUDEX) + B38400;
+        }
+
+       info->baud = baud_table[i];
+       uart->ubaud = PUT_FIELD(UBAUD_DIVIDE,    hw_baud_table[i].divisor) | 
+               PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale);
+
+       ustcnt &= ~(USTCNT_PARITYEN | USTCNT_ODD_EVEN | USTCNT_STOP | USTCNT_8_7);
+       
+       if ((cflag & CSIZE) == CS8)
+               ustcnt |= USTCNT_8_7;
+               
+       if (cflag & CSTOPB)
+               ustcnt |= USTCNT_STOP;
+
+       if (cflag & PARENB)
+               ustcnt |= USTCNT_PARITYEN;
+       if (cflag & PARODD)
+               ustcnt |= USTCNT_ODD_EVEN;
+       
+#ifdef CONFIG_SERIAL_68328_RTS_CTS
+       if (cflag & CRTSCTS) {
+               uart->utx.w &= ~ UTX_NOCTS;
+       } else {
+               uart->utx.w |= UTX_NOCTS;
+       }
+#endif
+
+       ustcnt |= USTCNT_TXEN;
+       
+       uart->ustcnt = ustcnt;
+       return;
+}
+
+/*
+ * Fair output driver allows a process to speak.
+ */
+static void rs_fair_output(void)
+{
+       int left;               /* Output no more than that */
+       unsigned long flags;
+       struct m68k_serial *info = &m68k_soft[0];
+       char c;
+
+       if (info == 0) return;
+       if (info->xmit_buf == 0) return;
+
+       local_irq_save(flags);
+       left = info->xmit_cnt;
+       while (left != 0) {
+               c = info->xmit_buf[info->xmit_tail];
+               info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
+               info->xmit_cnt--;
+               local_irq_restore(flags);
+
+               rs_put_char(c);
+
+               local_irq_save(flags);
+               left = min(info->xmit_cnt, left-1);
+       }
+
+       /* Last character is being transmitted now (hopefully). */
+       udelay(5);
+
+       local_irq_restore(flags);
+       return;
+}
+
+/*
+ * m68k_console_print is registered for printk.
+ */
+void console_print_68328(const char *p)
+{
+       char c;
+       
+       while((c=*(p++)) != 0) {
+               if(c == '\n')
+                       rs_put_char('\r');
+               rs_put_char(c);
+       }
+
+       /* Comment this if you want to have a strict interrupt-driven output */
+       rs_fair_output();
+
+       return;
+}
+
+static void rs_set_ldisc(struct tty_struct *tty)
+{
+       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+
+       if (serial_paranoia_check(info, tty->name, "rs_set_ldisc"))
+               return;
+
+       info->is_cons = (tty->termios->c_line == N_TTY);
+       
+       printk("ttyS%d console mode %s\n", info->line, info->is_cons ? "on" : "off");
+}
+
+static void rs_flush_chars(struct tty_struct *tty)
+{
+       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+       m68328_uart *uart = &uart_addr[info->line];
+       unsigned long flags;
+
+       if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
+               return;
+#ifndef USE_INTS
+       for(;;) {
+#endif
+
+       /* Enable transmitter */
+       local_irq_save(flags);
+
+       if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+                       !info->xmit_buf) {
+               local_irq_restore(flags);
+               return;
+       }
+
+#ifdef USE_INTS
+       uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK;
+#else
+       uart->ustcnt |= USTCNT_TXEN;
+#endif
+
+#ifdef USE_INTS
+       if (uart->utx.w & UTX_TX_AVAIL) {
+#else
+       if (1) {
+#endif
+               /* Send char */
+               uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
+               info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+               info->xmit_cnt--;
+       }
+
+#ifndef USE_INTS
+       while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5);
+       }
+#endif
+       local_irq_restore(flags);
+}
+
+extern void console_printn(const char * b, int count);
+
+static int rs_write(struct tty_struct * tty,
+                   const unsigned char *buf, int count)
+{
+       int     c, total = 0;
+       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+       m68328_uart *uart = &uart_addr[info->line];
+       unsigned long flags;
+
+       if (serial_paranoia_check(info, tty->name, "rs_write"))
+               return 0;
+
+       if (!tty || !info->xmit_buf)
+               return 0;
+
+       local_save_flags(flags);
+       while (1) {
+               local_irq_disable();            
+               c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                                  SERIAL_XMIT_SIZE - info->xmit_head));
+               local_irq_restore(flags);
+
+               if (c <= 0)
+                       break;
+
+               memcpy(info->xmit_buf + info->xmit_head, buf, c);
+
+               local_irq_disable();
+               info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+               info->xmit_cnt += c;
+               local_irq_restore(flags);
+               buf += c;
+               count -= c;
+               total += c;
+       }
+
+       if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
+               /* Enable transmitter */
+               local_irq_disable();            
+#ifndef USE_INTS
+               while(info->xmit_cnt) {
+#endif
+
+               uart->ustcnt |= USTCNT_TXEN;
+#ifdef USE_INTS
+               uart->ustcnt |= USTCNT_TX_INTR_MASK;
+#else
+               while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5);
+#endif
+               if (uart->utx.w & UTX_TX_AVAIL) {
+                       uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
+                       info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+                       info->xmit_cnt--;
+               }
+
+#ifndef USE_INTS
+               }
+#endif
+               local_irq_restore(flags);
+       }
+
+       return total;
+}
+
+static int rs_write_room(struct tty_struct *tty)
+{
+       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+       int     ret;
+                               
+       if (serial_paranoia_check(info, tty->name, "rs_write_room"))
+               return 0;
+       ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+       if (ret < 0)
+               ret = 0;
+       return ret;
+}
+
+static int rs_chars_in_buffer(struct tty_struct *tty)
+{
+       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+                               
+       if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
+               return 0;
+       return info->xmit_cnt;
+}
+
+static void rs_flush_buffer(struct tty_struct *tty)
+{
+       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+       unsigned long flags;
+                               
+       if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
+               return;
+       local_irq_save(flags);
+       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+       local_irq_restore(flags);
+       tty_wakeup(tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ * 
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void rs_throttle(struct tty_struct * tty)
+{
+       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+
+       if (serial_paranoia_check(info, tty->name, "rs_throttle"))
+               return;
+       
+       if (I_IXOFF(tty))
+               info->x_char = STOP_CHAR(tty);
+
+       /* Turn off RTS line (do this atomic) */
+}
+
+static void rs_unthrottle(struct tty_struct * tty)
+{
+       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+
+       if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
+               return;
+       
+       if (I_IXOFF(tty)) {
+               if (info->x_char)
+                       info->x_char = 0;
+               else
+                       info->x_char = START_CHAR(tty);
+       }
+
+       /* Assert RTS line (do this atomic) */
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static int get_serial_info(struct m68k_serial * info,
+                          struct serial_struct * retinfo)
+{
+       struct serial_struct tmp;
+  
+       if (!retinfo)
+               return -EFAULT;
+       memset(&tmp, 0, sizeof(tmp));
+       tmp.type = info->type;
+       tmp.line = info->line;
+       tmp.port = info->port;
+       tmp.irq = info->irq;
+       tmp.flags = info->flags;
+       tmp.baud_base = info->baud_base;
+       tmp.close_delay = info->close_delay;
+       tmp.closing_wait = info->closing_wait;
+       tmp.custom_divisor = info->custom_divisor;
+       if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int set_serial_info(struct m68k_serial * info,
+                          struct serial_struct * new_info)
+{
+       struct serial_struct new_serial;
+       struct m68k_serial old_info;
+       int                     retval = 0;
+
+       if (!new_info)
+               return -EFAULT;
+       if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
+               return -EFAULT;
+       old_info = *info;
+
+       if (!capable(CAP_SYS_ADMIN)) {
+               if ((new_serial.baud_base != info->baud_base) ||
+                   (new_serial.type != info->type) ||
+                   (new_serial.close_delay != info->close_delay) ||
+                   ((new_serial.flags & ~S_USR_MASK) !=
+                    (info->flags & ~S_USR_MASK)))
+                       return -EPERM;
+               info->flags = ((info->flags & ~S_USR_MASK) |
+                              (new_serial.flags & S_USR_MASK));
+               info->custom_divisor = new_serial.custom_divisor;
+               goto check_and_exit;
+       }
+
+       if (info->count > 1)
+               return -EBUSY;
+
+       /*
+        * OK, past this point, all the error checking has been done.
+        * At this point, we start making changes.....
+        */
+
+       info->baud_base = new_serial.baud_base;
+       info->flags = ((info->flags & ~S_FLAGS) |
+                       (new_serial.flags & S_FLAGS));
+       info->type = new_serial.type;
+       info->close_delay = new_serial.close_delay;
+       info->closing_wait = new_serial.closing_wait;
+
+check_and_exit:
+       retval = startup(info);
+       return retval;
+}
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ *         is emptied.  On bus types like RS485, the transmitter must
+ *         release the bus after transmitting. This must be done when
+ *         the transmit shift register is empty, not be done when the
+ *         transmit holding register is empty.  This functionality
+ *         allows an RS485 driver to be written in user space. 
+ */
+static int get_lsr_info(struct m68k_serial * info, unsigned int *value)
+{
+#ifdef CONFIG_SERIAL_68328_RTS_CTS
+       m68328_uart *uart = &uart_addr[info->line];
+#endif
+       unsigned char status;
+       unsigned long flags;
+
+       local_irq_save(flags);
+#ifdef CONFIG_SERIAL_68328_RTS_CTS
+       status = (uart->utx.w & UTX_CTS_STAT) ? 1 : 0;
+#else
+       status = 0;
+#endif
+       local_irq_restore(flags);
+       return put_user(status, value);
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void send_break(struct m68k_serial * info, unsigned int duration)
+{
+       m68328_uart *uart = &uart_addr[info->line];
+        unsigned long flags;
+        if (!info->port)
+                return;
+        local_irq_save(flags);
+#ifdef USE_INTS        
+       uart->utx.w |= UTX_SEND_BREAK;
+       msleep_interruptible(duration);
+       uart->utx.w &= ~UTX_SEND_BREAK;
+#endif         
+        local_irq_restore(flags);
+}
+
+static int rs_ioctl(struct tty_struct *tty, struct file * file,
+                   unsigned int cmd, unsigned long arg)
+{
+       int error;
+       struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
+       int retval;
+
+       if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
+               return -ENODEV;
+
+       if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+           (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
+           (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
+               if (tty->flags & (1 << TTY_IO_ERROR))
+                   return -EIO;
+       }
+       
+       switch (cmd) {
+               case TCSBRK:    /* SVID version: non-zero arg --> no break */
+                       retval = tty_check_change(tty);
+                       if (retval)
+                               return retval;
+                       tty_wait_until_sent(tty, 0);
+                       if (!arg)
+                               send_break(info, 250);  /* 1/4 second */
+                       return 0;
+               case TCSBRKP:   /* support for POSIX tcsendbreak() */
+                       retval = tty_check_change(tty);
+                       if (retval)
+                               return retval;
+                       tty_wait_until_sent(tty, 0);
+                       send_break(info, arg ? arg*(100) : 250);
+                       return 0;
+               case TIOCGSERIAL:
+                       return get_serial_info(info,
+                                      (struct serial_struct *) arg);
+               case TIOCSSERIAL:
+                       return set_serial_info(info,
+                                              (struct serial_struct *) arg);
+               case TIOCSERGETLSR: /* Get line status register */
+                       return get_lsr_info(info, (unsigned int *) arg);
+               case TIOCSERGSTRUCT:
+                       if (copy_to_user((struct m68k_serial *) arg,
+                                   info, sizeof(struct m68k_serial)))
+                               return -EFAULT;
+                       return 0;
+               default:
+                       return -ENOIOCTLCMD;
+               }
+       return 0;
+}
+
+static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+{
+       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+
+       change_speed(info);
+
+       if ((old_termios->c_cflag & CRTSCTS) &&
+           !(tty->termios->c_cflag & CRTSCTS)) {
+               tty->hw_stopped = 0;
+               rs_start(tty);
+       }
+       
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ * 
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * S structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void rs_close(struct tty_struct *tty, struct file * filp)
+{
+       struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
+       m68328_uart *uart = &uart_addr[info->line];
+       unsigned long flags;
+
+       if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
+               return;
+       
+       local_irq_save(flags);
+       
+       if (tty_hung_up_p(filp)) {
+               local_irq_restore(flags);
+               return;
+       }
+       
+       if ((tty->count == 1) && (info->count != 1)) {
+               /*
+                * Uh, oh.  tty->count is 1, which means that the tty
+                * structure will be freed.  Info->count should always
+                * be one in these conditions.  If it's greater than
+                * one, we've got real problems, since it means the
+                * serial port won't be shutdown.
+                */
+               printk("rs_close: bad serial port count; tty->count is 1, "
+                      "info->count is %d\n", info->count);
+               info->count = 1;
+       }
+       if (--info->count < 0) {
+               printk("rs_close: bad serial port count for ttyS%d: %d\n",
+                      info->line, info->count);
+               info->count = 0;
+       }
+       if (info->count) {
+               local_irq_restore(flags);
+               return;
+       }
+       info->flags |= S_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 (info->closing_wait != S_CLOSING_WAIT_NONE)
+               tty_wait_until_sent(tty, info->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.
+        */
+
+       uart->ustcnt &= ~USTCNT_RXEN;
+       uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK);
+
+       shutdown(info);
+       rs_flush_buffer(tty);
+               
+       tty_ldisc_flush(tty);
+       tty->closing = 0;
+       info->event = 0;
+       info->port.tty = NULL;
+#warning "This is not and has never been valid so fix it"      
+#if 0
+       if (tty->ldisc.num != ldiscs[N_TTY].num) {
+               if (tty->ldisc.close)
+                       (tty->ldisc.close)(tty);
+               tty->ldisc = ldiscs[N_TTY];
+               tty->termios->c_line = N_TTY;
+               if (tty->ldisc.open)
+                       (tty->ldisc.open)(tty);
+       }
+#endif 
+       if (info->blocked_open) {
+               if (info->close_delay) {
+                       msleep_interruptible(jiffies_to_msecs(info->close_delay));
+               }
+               wake_up_interruptible(&info->open_wait);
+       }
+       info->flags &= ~(S_NORMAL_ACTIVE|S_CLOSING);
+       wake_up_interruptible(&info->close_wait);
+       local_irq_restore(flags);
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+void rs_hangup(struct tty_struct *tty)
+{
+       struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
+       
+       if (serial_paranoia_check(info, tty->name, "rs_hangup"))
+               return;
+       
+       rs_flush_buffer(tty);
+       shutdown(info);
+       info->event = 0;
+       info->count = 0;
+       info->flags &= ~S_NORMAL_ACTIVE;
+       info->port.tty = NULL;
+       wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+                          struct m68k_serial *info)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       int             retval;
+       int             do_clocal = 0;
+
+       /*
+        * If the device is in the middle of being closed, then block
+        * until it's done, and then try again.
+        */
+       if (info->flags & S_CLOSING) {
+               interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+               if (info->flags & S_HUP_NOTIFY)
+                       return -EAGAIN;
+               else
+                       return -ERESTARTSYS;
+#else
+               return -EAGAIN;
+#endif
+       }
+       
+       /*
+        * 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))) {
+               info->flags |= S_NORMAL_ACTIVE;
+               return 0;
+       }
+
+       if (tty->termios->c_cflag & CLOCAL)
+               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, info->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(&info->open_wait, &wait);
+
+       info->count--;
+       info->blocked_open++;
+       while (1) {
+               local_irq_disable();
+               m68k_rtsdtr(info, 1);
+               local_irq_enable();
+               current->state = TASK_INTERRUPTIBLE;
+               if (tty_hung_up_p(filp) ||
+                   !(info->flags & S_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+                       if (info->flags & S_HUP_NOTIFY)
+                               retval = -EAGAIN;
+                       else
+                               retval = -ERESTARTSYS;  
+#else
+                       retval = -EAGAIN;
+#endif
+                       break;
+               }
+               if (!(info->flags & S_CLOSING) && do_clocal)
+                       break;
+                if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+                       break;
+               }
+               tty_unlock();
+               schedule();
+               tty_lock();
+       }
+       current->state = TASK_RUNNING;
+       remove_wait_queue(&info->open_wait, &wait);
+       if (!tty_hung_up_p(filp))
+               info->count++;
+       info->blocked_open--;
+
+       if (retval)
+               return retval;
+       info->flags |= S_NORMAL_ACTIVE;
+       return 0;
+}      
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its S structure into
+ * the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+int rs_open(struct tty_struct *tty, struct file * filp)
+{
+       struct m68k_serial      *info;
+       int                     retval, line;
+
+       line = tty->index;
+       
+       if (line >= NR_PORTS || line < 0) /* we have exactly one */
+               return -ENODEV;
+
+       info = &m68k_soft[line];
+
+       if (serial_paranoia_check(info, tty->name, "rs_open"))
+               return -ENODEV;
+
+       info->count++;
+       tty->driver_data = info;
+       info->port.tty = tty;
+
+       /*
+        * Start up serial port
+        */
+       retval = startup(info);
+       if (retval)
+               return retval;
+
+       return block_til_ready(tty, filp, info);
+}
+
+/* Finally, routines used to initialize the serial driver. */
+
+static void show_serial_version(void)
+{
+       printk("MC68328 serial driver version 1.00\n");
+}
+
+static const struct tty_operations rs_ops = {
+       .open = rs_open,
+       .close = rs_close,
+       .write = rs_write,
+       .flush_chars = rs_flush_chars,
+       .write_room = rs_write_room,
+       .chars_in_buffer = rs_chars_in_buffer,
+       .flush_buffer = rs_flush_buffer,
+       .ioctl = rs_ioctl,
+       .throttle = rs_throttle,
+       .unthrottle = rs_unthrottle,
+       .set_termios = rs_set_termios,
+       .stop = rs_stop,
+       .start = rs_start,
+       .hangup = rs_hangup,
+       .set_ldisc = rs_set_ldisc,
+};
+
+/* rs_init inits the driver */
+static int __init
+rs68328_init(void)
+{
+       int flags, i;
+       struct m68k_serial *info;
+
+       serial_driver = alloc_tty_driver(NR_PORTS);
+       if (!serial_driver)
+               return -ENOMEM;
+
+       show_serial_version();
+
+       /* Initialize the tty_driver structure */
+       /* SPARC: Not all of this is exactly right for us. */
+       
+       serial_driver->name = "ttyS";
+       serial_driver->major = TTY_MAJOR;
+       serial_driver->minor_start = 64;
+       serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
+       serial_driver->subtype = SERIAL_TYPE_NORMAL;
+       serial_driver->init_termios = tty_std_termios;
+       serial_driver->init_termios.c_cflag = 
+                       m68328_console_cbaud | CS8 | CREAD | HUPCL | CLOCAL;
+       serial_driver->flags = TTY_DRIVER_REAL_RAW;
+       tty_set_operations(serial_driver, &rs_ops);
+
+       if (tty_register_driver(serial_driver)) {
+               put_tty_driver(serial_driver);
+               printk(KERN_ERR "Couldn't register serial driver\n");
+               return -ENOMEM;
+       }
+
+       local_irq_save(flags);
+
+       for(i=0;i<NR_PORTS;i++) {
+
+           info = &m68k_soft[i];
+           info->magic = SERIAL_MAGIC;
+           info->port = (int) &uart_addr[i];
+           info->port.tty = NULL;
+           info->irq = uart_irqs[i];
+           info->custom_divisor = 16;
+           info->close_delay = 50;
+           info->closing_wait = 3000;
+           info->x_char = 0;
+           info->event = 0;
+           info->count = 0;
+           info->blocked_open = 0;
+           INIT_WORK(&info->tqueue, do_softint);
+           INIT_WORK(&info->tqueue_hangup, do_serial_hangup);
+           init_waitqueue_head(&info->open_wait);
+           init_waitqueue_head(&info->close_wait);
+           info->line = i;
+           info->is_cons = 1; /* Means shortcuts work */
+           
+           printk("%s%d at 0x%08x (irq = %d)", serial_driver->name, info->line, 
+                  info->port, info->irq);
+           printk(" is a builtin MC68328 UART\n");
+           
+#ifdef CONFIG_M68VZ328
+               if (i > 0 )
+                       PJSEL &= 0xCF;  /* PSW enable second port output */
+#endif
+
+           if (request_irq(uart_irqs[i],
+                           rs_interrupt,
+                           IRQF_DISABLED,
+                           "M68328_UART", info))
+                panic("Unable to attach 68328 serial interrupt\n");
+       }
+       local_irq_restore(flags);
+       return 0;
+}
+
+module_init(rs68328_init);
+
+
+
+static void m68328_set_baud(void)
+{
+       unsigned short ustcnt;
+       int     i;
+
+       ustcnt = USTCNT;
+       USTCNT = ustcnt & ~USTCNT_TXEN;
+
+again:
+       for (i = 0; i < ARRAY_SIZE(baud_table); i++)
+               if (baud_table[i] == m68328_console_baud)
+                       break;
+       if (i >= ARRAY_SIZE(baud_table)) {
+               m68328_console_baud = 9600;
+               goto again;
+       }
+
+       UBAUD = PUT_FIELD(UBAUD_DIVIDE,    hw_baud_table[i].divisor) | 
+               PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale);
+       ustcnt &= ~(USTCNT_PARITYEN | USTCNT_ODD_EVEN | USTCNT_STOP | USTCNT_8_7);
+       ustcnt |= USTCNT_8_7;
+       ustcnt |= USTCNT_TXEN;
+       USTCNT = ustcnt;
+       m68328_console_initted = 1;
+       return;
+}
+
+
+int m68328_console_setup(struct console *cp, char *arg)
+{
+       int             i, n = CONSOLE_BAUD_RATE;
+
+       if (!cp)
+               return(-1);
+
+       if (arg)
+               n = simple_strtoul(arg,NULL,0);
+
+       for (i = 0; i < ARRAY_SIZE(baud_table); i++)
+               if (baud_table[i] == n)
+                       break;
+       if (i < ARRAY_SIZE(baud_table)) {
+               m68328_console_baud = n;
+               m68328_console_cbaud = 0;
+               if (i > 15) {
+                       m68328_console_cbaud |= CBAUDEX;
+                       i -= 15;
+               }
+               m68328_console_cbaud |= i;
+       }
+
+       m68328_set_baud(); /* make sure baud rate changes */
+       return(0);
+}
+
+
+static struct tty_driver *m68328_console_device(struct console *c, int *index)
+{
+       *index = c->index;
+       return serial_driver;
+}
+
+
+void m68328_console_write (struct console *co, const char *str,
+                          unsigned int count)
+{
+       if (!m68328_console_initted)
+               m68328_set_baud();
+    while (count--) {
+        if (*str == '\n')
+           rs_put_char('\r');
+        rs_put_char( *str++ );
+    }
+}
+
+
+static struct console m68328_driver = {
+       .name           = "ttyS",
+       .write          = m68328_console_write,
+       .device         = m68328_console_device,
+       .setup          = m68328_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+};
+
+
+static int __init m68328_console_init(void)
+{
+       register_console(&m68328_driver);
+       return 0;
+}
+
+console_initcall(m68328_console_init);
diff --git a/drivers/tty/serial/68328serial.h b/drivers/tty/serial/68328serial.h
new file mode 100644 (file)
index 0000000..664ceb0
--- /dev/null
@@ -0,0 +1,188 @@
+/* 68328serial.h: Definitions for the mc68328 serial driver.
+ *
+ * Copyright (C) 1995       David S. Miller    <davem@caip.rutgers.edu>
+ * Copyright (C) 1998       Kenneth Albanowski <kjahds@kjahds.com>
+ * Copyright (C) 1998, 1999 D. Jeff Dionne     <jeff@uclinux.org>
+ * Copyright (C) 1999       Vladimir Gurevich  <vgurevic@cisco.com>
+ *
+ * VZ Support/Fixes             Evan Stawnyczy <e@lineo.ca>
+ */
+
+#ifndef _MC683XX_SERIAL_H
+#define _MC683XX_SERIAL_H
+
+
+struct serial_struct {
+       int     type;
+       int     line;
+       int     port;
+       int     irq;
+       int     flags;
+       int     xmit_fifo_size;
+       int     custom_divisor;
+       int     baud_base;
+       unsigned short  close_delay;
+       char    reserved_char[2];
+       int     hub6;  /* FIXME: We don't have AT&T Hub6 boards! */
+       unsigned short  closing_wait; /* time to wait before closing */
+       unsigned short  closing_wait2; /* no longer used... */
+       int     reserved[4];
+};
+
+/*
+ * For the close wait times, 0 means wait forever for serial port to
+ * flush its output.  65535 means don't wait at all.
+ */
+#define S_CLOSING_WAIT_INF     0
+#define S_CLOSING_WAIT_NONE    65535
+
+/*
+ * Definitions for S_struct (and serial_struct) flags field
+ */
+#define S_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes 
+                                  on the callout port */
+#define S_FOURPORT  0x0002     /* Set OU1, OUT2 per AST Fourport settings */
+#define S_SAK  0x0004  /* Secure Attention Key (Orange book) */
+#define S_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
+
+#define S_SPD_MASK     0x0030
+#define S_SPD_HI       0x0010  /* Use 56000 instead of 38400 bps */
+
+#define S_SPD_VHI      0x0020  /* Use 115200 instead of 38400 bps */
+#define S_SPD_CUST     0x0030  /* Use user-specified divisor */
+
+#define S_SKIP_TEST    0x0040 /* Skip UART test during autoconfiguration */
+#define S_AUTO_IRQ  0x0080 /* Do automatic IRQ during autoconfiguration */
+#define S_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
+#define S_PGRP_LOCKOUT    0x0200 /* Lock out cua opens based on pgrp */
+#define S_CALLOUT_NOHUP   0x0400 /* Don't do hangups for cua device */
+
+#define S_FLAGS        0x0FFF  /* Possible legal S flags */
+#define S_USR_MASK 0x0430      /* Legal flags that non-privileged
+                                * users can set or reset */
+
+/* Internal flags used only by kernel/chr_drv/serial.c */
+#define S_INITIALIZED  0x80000000 /* Serial port was initialized */
+#define S_CALLOUT_ACTIVE       0x40000000 /* Call out device is active */
+#define S_NORMAL_ACTIVE        0x20000000 /* Normal device is active */
+#define S_BOOT_AUTOCONF        0x10000000 /* Autoconfigure port on bootup */
+#define S_CLOSING              0x08000000 /* Serial port is closing */
+#define S_CTS_FLOW             0x04000000 /* Do CTS flow control */
+#define S_CHECK_CD             0x02000000 /* i.e., CLOCAL */
+
+/* Software state per channel */
+
+#ifdef __KERNEL__
+
+/*
+ * I believe this is the optimal setting that reduces the number of interrupts.
+ * At high speeds the output might become a little "bursted" (use USTCNT_TXHE
+ * if that bothers you), but in most cases it will not, since we try to 
+ * transmit characters every time rs_interrupt is called. Thus, quite often
+ * you'll see that a receive interrupt occures before the transmit one.
+ *                                  -- Vladimir Gurevich
+ */
+#define USTCNT_TX_INTR_MASK (USTCNT_TXEE)
+
+/*
+ * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special
+ * "Old data interrupt" which occures whenever the data stay in the FIFO
+ * longer than 30 bits time. This allows us to use FIFO without compromising
+ * latency. '328 does not have this feature and without the real  328-based
+ * board I would assume that RXRE is the safest setting.
+ *
+ * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of
+ * interrupts. RXFE (receive queue full) causes the system to lose data
+ * at least at 115200 baud
+ *
+ * If your board is busy doing other stuff, you might consider to use
+ * RXRE (data ready intrrupt) instead.
+ *
+ * The other option is to make these INTR masks run-time configurable, so
+ * that people can dynamically adapt them according to the current usage.
+ *                                  -- Vladimir Gurevich
+ */
+
+/* (es) */
+#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328)
+#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN)
+#elif defined(CONFIG_M68328)
+#define USTCNT_RX_INTR_MASK (USTCNT_RXRE)
+#else
+#error Please, define the Rx interrupt events for your CPU
+#endif
+/* (/es) */
+
+/*
+ * This is our internal structure for each serial port's state.
+ * 
+ * Many fields are paralleled by the structure used by the serial_struct
+ * structure.
+ *
+ * For definitions of the flags field, see tty.h
+ */
+
+struct m68k_serial {
+       char soft_carrier;  /* Use soft carrier on this channel */
+       char break_abort;   /* Is serial console in, so process brk/abrt */
+       char is_cons;       /* Is this our console. */
+
+       /* We need to know the current clock divisor
+        * to read the bps rate the chip has currently
+        * loaded.
+        */
+       unsigned char clk_divisor;  /* May be 1, 16, 32, or 64 */
+       int baud;
+       int                     magic;
+       int                     baud_base;
+       int                     port;
+       int                     irq;
+       int                     flags;          /* defined in tty.h */
+       int                     type;           /* UART type */
+       struct tty_struct       *tty;
+       int                     read_status_mask;
+       int                     ignore_status_mask;
+       int                     timeout;
+       int                     xmit_fifo_size;
+       int                     custom_divisor;
+       int                     x_char; /* xon/xoff character */
+       int                     close_delay;
+       unsigned short          closing_wait;
+       unsigned short          closing_wait2;
+       unsigned long           event;
+       unsigned long           last_active;
+       int                     line;
+       int                     count;      /* # of fd on device */
+       int                     blocked_open; /* # of blocked opens */
+       unsigned char           *xmit_buf;
+       int                     xmit_head;
+       int                     xmit_tail;
+       int                     xmit_cnt;
+       struct work_struct      tqueue;
+       struct work_struct      tqueue_hangup;
+       wait_queue_head_t       open_wait;
+       wait_queue_head_t       close_wait;
+};
+
+
+#define SERIAL_MAGIC 0x5301
+
+/*
+ * The size of the serial xmit buffer is 1 page, or 4096 bytes
+ */
+#define SERIAL_XMIT_SIZE 4096
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at rs interrupt time.
+ */
+#define RS_EVENT_WRITE_WAKEUP  0
+
+/* 
+ * Define the number of ports supported and their irqs.
+ */
+#define NR_PORTS 1
+#define UART_IRQ_DEFNS {UART_IRQ_NUM}
+
+#endif /* __KERNEL__ */
+#endif /* !(_MC683XX_SERIAL_H) */
diff --git a/drivers/tty/serial/68360serial.c b/drivers/tty/serial/68360serial.c
new file mode 100644 (file)
index 0000000..88b1335
--- /dev/null
@@ -0,0 +1,2978 @@
+/*
+ *  UART driver for 68360 CPM SCC or SMC
+ *  Copyright (c) 2000 D. Jeff Dionne <jeff@uclinux.org>,
+ *  Copyright (c) 2000 Michael Leslie <mleslie@lineo.ca>
+ *  Copyright (c) 1997 Dan Malek <dmalek@jlc.net>
+ *
+ * I used the serial.c driver as the framework for this driver.
+ * Give credit to those guys.
+ * The original code was written for the MBX860 board.  I tried to make
+ * it generic, but there may be some assumptions in the structures that
+ * have to be fixed later.
+ * To save porting time, I did not bother to change any object names
+ * that are not accessed outside of this file.
+ * It still needs lots of work........When it was easy, I included code
+ * to support the SCCs, but this has never been tested, nor is it complete.
+ * Only the SCCs support modem control, so that is not complete either.
+ *
+ * This module exports the following rs232 io functions:
+ *
+ *     int rs_360_init(void);
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serialP.h> 
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/irq.h>
+#include <asm/m68360.h>
+#include <asm/commproc.h>
+
+#ifdef CONFIG_KGDB
+extern void breakpoint(void);
+extern void set_debug_traps(void);
+extern int  kgdb_output_string (const char* s, unsigned int count);
+#endif
+
+
+/* #ifdef CONFIG_SERIAL_CONSOLE */ /* This seems to be a post 2.0 thing - mles */
+#include <linux/console.h>
+#include <linux/jiffies.h>
+
+/* this defines the index into rs_table for the port to use
+ */
+#ifndef CONFIG_SERIAL_CONSOLE_PORT
+#define CONFIG_SERIAL_CONSOLE_PORT     1 /* ie SMC2 - note USE_SMC2 must be defined */
+#endif
+/* #endif */
+
+#if 0
+/* SCC2 for console
+ */
+#undef CONFIG_SERIAL_CONSOLE_PORT
+#define CONFIG_SERIAL_CONSOLE_PORT     2
+#endif
+
+
+#define TX_WAKEUP      ASYNC_SHARE_IRQ
+
+static char *serial_name = "CPM UART driver";
+static char *serial_version = "0.03";
+
+static struct tty_driver *serial_driver;
+int serial_console_setup(struct console *co, char *options);
+
+/*
+ * Serial driver configuration section.  Here are the various options:
+ */
+#define SERIAL_PARANOIA_CHECK
+#define CONFIG_SERIAL_NOPAUSE_IO
+#define SERIAL_DO_RESTART
+
+/* Set of debugging defines */
+
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+
+#define _INLINE_ inline
+  
+#define DBG_CNT(s)
+
+/* We overload some of the items in the data structure to meet our
+ * needs.  For example, the port address is the CPM parameter ram
+ * offset for the SCC or SMC.  The maximum number of ports is 4 SCCs and
+ * 2 SMCs.  The "hub6" field is used to indicate the channel number, with
+ * a flag indicating SCC or SMC, and the number is used as an index into
+ * the CPM parameter area for this device.
+ * The "type" field is currently set to 0, for PORT_UNKNOWN.  It is
+ * not currently used.  I should probably use it to indicate the port
+ * type of SMC or SCC.
+ * The SMCs do not support any modem control signals.
+ */
+#define smc_scc_num    hub6
+#define NUM_IS_SCC     ((int)0x00010000)
+#define PORT_NUM(P)    ((P) & 0x0000ffff)
+
+
+#if defined (CONFIG_UCQUICC)
+
+volatile extern void *_periph_base;
+/* sipex transceiver
+ *   mode bits for       are on pins
+ *
+ *    SCC2                d16..19
+ *    SCC3                d20..23
+ *    SCC4                d24..27
+ */
+#define SIPEX_MODE(n,m) ((m & 0x0f)<<(16+4*(n-1)))
+
+static uint sipex_mode_bits = 0x00000000;
+
+#endif
+
+/* There is no `serial_state' defined back here in 2.0.
+ * Try to get by with serial_struct
+ */
+/* #define serial_state serial_struct */
+
+/* 2.4 -> 2.0 portability problem: async_icount in 2.4 has a few
+ * extras: */
+
+#if 0
+struct async_icount_24 {
+       __u32   cts, dsr, rng, dcd, tx, rx;
+       __u32   frame, parity, overrun, brk;
+       __u32   buf_overrun;
+} icount;
+#endif
+
+#if 0
+
+struct serial_state {
+        int     magic;
+        int     baud_base;
+        unsigned long   port;
+        int     irq;
+        int     flags;
+        int     hub6;
+        int     type;
+        int     line;
+        int     revision;       /* Chip revision (950) */
+        int     xmit_fifo_size;
+        int     custom_divisor;
+        int     count;
+        u8      *iomem_base;
+        u16     iomem_reg_shift;
+        unsigned short  close_delay;
+        unsigned short  closing_wait; /* time to wait before closing */
+        struct async_icount_24     icount; 
+        int     io_type;
+        struct async_struct *info;
+};
+#endif
+
+#define SSTATE_MAGIC 0x5302
+
+
+
+/* SMC2 is sometimes used for low performance TDM interfaces.  Define
+ * this as 1 if you want SMC2 as a serial port UART managed by this driver.
+ * Define this as 0 if you wish to use SMC2 for something else.
+ */
+#define USE_SMC2 1
+
+#if 0
+/* Define SCC to ttySx mapping. */
+#define SCC_NUM_BASE   (USE_SMC2 + 1)  /* SCC base tty "number" */
+
+/* Define which SCC is the first one to use for a serial port.  These
+ * are 0-based numbers, i.e. this assumes the first SCC (SCC1) is used
+ * for Ethernet, and the first available SCC for serial UART is SCC2.
+ * NOTE:  IF YOU CHANGE THIS, you have to change the PROFF_xxx and
+ * interrupt vectors in the table below to match.
+ */
+#define SCC_IDX_BASE   1       /* table index */
+#endif
+
+
+/* Processors other than the 860 only get SMCs configured by default.
+ * Either they don't have SCCs or they are allocated somewhere else.
+ * Of course, there are now 860s without some SCCs, so we will need to
+ * address that someday.
+ * The Embedded Planet Multimedia I/O cards use TDM interfaces to the
+ * stereo codec parts, and we use SMC2 to help support that.
+ */
+static struct serial_state rs_table[] = {
+/*  type   line   PORT           IRQ       FLAGS  smc_scc_num (F.K.A. hub6) */
+       {  0,     0, PRSLOT_SMC1, CPMVEC_SMC1,   0,    0 }    /* SMC1 ttyS0 */
+#if USE_SMC2
+       ,{ 0,     0, PRSLOT_SMC2, CPMVEC_SMC2,   0,    1 }     /* SMC2 ttyS1 */
+#endif
+
+#if defined(CONFIG_SERIAL_68360_SCC)
+       ,{ 0,     0, PRSLOT_SCC2, CPMVEC_SCC2,   0, (NUM_IS_SCC | 1) }    /* SCC2 ttyS2 */
+       ,{ 0,     0, PRSLOT_SCC3, CPMVEC_SCC3,   0, (NUM_IS_SCC | 2) }    /* SCC3 ttyS3 */
+       ,{ 0,     0, PRSLOT_SCC4, CPMVEC_SCC4,   0, (NUM_IS_SCC | 3) }    /* SCC4 ttyS4 */
+#endif
+};
+
+#define NR_PORTS       (sizeof(rs_table)/sizeof(struct serial_state))
+
+/* The number of buffer descriptors and their sizes.
+ */
+#define RX_NUM_FIFO    4
+#define RX_BUF_SIZE    32
+#define TX_NUM_FIFO    4
+#define TX_BUF_SIZE    32
+
+#define CONSOLE_NUM_FIFO 2
+#define CONSOLE_BUF_SIZE 4
+
+char *console_fifos[CONSOLE_NUM_FIFO * CONSOLE_BUF_SIZE];
+
+/* The async_struct in serial.h does not really give us what we
+ * need, so define our own here.
+ */
+typedef struct serial_info {
+       int                     magic;
+       int                     flags;
+
+       struct serial_state     *state;
+       /* struct serial_struct *state; */
+       /* struct async_struct  *state; */
+       
+       struct tty_struct       *tty;
+       int                     read_status_mask;
+       int                     ignore_status_mask;
+       int                     timeout;
+       int                     line;
+       int                     x_char; /* xon/xoff character */
+       int                     close_delay;
+       unsigned short          closing_wait;
+       unsigned short          closing_wait2;
+       unsigned long           event;
+       unsigned long           last_active;
+       int                     blocked_open; /* # of blocked opens */
+       struct work_struct      tqueue;
+       struct work_struct      tqueue_hangup;
+       wait_queue_head_t       open_wait; 
+       wait_queue_head_t       close_wait; 
+
+       
+/* CPM Buffer Descriptor pointers.
+       */
+       QUICC_BD                        *rx_bd_base;
+       QUICC_BD                        *rx_cur;
+       QUICC_BD                        *tx_bd_base;
+       QUICC_BD                        *tx_cur;
+} ser_info_t;
+
+
+/* since kmalloc_init() does not get called until much after this initialization: */
+static ser_info_t  quicc_ser_info[NR_PORTS];
+static char rx_buf_pool[NR_PORTS * RX_NUM_FIFO * RX_BUF_SIZE];
+static char tx_buf_pool[NR_PORTS * TX_NUM_FIFO * TX_BUF_SIZE];
+
+static void change_speed(ser_info_t *info);
+static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout);
+
+static inline int serial_paranoia_check(ser_info_t *info,
+                                       char *name, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+       static const char *badmagic =
+               "Warning: bad magic number for serial struct (%s) in %s\n";
+       static const char *badinfo =
+               "Warning: null async_struct for (%s) in %s\n";
+
+       if (!info) {
+               printk(badinfo, name, routine);
+               return 1;
+       }
+       if (info->magic != SERIAL_MAGIC) {
+               printk(badmagic, name, routine);
+               return 1;
+       }
+#endif
+       return 0;
+}
+
+/*
+ * This is used to figure out the divisor speeds and the timeouts,
+ * indexed by the termio value.  The generic CPM functions are responsible
+ * for setting and assigning baud rate generators for us.
+ */
+static int baud_table[] = {
+       0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+       9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };
+
+/* This sucks. There is a better way: */
+#if defined(CONFIG_CONSOLE_9600)
+  #define CONSOLE_BAUDRATE 9600
+#elif defined(CONFIG_CONSOLE_19200)
+  #define CONSOLE_BAUDRATE 19200
+#elif defined(CONFIG_CONSOLE_115200)
+  #define CONSOLE_BAUDRATE 115200
+#else
+  #warning "console baud rate undefined"
+  #define CONSOLE_BAUDRATE 9600
+#endif
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ * ------------------------------------------------------------
+ */
+static void rs_360_stop(struct tty_struct *tty)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       int     idx;
+       unsigned long flags;
+       volatile struct scc_regs *sccp;
+       volatile struct smc_regs *smcp;
+
+       if (serial_paranoia_check(info, tty->name, "rs_stop"))
+               return;
+       
+       local_irq_save(flags);
+       idx = PORT_NUM(info->state->smc_scc_num);
+       if (info->state->smc_scc_num & NUM_IS_SCC) {
+               sccp = &pquicc->scc_regs[idx];
+               sccp->scc_sccm &= ~UART_SCCM_TX;
+       } else {
+               /* smcp = &cpmp->cp_smc[idx]; */
+               smcp = &pquicc->smc_regs[idx];
+               smcp->smc_smcm &= ~SMCM_TX;
+       }
+       local_irq_restore(flags);
+}
+
+
+static void rs_360_start(struct tty_struct *tty)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       int     idx;
+       unsigned long flags;
+       volatile struct scc_regs *sccp;
+       volatile struct smc_regs *smcp;
+
+       if (serial_paranoia_check(info, tty->name, "rs_stop"))
+               return;
+       
+       local_irq_save(flags);
+       idx = PORT_NUM(info->state->smc_scc_num);
+       if (info->state->smc_scc_num & NUM_IS_SCC) {
+               sccp = &pquicc->scc_regs[idx];
+               sccp->scc_sccm |= UART_SCCM_TX;
+       } else {
+               smcp = &pquicc->smc_regs[idx];
+               smcp->smc_smcm |= SMCM_TX;
+       }
+       local_irq_restore(flags);
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines.  All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt().  They were separated out for readability's sake.
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off.  People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible.  After you are done making modifications, it is not a bad
+ * idea to do:
+ * 
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ *                             - Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+static _INLINE_ void receive_chars(ser_info_t *info)
+{
+       struct tty_struct *tty = info->port.tty;
+       unsigned char ch, flag, *cp;
+       /*int   ignored = 0;*/
+       int     i;
+       ushort  status;
+        struct async_icount *icount; 
+       /* struct       async_icount_24 *icount; */
+       volatile QUICC_BD       *bdp;
+
+       icount = &info->state->icount;
+
+       /* Just loop through the closed BDs and copy the characters into
+        * the buffer.
+        */
+       bdp = info->rx_cur;
+       for (;;) {
+               if (bdp->status & BD_SC_EMPTY)  /* If this one is empty */
+                       break;                  /*   we are all done */
+
+               /* The read status mask tell us what we should do with
+                * incoming characters, especially if errors occur.
+                * One special case is the use of BD_SC_EMPTY.  If
+                * this is not set, we are supposed to be ignoring
+                * inputs.  In this case, just mark the buffer empty and
+                * continue.
+                */
+               if (!(info->read_status_mask & BD_SC_EMPTY)) {
+                       bdp->status |= BD_SC_EMPTY;
+                       bdp->status &=
+                               ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
+
+                       if (bdp->status & BD_SC_WRAP)
+                               bdp = info->rx_bd_base;
+                       else
+                               bdp++;
+                       continue;
+               }
+
+               /* Get the number of characters and the buffer pointer.
+               */
+               i = bdp->length;
+               /* cp = (unsigned char *)__va(bdp->buf); */
+               cp = (char *)bdp->buf;
+               status = bdp->status;
+
+               while (i-- > 0) {
+                       ch = *cp++;
+                       icount->rx++;
+
+#ifdef SERIAL_DEBUG_INTR
+                       printk("DR%02x:%02x...", ch, status);
+#endif
+                       flag = TTY_NORMAL;
+
+                       if (status & (BD_SC_BR | BD_SC_FR |
+                                      BD_SC_PR | BD_SC_OV)) {
+                               /*
+                                * For statistics only
+                                */
+                               if (status & BD_SC_BR)
+                                       icount->brk++;
+                               else if (status & BD_SC_PR)
+                                       icount->parity++;
+                               else if (status & BD_SC_FR)
+                                       icount->frame++;
+                               if (status & BD_SC_OV)
+                                       icount->overrun++;
+
+                               /*
+                                * Now check to see if character should be
+                                * ignored, and mask off conditions which
+                                * should be ignored.
+                               if (status & info->ignore_status_mask) {
+                                       if (++ignored > 100)
+                                               break;
+                                       continue;
+                               }
+                                */
+                               status &= info->read_status_mask;
+               
+                               if (status & (BD_SC_BR)) {
+#ifdef SERIAL_DEBUG_INTR
+                                       printk("handling break....");
+#endif
+                                       *tty->flip.flag_buf_ptr = TTY_BREAK;
+                                       if (info->flags & ASYNC_SAK)
+                                               do_SAK(tty);
+                               } else if (status & BD_SC_PR)
+                                       flag = TTY_PARITY;
+                               else if (status & BD_SC_FR)
+                                       flag = TTY_FRAME;
+                       }
+                       tty_insert_flip_char(tty, ch, flag);
+                       if (status & BD_SC_OV)
+                               /*
+                                * Overrun is special, since it's
+                                * reported immediately, and doesn't
+                                * affect the current character
+                                */
+                               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+               }
+
+               /* This BD is ready to be used again.  Clear status.
+                * Get next BD.
+                */
+               bdp->status |= BD_SC_EMPTY;
+               bdp->status &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
+
+               if (bdp->status & BD_SC_WRAP)
+                       bdp = info->rx_bd_base;
+               else
+                       bdp++;
+       }
+
+       info->rx_cur = (QUICC_BD *)bdp;
+
+       tty_schedule_flip(tty);
+}
+
+static _INLINE_ void receive_break(ser_info_t *info)
+{
+       struct tty_struct *tty = info->port.tty;
+
+       info->state->icount.brk++;
+       /* Check to see if there is room in the tty buffer for
+        * the break.  If not, we exit now, losing the break.  FIXME
+        */
+       tty_insert_flip_char(tty, 0, TTY_BREAK);
+       tty_schedule_flip(tty);
+}
+
+static _INLINE_ void transmit_chars(ser_info_t *info)
+{
+
+       if ((info->flags & TX_WAKEUP) ||
+           (info->port.tty->flags & (1 << TTY_DO_WRITE_WAKEUP))) {
+               schedule_work(&info->tqueue);
+       }
+
+#ifdef SERIAL_DEBUG_INTR
+       printk("THRE...");
+#endif
+}
+
+#ifdef notdef
+       /* I need to do this for the SCCs, so it is left as a reminder.
+       */
+static _INLINE_ void check_modem_status(struct async_struct *info)
+{
+       int     status;
+       /* struct       async_icount *icount; */
+       struct  async_icount_24 *icount;
+       
+       status = serial_in(info, UART_MSR);
+
+       if (status & UART_MSR_ANY_DELTA) {
+               icount = &info->state->icount;
+               /* update input line counters */
+               if (status & UART_MSR_TERI)
+                       icount->rng++;
+               if (status & UART_MSR_DDSR)
+                       icount->dsr++;
+               if (status & UART_MSR_DDCD) {
+                       icount->dcd++;
+#ifdef CONFIG_HARD_PPS
+                       if ((info->flags & ASYNC_HARDPPS_CD) &&
+                           (status & UART_MSR_DCD))
+                               hardpps();
+#endif
+               }
+               if (status & UART_MSR_DCTS)
+                       icount->cts++;
+               wake_up_interruptible(&info->delta_msr_wait);
+       }
+
+       if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
+#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
+               printk("ttys%d CD now %s...", info->line,
+                      (status & UART_MSR_DCD) ? "on" : "off");
+#endif         
+               if (status & UART_MSR_DCD)
+                       wake_up_interruptible(&info->open_wait);
+               else {
+#ifdef SERIAL_DEBUG_OPEN
+                       printk("scheduling hangup...");
+#endif
+                       queue_task(&info->tqueue_hangup,
+                                          &tq_scheduler);
+               }
+       }
+       if (info->flags & ASYNC_CTS_FLOW) {
+               if (info->port.tty->hw_stopped) {
+                       if (status & UART_MSR_CTS) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+                               printk("CTS tx start...");
+#endif
+                               info->port.tty->hw_stopped = 0;
+                               info->IER |= UART_IER_THRI;
+                               serial_out(info, UART_IER, info->IER);
+                               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+                               return;
+                       }
+               } else {
+                       if (!(status & UART_MSR_CTS)) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+                               printk("CTS tx stop...");
+#endif
+                               info->port.tty->hw_stopped = 1;
+                               info->IER &= ~UART_IER_THRI;
+                               serial_out(info, UART_IER, info->IER);
+                       }
+               }
+       }
+}
+#endif
+
+/*
+ * This is the serial driver's interrupt routine for a single port
+ */
+/* static void rs_360_interrupt(void *dev_id) */ /* until and if we start servicing irqs here */
+static void rs_360_interrupt(int vec, void *dev_id)
+{
+       u_char  events;
+       int     idx;
+       ser_info_t *info;
+       volatile struct smc_regs *smcp;
+       volatile struct scc_regs *sccp;
+       
+       info = dev_id;
+
+       idx = PORT_NUM(info->state->smc_scc_num);
+       if (info->state->smc_scc_num & NUM_IS_SCC) {
+               sccp = &pquicc->scc_regs[idx];
+               events = sccp->scc_scce;
+               if (events & SCCM_RX)
+                       receive_chars(info);
+               if (events & SCCM_TX)
+                       transmit_chars(info);
+               sccp->scc_scce = events;
+       } else {
+               smcp = &pquicc->smc_regs[idx];
+               events = smcp->smc_smce;
+               if (events & SMCM_BRKE)
+                       receive_break(info);
+               if (events & SMCM_RX)
+                       receive_chars(info);
+               if (events & SMCM_TX)
+                       transmit_chars(info);
+               smcp->smc_smce = events;
+       }
+       
+#ifdef SERIAL_DEBUG_INTR
+       printk("rs_interrupt_single(%d, %x)...",
+                                       info->state->smc_scc_num, events);
+#endif
+#ifdef modem_control
+       check_modem_status(info);
+#endif
+       info->last_active = jiffies;
+#ifdef SERIAL_DEBUG_INTR
+       printk("end.\n");
+#endif
+}
+
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+
+static void do_softint(void *private_)
+{
+       ser_info_t      *info = (ser_info_t *) private_;
+       struct tty_struct       *tty;
+       
+       tty = info->port.tty;
+       if (!tty)
+               return;
+
+       if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event))
+               tty_wakeup(tty);
+}
+
+
+/*
+ * This routine is called from the scheduler tqueue when the interrupt
+ * routine has signalled that a hangup has occurred.  The path of
+ * hangup processing is:
+ *
+ *     serial interrupt routine -> (scheduler tqueue) ->
+ *     do_serial_hangup() -> tty->hangup() -> rs_hangup()
+ * 
+ */
+static void do_serial_hangup(void *private_)
+{
+       struct async_struct     *info = (struct async_struct *) private_;
+       struct tty_struct       *tty;
+       
+       tty = info->port.tty;
+       if (!tty)
+               return;
+
+       tty_hangup(tty);
+}
+
+
+static int startup(ser_info_t *info)
+{
+       unsigned long flags;
+       int     retval=0;
+       int     idx;
+       /*struct serial_state *state = info->state;*/
+       volatile struct smc_regs *smcp;
+       volatile struct scc_regs *sccp;
+       volatile struct smc_uart_pram   *up;
+       volatile struct uart_pram           *scup;
+
+
+       local_irq_save(flags);
+
+       if (info->flags & ASYNC_INITIALIZED) {
+               goto errout;
+       }
+
+#ifdef maybe
+       if (!state->port || !state->type) {
+               if (info->port.tty)
+                       set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+               goto errout;
+       }
+#endif
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("starting up ttys%d (irq %d)...", info->line, state->irq);
+#endif
+
+
+#ifdef modem_control
+       info->MCR = 0;
+       if (info->port.tty->termios->c_cflag & CBAUD)
+               info->MCR = UART_MCR_DTR | UART_MCR_RTS;
+#endif
+       
+       if (info->port.tty)
+               clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
+
+       /*
+        * and set the speed of the serial port
+        */
+       change_speed(info);
+
+       idx = PORT_NUM(info->state->smc_scc_num);
+       if (info->state->smc_scc_num & NUM_IS_SCC) {
+               sccp = &pquicc->scc_regs[idx];
+               scup = &pquicc->pram[info->state->port].scc.pscc.u;
+
+               scup->mrblr = RX_BUF_SIZE;
+               scup->max_idl = RX_BUF_SIZE;
+
+               sccp->scc_sccm |= (UART_SCCM_TX | UART_SCCM_RX);
+               sccp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+       } else {
+               smcp = &pquicc->smc_regs[idx];
+
+               /* Enable interrupts and I/O.
+               */
+               smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
+               smcp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN);
+
+               /* We can tune the buffer length and idle characters
+                * to take advantage of the entire incoming buffer size.
+                * If mrblr is something other than 1, maxidl has to be
+                * non-zero or we never get an interrupt.  The maxidl
+                * is the number of character times we wait after reception
+                * of the last character before we decide no more characters
+                * are coming.
+                */
+               /* up = (smc_uart_t *)&pquicc->cp_dparam[state->port]; */
+               /* holy unionized structures, Batman: */
+               up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u;
+
+               up->mrblr = RX_BUF_SIZE;
+               up->max_idl = RX_BUF_SIZE;
+
+               up->brkcr = 1;  /* number of break chars */
+       }
+
+       info->flags |= ASYNC_INITIALIZED;
+       local_irq_restore(flags);
+       return 0;
+       
+errout:
+       local_irq_restore(flags);
+       return retval;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(ser_info_t *info)
+{
+       unsigned long   flags;
+       struct serial_state *state;
+       int             idx;
+       volatile struct smc_regs        *smcp;
+       volatile struct scc_regs        *sccp;
+
+       if (!(info->flags & ASYNC_INITIALIZED))
+               return;
+
+       state = info->state;
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("Shutting down serial port %d (irq %d)....", info->line,
+              state->irq);
+#endif
+       
+       local_irq_save(flags);
+
+       idx = PORT_NUM(state->smc_scc_num);
+       if (state->smc_scc_num & NUM_IS_SCC) {
+               sccp = &pquicc->scc_regs[idx];
+               sccp->scc_gsmr.w.low &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+#ifdef CONFIG_SERIAL_CONSOLE
+               /* We can't disable the transmitter if this is the
+                * system console.
+                */
+               if ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT)
+#endif
+               sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
+       } else {
+               smcp = &pquicc->smc_regs[idx];
+
+               /* Disable interrupts and I/O.
+                */
+               smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
+#ifdef CONFIG_SERIAL_CONSOLE
+               /* We can't disable the transmitter if this is the
+                * system console.
+                */
+               if ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT)
+#endif
+                       smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+       }
+       
+       if (info->port.tty)
+               set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+
+       info->flags &= ~ASYNC_INITIALIZED;
+       local_irq_restore(flags);
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void change_speed(ser_info_t *info)
+{
+       int     baud_rate;
+       unsigned cflag, cval, scval, prev_mode;
+       int     i, bits, sbits, idx;
+       unsigned long   flags;
+       struct serial_state *state;
+       volatile struct smc_regs        *smcp;
+       volatile struct scc_regs        *sccp;
+
+       if (!info->port.tty || !info->port.tty->termios)
+               return;
+       cflag = info->port.tty->termios->c_cflag;
+
+       state = info->state;
+
+       /* Character length programmed into the mode register is the
+        * sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
+        * 1 or 2 stop bits, minus 1.
+        * The value 'bits' counts this for us.
+        */
+       cval = 0;
+       scval = 0;
+
+       /* byte size and parity */
+       switch (cflag & CSIZE) {
+             case CS5: bits = 5; break;
+             case CS6: bits = 6; break;
+             case CS7: bits = 7; break;
+             case CS8: bits = 8; break;
+             /* Never happens, but GCC is too dumb to figure it out */
+             default:  bits = 8; break;
+       }
+       sbits = bits - 5;
+
+       if (cflag & CSTOPB) {
+               cval |= SMCMR_SL;       /* Two stops */
+               scval |= SCU_PMSR_SL;
+               bits++;
+       }
+       if (cflag & PARENB) {
+               cval |= SMCMR_PEN;
+               scval |= SCU_PMSR_PEN;
+               bits++;
+       }
+       if (!(cflag & PARODD)) {
+               cval |= SMCMR_PM_EVEN;
+               scval |= (SCU_PMSR_REVP | SCU_PMSR_TEVP);
+       }
+
+       /* Determine divisor based on baud rate */
+       i = cflag & CBAUD;
+       if (i >= (sizeof(baud_table)/sizeof(int)))
+               baud_rate = 9600;
+       else
+               baud_rate = baud_table[i];
+
+       info->timeout = (TX_BUF_SIZE*HZ*bits);
+       info->timeout += HZ/50;         /* Add .02 seconds of slop */
+
+#ifdef modem_control
+       /* CTS flow control flag and modem status interrupts */
+       info->IER &= ~UART_IER_MSI;
+       if (info->flags & ASYNC_HARDPPS_CD)
+               info->IER |= UART_IER_MSI;
+       if (cflag & CRTSCTS) {
+               info->flags |= ASYNC_CTS_FLOW;
+               info->IER |= UART_IER_MSI;
+       } else
+               info->flags &= ~ASYNC_CTS_FLOW;
+       if (cflag & CLOCAL)
+               info->flags &= ~ASYNC_CHECK_CD;
+       else {
+               info->flags |= ASYNC_CHECK_CD;
+               info->IER |= UART_IER_MSI;
+       }
+       serial_out(info, UART_IER, info->IER);
+#endif
+
+       /*
+        * Set up parity check flag
+        */
+       info->read_status_mask = (BD_SC_EMPTY | BD_SC_OV);
+       if (I_INPCK(info->port.tty))
+               info->read_status_mask |= BD_SC_FR | BD_SC_PR;
+       if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
+               info->read_status_mask |= BD_SC_BR;
+       
+       /*
+        * Characters to ignore
+        */
+       info->ignore_status_mask = 0;
+       if (I_IGNPAR(info->port.tty))
+               info->ignore_status_mask |= BD_SC_PR | BD_SC_FR;
+       if (I_IGNBRK(info->port.tty)) {
+               info->ignore_status_mask |= BD_SC_BR;
+               /*
+                * If we're ignore parity and break indicators, ignore 
+                * overruns too.  (For real raw support).
+                */
+               if (I_IGNPAR(info->port.tty))
+                       info->ignore_status_mask |= BD_SC_OV;
+       }
+       /*
+        * !!! ignore all characters if CREAD is not set
+        */
+       if ((cflag & CREAD) == 0)
+        info->read_status_mask &= ~BD_SC_EMPTY;
+        local_irq_save(flags);
+
+        /* Start bit has not been added (so don't, because we would just
+         * subtract it later), and we need to add one for the number of
+         * stops bits (there is always at least one).
+         */
+        bits++;
+        idx = PORT_NUM(state->smc_scc_num);
+        if (state->smc_scc_num & NUM_IS_SCC) {
+         sccp = &pquicc->scc_regs[idx];
+         sccp->scc_psmr = (sbits << 12) | scval;
+     } else {
+         smcp = &pquicc->smc_regs[idx];
+
+               /* Set the mode register.  We want to keep a copy of the
+                * enables, because we want to put them back if they were
+                * present.
+                */
+               prev_mode = smcp->smc_smcmr;
+               smcp->smc_smcmr = smcr_mk_clen(bits) | cval |  SMCMR_SM_UART;
+               smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN));
+       }
+
+       m360_cpm_setbrg((state - rs_table), baud_rate);
+
+       local_irq_restore(flags);
+}
+
+static void rs_360_put_char(struct tty_struct *tty, unsigned char ch)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       volatile QUICC_BD       *bdp;
+
+       if (serial_paranoia_check(info, tty->name, "rs_put_char"))
+               return 0;
+
+       if (!tty)
+               return 0;
+
+       bdp = info->tx_cur;
+       while (bdp->status & BD_SC_READY);
+
+       /* *((char *)__va(bdp->buf)) = ch; */
+       *((char *)bdp->buf) = ch;
+       bdp->length = 1;
+       bdp->status |= BD_SC_READY;
+
+       /* Get next BD.
+       */
+       if (bdp->status & BD_SC_WRAP)
+               bdp = info->tx_bd_base;
+       else
+               bdp++;
+
+       info->tx_cur = (QUICC_BD *)bdp;
+       return 1;
+
+}
+
+static int rs_360_write(struct tty_struct * tty,
+                   const unsigned char *buf, int count)
+{
+       int     c, ret = 0;
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       volatile QUICC_BD *bdp;
+
+#ifdef CONFIG_KGDB
+       /* Try to let stub handle output. Returns true if it did. */ 
+       if (kgdb_output_string(buf, count))
+               return ret;
+#endif
+
+       if (serial_paranoia_check(info, tty->name, "rs_write"))
+               return 0;
+
+       if (!tty) 
+               return 0;
+
+       bdp = info->tx_cur;
+
+       while (1) {
+               c = min(count, TX_BUF_SIZE);
+
+               if (c <= 0)
+                       break;
+
+               if (bdp->status & BD_SC_READY) {
+                       info->flags |= TX_WAKEUP;
+                       break;
+               }
+
+               /* memcpy(__va(bdp->buf), buf, c); */
+               memcpy((void *)bdp->buf, buf, c);
+
+               bdp->length = c;
+               bdp->status |= BD_SC_READY;
+
+               buf += c;
+               count -= c;
+               ret += c;
+
+               /* Get next BD.
+               */
+               if (bdp->status & BD_SC_WRAP)
+                       bdp = info->tx_bd_base;
+               else
+                       bdp++;
+               info->tx_cur = (QUICC_BD *)bdp;
+       }
+       return ret;
+}
+
+static int rs_360_write_room(struct tty_struct *tty)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       int     ret;
+
+       if (serial_paranoia_check(info, tty->name, "rs_write_room"))
+               return 0;
+
+       if ((info->tx_cur->status & BD_SC_READY) == 0) {
+               info->flags &= ~TX_WAKEUP;
+               ret = TX_BUF_SIZE;
+       }
+       else {
+               info->flags |= TX_WAKEUP;
+               ret = 0;
+       }
+       return ret;
+}
+
+/* I could track this with transmit counters....maybe later.
+*/
+static int rs_360_chars_in_buffer(struct tty_struct *tty)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+                               
+       if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
+               return 0;
+       return 0;
+}
+
+static void rs_360_flush_buffer(struct tty_struct *tty)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+                               
+       if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
+               return;
+
+       /* There is nothing to "flush", whatever we gave the CPM
+        * is on its way out.
+        */
+       tty_wakeup(tty);
+       info->flags &= ~TX_WAKEUP;
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ */
+static void rs_360_send_xchar(struct tty_struct *tty, char ch)
+{
+       volatile QUICC_BD       *bdp;
+
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+
+       if (serial_paranoia_check(info, tty->name, "rs_send_char"))
+               return;
+
+       bdp = info->tx_cur;
+       while (bdp->status & BD_SC_READY);
+
+       /* *((char *)__va(bdp->buf)) = ch; */
+       *((char *)bdp->buf) = ch;
+       bdp->length = 1;
+       bdp->status |= BD_SC_READY;
+
+       /* Get next BD.
+       */
+       if (bdp->status & BD_SC_WRAP)
+               bdp = info->tx_bd_base;
+       else
+               bdp++;
+
+       info->tx_cur = (QUICC_BD *)bdp;
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ * 
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void rs_360_throttle(struct tty_struct * tty)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+       char    buf[64];
+       
+       printk("throttle %s: %d....\n", _tty_name(tty, buf),
+              tty->ldisc.chars_in_buffer(tty));
+#endif
+
+       if (serial_paranoia_check(info, tty->name, "rs_throttle"))
+               return;
+       
+       if (I_IXOFF(tty))
+               rs_360_send_xchar(tty, STOP_CHAR(tty));
+
+#ifdef modem_control
+       if (tty->termios->c_cflag & CRTSCTS)
+               info->MCR &= ~UART_MCR_RTS;
+
+       local_irq_disable();
+       serial_out(info, UART_MCR, info->MCR);
+       local_irq_enable();
+#endif
+}
+
+static void rs_360_unthrottle(struct tty_struct * tty)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+       char    buf[64];
+       
+       printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
+              tty->ldisc.chars_in_buffer(tty));
+#endif
+
+       if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
+               return;
+       
+       if (I_IXOFF(tty)) {
+               if (info->x_char)
+                       info->x_char = 0;
+               else
+                       rs_360_send_xchar(tty, START_CHAR(tty));
+       }
+#ifdef modem_control
+       if (tty->termios->c_cflag & CRTSCTS)
+               info->MCR |= UART_MCR_RTS;
+       local_irq_disable();
+       serial_out(info, UART_MCR, info->MCR);
+       local_irq_enable();
+#endif
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+#ifdef maybe
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ *         is emptied.  On bus types like RS485, the transmitter must
+ *         release the bus after transmitting. This must be done when
+ *         the transmit shift register is empty, not be done when the
+ *         transmit holding register is empty.  This functionality
+ *         allows an RS485 driver to be written in user space. 
+ */
+static int get_lsr_info(struct async_struct * info, unsigned int *value)
+{
+       unsigned char status;
+       unsigned int result;
+
+       local_irq_disable();
+       status = serial_in(info, UART_LSR);
+       local_irq_enable();
+       result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
+       return put_user(result,value);
+}
+#endif
+
+static int rs_360_tiocmget(struct tty_struct *tty, struct file *file)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       unsigned int result = 0;
+#ifdef modem_control
+       unsigned char control, status;
+
+       if (serial_paranoia_check(info, tty->name, __func__))
+               return -ENODEV;
+
+       if (tty->flags & (1 << TTY_IO_ERROR))
+               return -EIO;
+
+       control = info->MCR;
+       local_irq_disable();
+       status = serial_in(info, UART_MSR);
+       local_irq_enable();
+       result =  ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
+               | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
+#ifdef TIOCM_OUT1
+               | ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0)
+               | ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0)
+#endif
+               | ((status  & UART_MSR_DCD) ? TIOCM_CAR : 0)
+               | ((status  & UART_MSR_RI) ? TIOCM_RNG : 0)
+               | ((status  & UART_MSR_DSR) ? TIOCM_DSR : 0)
+               | ((status  & UART_MSR_CTS) ? TIOCM_CTS : 0);
+#endif
+       return result;
+}
+
+static int rs_360_tiocmset(struct tty_struct *tty, struct file *file,
+                          unsigned int set, unsigned int clear)
+{
+#ifdef modem_control
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       unsigned int arg;
+
+       if (serial_paranoia_check(info, tty->name, __func__))
+               return -ENODEV;
+
+       if (tty->flags & (1 << TTY_IO_ERROR))
+               return -EIO;
+       /* FIXME: locking on info->mcr */
+       if (set & TIOCM_RTS)
+               info->mcr |= UART_MCR_RTS;
+       if (set & TIOCM_DTR)
+               info->mcr |= UART_MCR_DTR;
+       if (clear & TIOCM_RTS)
+               info->MCR &= ~UART_MCR_RTS;
+       if (clear & TIOCM_DTR)
+               info->MCR &= ~UART_MCR_DTR;
+
+#ifdef TIOCM_OUT1
+       if (set & TIOCM_OUT1)
+               info->MCR |= UART_MCR_OUT1;
+       if (set & TIOCM_OUT2)
+               info->MCR |= UART_MCR_OUT2;
+       if (clear & TIOCM_OUT1)
+               info->MCR &= ~UART_MCR_OUT1;
+       if (clear & TIOCM_OUT2)
+               info->MCR &= ~UART_MCR_OUT2;
+#endif
+
+       local_irq_disable();
+       serial_out(info, UART_MCR, info->MCR);
+       local_irq_enable();
+#endif
+       return 0;
+}
+
+/* Sending a break is a two step process on the SMC/SCC.  It is accomplished
+ * by sending a STOP TRANSMIT command followed by a RESTART TRANSMIT
+ * command.  We take advantage of the begin/end functions to make this
+ * happen.
+ */
+static ushort  smc_chan_map[] = {
+       CPM_CR_CH_SMC1,
+       CPM_CR_CH_SMC2
+};
+
+static ushort  scc_chan_map[] = {
+       CPM_CR_CH_SCC1,
+       CPM_CR_CH_SCC2,
+       CPM_CR_CH_SCC3,
+       CPM_CR_CH_SCC4
+};
+
+static void begin_break(ser_info_t *info)
+{
+       volatile QUICC *cp;
+       ushort  chan;
+       int     idx;
+
+       cp = pquicc;
+
+       idx = PORT_NUM(info->state->smc_scc_num);
+       if (info->state->smc_scc_num & NUM_IS_SCC)
+               chan = scc_chan_map[idx];
+       else
+               chan = smc_chan_map[idx];
+
+       cp->cp_cr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG;
+       while (cp->cp_cr & CPM_CR_FLG);
+}
+
+static void end_break(ser_info_t *info)
+{
+       volatile QUICC *cp;
+       ushort  chan;
+       int idx;
+
+       cp = pquicc;
+
+       idx = PORT_NUM(info->state->smc_scc_num);
+       if (info->state->smc_scc_num & NUM_IS_SCC)
+               chan = scc_chan_map[idx];
+       else
+               chan = smc_chan_map[idx];
+
+       cp->cp_cr = mk_cr_cmd(chan, CPM_CR_RESTART_TX) | CPM_CR_FLG;
+       while (cp->cp_cr & CPM_CR_FLG);
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void send_break(ser_info_t *info, unsigned int duration)
+{
+#ifdef SERIAL_DEBUG_SEND_BREAK
+       printk("rs_send_break(%d) jiff=%lu...", duration, jiffies);
+#endif
+       begin_break(info);
+       msleep_interruptible(duration);
+       end_break(info);
+#ifdef SERIAL_DEBUG_SEND_BREAK
+       printk("done jiffies=%lu\n", jiffies);
+#endif
+}
+
+
+/*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * Return: write counters to the user passed counter struct
+ * NB: both 1->0 and 0->1 transitions are counted except for
+ *     RI where only 0->1 is counted.
+ */
+static int rs_360_get_icount(struct tty_struct *tty,
+                               struct serial_icounter_struct *icount)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       struct async_icount cnow;
+
+       local_irq_disable();
+       cnow = info->state->icount;
+       local_irq_enable();
+
+       icount->cts = cnow.cts;
+       icount->dsr = cnow.dsr;
+       icount->rng = cnow.rng;
+       icount->dcd = cnow.dcd;
+
+       return 0;
+}
+
+static int rs_360_ioctl(struct tty_struct *tty, struct file * file,
+                   unsigned int cmd, unsigned long arg)
+{
+       int error;
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       int retval;
+       struct async_icount cnow; 
+       /* struct async_icount_24 cnow;*/       /* kernel counter temps */
+       struct serial_icounter_struct *p_cuser; /* user space */
+
+       if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
+               return -ENODEV;
+
+       if (cmd != TIOCMIWAIT) {
+               if (tty->flags & (1 << TTY_IO_ERROR))
+                   return -EIO;
+       }
+       
+       switch (cmd) {
+               case TCSBRK:    /* SVID version: non-zero arg --> no break */
+                       retval = tty_check_change(tty);
+                       if (retval)
+                               return retval;
+                       tty_wait_until_sent(tty, 0);
+                       if (signal_pending(current))
+                               return -EINTR;
+                       if (!arg) {
+                               send_break(info, 250);  /* 1/4 second */
+                               if (signal_pending(current))
+                                       return -EINTR;
+                       }
+                       return 0;
+               case TCSBRKP:   /* support for POSIX tcsendbreak() */
+                       retval = tty_check_change(tty);
+                       if (retval)
+                               return retval;
+                       tty_wait_until_sent(tty, 0);
+                       if (signal_pending(current))
+                               return -EINTR;
+                       send_break(info, arg ? arg*100 : 250);
+                       if (signal_pending(current))
+                               return -EINTR;
+                       return 0;
+               case TIOCSBRK:
+                       retval = tty_check_change(tty);
+                       if (retval)
+                               return retval;
+                       tty_wait_until_sent(tty, 0);
+                       begin_break(info);
+                       return 0;
+               case TIOCCBRK:
+                       retval = tty_check_change(tty);
+                       if (retval)
+                               return retval;
+                       end_break(info);
+                       return 0;
+#ifdef maybe
+               case TIOCSERGETLSR: /* Get line status register */
+                       return get_lsr_info(info, (unsigned int *) arg);
+#endif
+               /*
+                * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+                * - mask passed in arg for lines of interest
+                *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+                * Caller should use TIOCGICOUNT to see which one it was
+                */
+                case TIOCMIWAIT:
+#ifdef modem_control
+                       local_irq_disable();
+                       /* note the counters on entry */
+                       cprev = info->state->icount;
+                       local_irq_enable();
+                       while (1) {
+                               interruptible_sleep_on(&info->delta_msr_wait);
+                               /* see if a signal did it */
+                               if (signal_pending(current))
+                                       return -ERESTARTSYS;
+                               local_irq_disable();
+                               cnow = info->state->icount; /* atomic copy */
+                               local_irq_enable();
+                               if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 
+                                   cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+                                       return -EIO; /* no change => error */
+                               if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+                                    ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+                                    ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
+                                    ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
+                                       return 0;
+                               }
+                               cprev = cnow;
+                       }
+                       /* NOTREACHED */
+#else
+                       return 0;
+#endif
+
+
+               default:
+                       return -ENOIOCTLCMD;
+               }
+       return 0;
+}
+
+/* FIX UP modem control here someday......
+*/
+static void rs_360_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+
+       change_speed(info);
+
+#ifdef modem_control
+       /* Handle transition to B0 status */
+       if ((old_termios->c_cflag & CBAUD) &&
+           !(tty->termios->c_cflag & CBAUD)) {
+               info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
+               local_irq_disable();
+               serial_out(info, UART_MCR, info->MCR);
+               local_irq_enable();
+       }
+       
+       /* Handle transition away from B0 status */
+       if (!(old_termios->c_cflag & CBAUD) &&
+           (tty->termios->c_cflag & CBAUD)) {
+               info->MCR |= UART_MCR_DTR;
+               if (!tty->hw_stopped ||
+                   !(tty->termios->c_cflag & CRTSCTS)) {
+                       info->MCR |= UART_MCR_RTS;
+               }
+               local_irq_disable();
+               serial_out(info, UART_MCR, info->MCR);
+               local_irq_enable();
+       }
+       
+       /* Handle turning off CRTSCTS */
+       if ((old_termios->c_cflag & CRTSCTS) &&
+           !(tty->termios->c_cflag & CRTSCTS)) {
+               tty->hw_stopped = 0;
+               rs_360_start(tty);
+       }
+#endif
+
+#if 0
+       /*
+        * No need to wake up processes in open wait, since they
+        * sample the CLOCAL flag once, and don't recheck it.
+        * XXX  It's not clear whether the current behavior is correct
+        * or not.  Hence, this may change.....
+        */
+       if (!(old_termios->c_cflag & CLOCAL) &&
+           (tty->termios->c_cflag & CLOCAL))
+               wake_up_interruptible(&info->open_wait);
+#endif
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ * 
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void rs_360_close(struct tty_struct *tty, struct file * filp)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       /* struct async_state *state; */
+       struct serial_state *state;
+       unsigned long   flags;
+       int             idx;
+       volatile struct smc_regs        *smcp;
+       volatile struct scc_regs        *sccp;
+
+       if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
+               return;
+
+       state = info->state;
+       
+       local_irq_save(flags);
+       
+       if (tty_hung_up_p(filp)) {
+               DBG_CNT("before DEC-hung");
+               local_irq_restore(flags);
+               return;
+       }
+       
+#ifdef SERIAL_DEBUG_OPEN
+       printk("rs_close ttys%d, count = %d\n", info->line, state->count);
+#endif
+       if ((tty->count == 1) && (state->count != 1)) {
+               /*
+                * Uh, oh.  tty->count is 1, which means that the tty
+                * structure will be freed.  state->count should always
+                * be one in these conditions.  If it's greater than
+                * one, we've got real problems, since it means the
+                * serial port won't be shutdown.
+                */
+               printk("rs_close: bad serial port count; tty->count is 1, "
+                      "state->count is %d\n", state->count);
+               state->count = 1;
+       }
+       if (--state->count < 0) {
+               printk("rs_close: bad serial port count for ttys%d: %d\n",
+                      info->line, state->count);
+               state->count = 0;
+       }
+       if (state->count) {
+               DBG_CNT("before DEC-2");
+               local_irq_restore(flags);
+               return;
+       }
+       info->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 (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+               tty_wait_until_sent(tty, info->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.
+        */
+       info->read_status_mask &= ~BD_SC_EMPTY;
+       if (info->flags & ASYNC_INITIALIZED) {
+
+               idx = PORT_NUM(info->state->smc_scc_num);
+               if (info->state->smc_scc_num & NUM_IS_SCC) {
+                       sccp = &pquicc->scc_regs[idx];
+                       sccp->scc_sccm &= ~UART_SCCM_RX;
+                       sccp->scc_gsmr.w.low &= ~SCC_GSMRL_ENR;
+               } else {
+                       smcp = &pquicc->smc_regs[idx];
+                       smcp->smc_smcm &= ~SMCM_RX;
+                       smcp->smc_smcmr &= ~SMCMR_REN;
+               }
+               /*
+                * Before we drop DTR, make sure the UART transmitter
+                * has completely drained; this is especially
+                * important if there is a transmit FIFO!
+                */
+               rs_360_wait_until_sent(tty, info->timeout);
+       }
+       shutdown(info);
+       rs_360_flush_buffer(tty);
+       tty_ldisc_flush(tty);           
+       tty->closing = 0;
+       info->event = 0;
+       info->port.tty = NULL;
+       if (info->blocked_open) {
+               if (info->close_delay) {
+                       msleep_interruptible(jiffies_to_msecs(info->close_delay));
+               }
+               wake_up_interruptible(&info->open_wait);
+       }
+       info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
+       wake_up_interruptible(&info->close_wait);
+       local_irq_restore(flags);
+}
+
+/*
+ * rs_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       unsigned long orig_jiffies, char_time;
+       /*int lsr;*/
+       volatile QUICC_BD *bdp;
+       
+       if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
+               return;
+
+#ifdef maybe
+       if (info->state->type == PORT_UNKNOWN)
+               return;
+#endif
+
+       orig_jiffies = jiffies;
+       /*
+        * Set the check interval to be 1/5 of the estimated time to
+        * send a single character, and make it at least 1.  The check
+        * interval should also be less than the timeout.
+        * 
+        * Note: we have to use pretty tight timings here to satisfy
+        * the NIST-PCTS.
+        */
+       char_time = 1;
+       if (timeout)
+               char_time = min(char_time, (unsigned long)timeout);
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+       printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
+       printk("jiff=%lu...", jiffies);
+#endif
+
+       /* We go through the loop at least once because we can't tell
+        * exactly when the last character exits the shifter.  There can
+        * be at least two characters waiting to be sent after the buffers
+        * are empty.
+        */
+       do {
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+               printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
+#endif
+/*             current->counter = 0;    make us low-priority */
+               msleep_interruptible(jiffies_to_msecs(char_time));
+               if (signal_pending(current))
+                       break;
+               if (timeout && (time_after(jiffies, orig_jiffies + timeout)))
+                       break;
+               /* The 'tx_cur' is really the next buffer to send.  We
+                * have to back up to the previous BD and wait for it
+                * to go.  This isn't perfect, because all this indicates
+                * is the buffer is available.  There are still characters
+                * in the CPM FIFO.
+                */
+               bdp = info->tx_cur;
+               if (bdp == info->tx_bd_base)
+                       bdp += (TX_NUM_FIFO-1);
+               else
+                       bdp--;
+       } while (bdp->status & BD_SC_READY);
+       current->state = TASK_RUNNING;
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+       printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
+#endif
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+static void rs_360_hangup(struct tty_struct *tty)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       struct serial_state *state = info->state;
+       
+       if (serial_paranoia_check(info, tty->name, "rs_hangup"))
+               return;
+
+       state = info->state;
+       
+       rs_360_flush_buffer(tty);
+       shutdown(info);
+       info->event = 0;
+       state->count = 0;
+       info->flags &= ~ASYNC_NORMAL_ACTIVE;
+       info->port.tty = NULL;
+       wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+                          ser_info_t *info)
+{
+#ifdef DO_THIS_LATER
+       DECLARE_WAITQUEUE(wait, current);
+#endif
+       struct serial_state *state = info->state;
+       int             retval;
+       int             do_clocal = 0;
+
+       /*
+        * 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) ||
+           (info->flags & ASYNC_CLOSING)) {
+               if (info->flags & ASYNC_CLOSING)
+                       interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+               if (info->flags & ASYNC_HUP_NOTIFY)
+                       return -EAGAIN;
+               else
+                       return -ERESTARTSYS;
+#else
+               return -EAGAIN;
+#endif
+       }
+
+       /*
+        * If non-blocking mode is set, or the port is not enabled,
+        * then make the check up front and then exit.
+        * If this is an SMC port, we don't have modem control to wait
+        * for, so just get out here.
+        */
+       if ((filp->f_flags & O_NONBLOCK) ||
+           (tty->flags & (1 << TTY_IO_ERROR)) ||
+           !(info->state->smc_scc_num & NUM_IS_SCC)) {
+               info->flags |= ASYNC_NORMAL_ACTIVE;
+               return 0;
+       }
+
+       if (tty->termios->c_cflag & CLOCAL)
+               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, state->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;
+#ifdef DO_THIS_LATER
+       add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+       printk("block_til_ready before block: ttys%d, count = %d\n",
+              state->line, state->count);
+#endif
+       local_irq_disable();
+       if (!tty_hung_up_p(filp)) 
+               state->count--;
+       local_irq_enable();
+       info->blocked_open++;
+       while (1) {
+               local_irq_disable();
+               if (tty->termios->c_cflag & CBAUD)
+                       serial_out(info, UART_MCR,
+                                  serial_inp(info, UART_MCR) |
+                                  (UART_MCR_DTR | UART_MCR_RTS));
+               local_irq_enable();
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (tty_hung_up_p(filp) ||
+                   !(info->flags & ASYNC_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+                       if (info->flags & ASYNC_HUP_NOTIFY)
+                               retval = -EAGAIN;
+                       else
+                               retval = -ERESTARTSYS;  
+#else
+                       retval = -EAGAIN;
+#endif
+                       break;
+               }
+               if (!(info->flags & ASYNC_CLOSING) &&
+                   (do_clocal || (serial_in(info, UART_MSR) &
+                                  UART_MSR_DCD)))
+                       break;
+               if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+                       break;
+               }
+#ifdef SERIAL_DEBUG_OPEN
+               printk("block_til_ready blocking: ttys%d, count = %d\n",
+                      info->line, state->count);
+#endif
+               tty_unlock();
+               schedule();
+               tty_lock();
+       }
+       current->state = TASK_RUNNING;
+       remove_wait_queue(&info->open_wait, &wait);
+       if (!tty_hung_up_p(filp))
+               state->count++;
+       info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+       printk("block_til_ready after blocking: ttys%d, count = %d\n",
+              info->line, state->count);
+#endif
+#endif /* DO_THIS_LATER */
+       if (retval)
+               return retval;
+       info->flags |= ASYNC_NORMAL_ACTIVE;
+       return 0;
+}
+
+static int get_async_struct(int line, ser_info_t **ret_info)
+{
+       struct serial_state *sstate;
+
+       sstate = rs_table + line;
+       if (sstate->info) {
+               sstate->count++;
+               *ret_info = (ser_info_t *)sstate->info;
+               return 0;
+       }
+       else {
+               return -ENOMEM;
+       }
+}
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+static int rs_360_open(struct tty_struct *tty, struct file * filp)
+{
+       ser_info_t      *info;
+       int             retval, line;
+
+       line = tty->index;
+       if ((line < 0) || (line >= NR_PORTS))
+               return -ENODEV;
+       retval = get_async_struct(line, &info);
+       if (retval)
+               return retval;
+       if (serial_paranoia_check(info, tty->name, "rs_open"))
+               return -ENODEV;
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("rs_open %s, count = %d\n", tty->name, info->state->count);
+#endif
+       tty->driver_data = info;
+       info->port.tty = tty;
+
+       /*
+        * Start up serial port
+        */
+       retval = startup(info);
+       if (retval)
+               return retval;
+
+       retval = block_til_ready(tty, filp, info);
+       if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+               printk("rs_open returning after block_til_ready with %d\n",
+                      retval);
+#endif
+               return retval;
+       }
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("rs_open %s successful...", tty->name);
+#endif
+       return 0;
+}
+
+/*
+ * /proc fs routines....
+ */
+
+static inline int line_info(char *buf, struct serial_state *state)
+{
+#ifdef notdef
+       struct async_struct *info = state->info, scr_info;
+       char    stat_buf[30], control, status;
+#endif
+       int     ret;
+
+       ret = sprintf(buf, "%d: uart:%s port:%X irq:%d",
+                     state->line,
+                     (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC",
+                     (unsigned int)(state->port), state->irq);
+
+       if (!state->port || (state->type == PORT_UNKNOWN)) {
+               ret += sprintf(buf+ret, "\n");
+               return ret;
+       }
+
+#ifdef notdef
+       /*
+        * Figure out the current RS-232 lines
+        */
+       if (!info) {
+               info = &scr_info;       /* This is just for serial_{in,out} */
+
+               info->magic = SERIAL_MAGIC;
+               info->port = state->port;
+               info->flags = state->flags;
+               info->quot = 0;
+               info->port.tty = NULL;
+       }
+       local_irq_disable();
+       status = serial_in(info, UART_MSR);
+       control = info ? info->MCR : serial_in(info, UART_MCR);
+       local_irq_enable();
+       
+       stat_buf[0] = 0;
+       stat_buf[1] = 0;
+       if (control & UART_MCR_RTS)
+               strcat(stat_buf, "|RTS");
+       if (status & UART_MSR_CTS)
+               strcat(stat_buf, "|CTS");
+       if (control & UART_MCR_DTR)
+               strcat(stat_buf, "|DTR");
+       if (status & UART_MSR_DSR)
+               strcat(stat_buf, "|DSR");
+       if (status & UART_MSR_DCD)
+               strcat(stat_buf, "|CD");
+       if (status & UART_MSR_RI)
+               strcat(stat_buf, "|RI");
+
+       if (info->quot) {
+               ret += sprintf(buf+ret, " baud:%d",
+                              state->baud_base / info->quot);
+       }
+
+       ret += sprintf(buf+ret, " tx:%d rx:%d",
+                     state->icount.tx, state->icount.rx);
+
+       if (state->icount.frame)
+               ret += sprintf(buf+ret, " fe:%d", state->icount.frame);
+       
+       if (state->icount.parity)
+               ret += sprintf(buf+ret, " pe:%d", state->icount.parity);
+       
+       if (state->icount.brk)
+               ret += sprintf(buf+ret, " brk:%d", state->icount.brk);  
+
+       if (state->icount.overrun)
+               ret += sprintf(buf+ret, " oe:%d", state->icount.overrun);
+
+       /*
+        * Last thing is the RS-232 status lines
+        */
+       ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+#endif
+       return ret;
+}
+
+int rs_360_read_proc(char *page, char **start, off_t off, int count,
+                int *eof, void *data)
+{
+       int i, len = 0;
+       off_t   begin = 0;
+
+       len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
+       for (i = 0; i < NR_PORTS && len < 4000; i++) {
+               len += line_info(page + len, &rs_table[i]);
+               if (len+begin > off+count)
+                       goto done;
+               if (len+begin < off) {
+                       begin += len;
+                       len = 0;
+               }
+       }
+       *eof = 1;
+done:
+       if (off >= len+begin)
+               return 0;
+       *start = page + (begin-off);
+       return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * rs_init() and friends
+ *
+ * rs_init() is called at boot-time to initialize the serial driver.
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * This routine prints out the appropriate serial driver version
+ * number, and identifies which options were configured into this
+ * driver.
+ */
+static _INLINE_ void show_serial_version(void)
+{
+       printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
+}
+
+
+/*
+ * The serial console driver used during boot.  Note that these names
+ * clash with those found in "serial.c", so we currently can't support
+ * the 16xxx uarts and these at the same time.  I will fix this to become
+ * an indirect function call from tty_io.c (or something).
+ */
+
+#ifdef CONFIG_SERIAL_CONSOLE
+
+/*
+ * Print a string to the serial port trying not to disturb any possible
+ * real use of the port...
+ */
+static void my_console_write(int idx, const char *s,
+                               unsigned count)
+{
+       struct          serial_state    *ser;
+       ser_info_t              *info;
+       unsigned                i;
+       QUICC_BD                *bdp, *bdbase;
+       volatile struct smc_uart_pram   *up;
+       volatile        u_char          *cp;
+
+       ser = rs_table + idx;
+
+
+       /* If the port has been initialized for general use, we have
+        * to use the buffer descriptors allocated there.  Otherwise,
+        * we simply use the single buffer allocated.
+        */
+       if ((info = (ser_info_t *)ser->info) != NULL) {
+               bdp = info->tx_cur;
+               bdbase = info->tx_bd_base;
+       }
+       else {
+               /* Pointer to UART in parameter ram.
+               */
+               /* up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; */
+               up = &pquicc->pram[ser->port].scc.pothers.idma_smc.psmc.u;
+
+               /* Get the address of the host memory buffer.
+                */
+               bdp = bdbase = (QUICC_BD *)((uint)pquicc + (uint)up->tbase);
+       }
+
+       /*
+        * We need to gracefully shut down the transmitter, disable
+        * interrupts, then send our bytes out.
+        */
+
+       /*
+        * Now, do each character.  This is not as bad as it looks
+        * since this is a holding FIFO and not a transmitting FIFO.
+        * We could add the complexity of filling the entire transmit
+        * buffer, but we would just wait longer between accesses......
+        */
+       for (i = 0; i < count; i++, s++) {
+               /* Wait for transmitter fifo to empty.
+                * Ready indicates output is ready, and xmt is doing
+                * that, not that it is ready for us to send.
+                */
+               while (bdp->status & BD_SC_READY);
+
+               /* Send the character out.
+                */
+               cp = bdp->buf;
+               *cp = *s;
+               
+               bdp->length = 1;
+               bdp->status |= BD_SC_READY;
+
+               if (bdp->status & BD_SC_WRAP)
+                       bdp = bdbase;
+               else
+                       bdp++;
+
+               /* if a LF, also do CR... */
+               if (*s == 10) {
+                       while (bdp->status & BD_SC_READY);
+                       /* cp = __va(bdp->buf); */
+                       cp = bdp->buf;
+                       *cp = 13;
+                       bdp->length = 1;
+                       bdp->status |= BD_SC_READY;
+
+                       if (bdp->status & BD_SC_WRAP) {
+                               bdp = bdbase;
+                       }
+                       else {
+                               bdp++;
+                       }
+               }
+       }
+
+       /*
+        * Finally, Wait for transmitter & holding register to empty
+        *  and restore the IER
+        */
+       while (bdp->status & BD_SC_READY);
+
+       if (info)
+               info->tx_cur = (QUICC_BD *)bdp;
+}
+
+static void serial_console_write(struct console *c, const char *s,
+                               unsigned count)
+{
+#ifdef CONFIG_KGDB
+       /* Try to let stub handle output. Returns true if it did. */ 
+       if (kgdb_output_string(s, count))
+               return;
+#endif
+       my_console_write(c->index, s, count);
+}
+
+
+
+/*void console_print_68360(const char *p)
+{
+       const char *cp = p;
+       int i;
+
+       for (i=0;cp[i]!=0;i++);
+
+       serial_console_write (p, i);
+
+       //Comment this if you want to have a strict interrupt-driven output
+       //rs_fair_output();
+
+       return;
+}*/
+
+
+
+
+
+
+#ifdef CONFIG_XMON
+int
+xmon_360_write(const char *s, unsigned count)
+{
+       my_console_write(0, s, count);
+       return(count);
+}
+#endif
+
+#ifdef CONFIG_KGDB
+void
+putDebugChar(char ch)
+{
+       my_console_write(0, &ch, 1);
+}
+#endif
+
+/*
+ * Receive character from the serial port.  This only works well
+ * before the port is initialized for real use.
+ */
+static int my_console_wait_key(int idx, int xmon, char *obuf)
+{
+       struct serial_state             *ser;
+       u_char                  c, *cp;
+       ser_info_t              *info;
+       QUICC_BD                *bdp;
+       volatile struct smc_uart_pram   *up;
+       int                             i;
+
+       ser = rs_table + idx;
+
+       /* Get the address of the host memory buffer.
+        * If the port has been initialized for general use, we must
+        * use information from the port structure.
+        */
+       if ((info = (ser_info_t *)ser->info))
+               bdp = info->rx_cur;
+       else
+               /* bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_rbase]; */
+               bdp = (QUICC_BD *)((uint)pquicc + (uint)up->tbase);
+
+       /* Pointer to UART in parameter ram.
+        */
+       /* up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; */
+       up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u;
+
+       /*
+        * We need to gracefully shut down the receiver, disable
+        * interrupts, then read the input.
+        * XMON just wants a poll.  If no character, return -1, else
+        * return the character.
+        */
+       if (!xmon) {
+               while (bdp->status & BD_SC_EMPTY);
+       }
+       else {
+               if (bdp->status & BD_SC_EMPTY)
+                       return -1;
+       }
+
+       cp = (char *)bdp->buf;
+
+       if (obuf) {
+               i = c = bdp->length;
+               while (i-- > 0)
+                       *obuf++ = *cp++;
+       }
+       else {
+               c = *cp;
+       }
+       bdp->status |= BD_SC_EMPTY;
+
+       if (info) {
+               if (bdp->status & BD_SC_WRAP) {
+                       bdp = info->rx_bd_base;
+               }
+               else {
+                       bdp++;
+               }
+               info->rx_cur = (QUICC_BD *)bdp;
+       }
+
+       return((int)c);
+}
+
+static int serial_console_wait_key(struct console *co)
+{
+       return(my_console_wait_key(co->index, 0, NULL));
+}
+
+#ifdef CONFIG_XMON
+int
+xmon_360_read_poll(void)
+{
+       return(my_console_wait_key(0, 1, NULL));
+}
+
+int
+xmon_360_read_char(void)
+{
+       return(my_console_wait_key(0, 0, NULL));
+}
+#endif
+
+#ifdef CONFIG_KGDB
+static char kgdb_buf[RX_BUF_SIZE], *kgdp;
+static int kgdb_chars;
+
+unsigned char
+getDebugChar(void)
+{
+       if (kgdb_chars <= 0) {
+               kgdb_chars = my_console_wait_key(0, 0, kgdb_buf);
+               kgdp = kgdb_buf;
+       }
+       kgdb_chars--;
+
+       return(*kgdp++);
+}
+
+void kgdb_interruptible(int state)
+{
+}
+void kgdb_map_scc(void)
+{
+       struct          serial_state *ser;
+       uint            mem_addr;
+       volatile        QUICC_BD                *bdp;
+       volatile        smc_uart_t      *up;
+
+       cpmp = (cpm360_t *)&(((immap_t *)IMAP_ADDR)->im_cpm);
+
+       /* To avoid data cache CPM DMA coherency problems, allocate a
+        * buffer in the CPM DPRAM.  This will work until the CPM and
+        * serial ports are initialized.  At that time a memory buffer
+        * will be allocated.
+        * The port is already initialized from the boot procedure, all
+        * we do here is give it a different buffer and make it a FIFO.
+        */
+
+       ser = rs_table;
+
+       /* Right now, assume we are using SMCs.
+       */
+       up = (smc_uart_t *)&cpmp->cp_dparam[ser->port];
+
+       /* Allocate space for an input FIFO, plus a few bytes for output.
+        * Allocate bytes to maintain word alignment.
+        */
+       mem_addr = (uint)(&cpmp->cp_dpmem[0x1000]);
+
+       /* Set the physical address of the host memory buffers in
+        * the buffer descriptors.
+        */
+       bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_rbase];
+       bdp->buf = mem_addr;
+
+       bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_tbase];
+       bdp->buf = mem_addr+RX_BUF_SIZE;
+
+       up->smc_mrblr = RX_BUF_SIZE;            /* receive buffer length */
+       up->smc_maxidl = RX_BUF_SIZE;
+}
+#endif
+
+static struct tty_struct *serial_console_device(struct console *c, int *index)
+{
+       *index = c->index;
+       return serial_driver;
+}
+
+
+struct console sercons = {
+       .name           = "ttyS",
+       .write          = serial_console_write,
+       .device         = serial_console_device,
+       .wait_key       = serial_console_wait_key,
+       .setup          = serial_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = CONFIG_SERIAL_CONSOLE_PORT, 
+};
+
+
+
+/*
+ *     Register console.
+ */
+long console_360_init(long kmem_start, long kmem_end)
+{
+       register_console(&sercons);
+       /*register_console (console_print_68360); - 2.0.38 only required a write
+      function pointer. */
+       return kmem_start;
+}
+
+#endif
+
+/* Index in baud rate table of the default console baud rate.
+*/
+static int     baud_idx;
+
+static const struct tty_operations rs_360_ops = {
+       .owner = THIS_MODULE,
+       .open = rs_360_open,
+       .close = rs_360_close,
+       .write = rs_360_write,
+       .put_char = rs_360_put_char,
+       .write_room = rs_360_write_room,
+       .chars_in_buffer = rs_360_chars_in_buffer,
+       .flush_buffer = rs_360_flush_buffer,
+       .ioctl = rs_360_ioctl,
+       .throttle = rs_360_throttle,
+       .unthrottle = rs_360_unthrottle,
+       /* .send_xchar = rs_360_send_xchar, */
+       .set_termios = rs_360_set_termios,
+       .stop = rs_360_stop,
+       .start = rs_360_start,
+       .hangup = rs_360_hangup,
+       /* .wait_until_sent = rs_360_wait_until_sent, */
+       /* .read_proc = rs_360_read_proc, */
+       .tiocmget = rs_360_tiocmget,
+       .tiocmset = rs_360_tiocmset,
+};
+
+static int __init rs_360_init(void)
+{
+       struct serial_state * state;
+       ser_info_t      *info;
+       void       *mem_addr;
+       uint            dp_addr, iobits;
+       int                 i, j, idx;
+       ushort          chan;
+       QUICC_BD        *bdp;
+       volatile        QUICC           *cp;
+       volatile        struct smc_regs *sp;
+       volatile        struct smc_uart_pram    *up;
+       volatile        struct scc_regs *scp;
+       volatile        struct uart_pram        *sup;
+       /* volatile     immap_t         *immap; */
+       
+       serial_driver = alloc_tty_driver(NR_PORTS);
+       if (!serial_driver)
+               return -1;
+
+       show_serial_version();
+
+       serial_driver->name = "ttyS";
+       serial_driver->major = TTY_MAJOR;
+       serial_driver->minor_start = 64;
+       serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
+       serial_driver->subtype = SERIAL_TYPE_NORMAL;
+       serial_driver->init_termios = tty_std_termios;
+       serial_driver->init_termios.c_cflag =
+               baud_idx | CS8 | CREAD | HUPCL | CLOCAL;
+       serial_driver->flags = TTY_DRIVER_REAL_RAW;
+       tty_set_operations(serial_driver, &rs_360_ops);
+       
+       if (tty_register_driver(serial_driver))
+               panic("Couldn't register serial driver\n");
+
+       cp = pquicc;    /* Get pointer to Communication Processor */
+       /* immap = (immap_t *)IMAP_ADDR; */     /* and to internal registers */
+
+
+       /* Configure SCC2, SCC3, and SCC4 instead of port A parallel I/O.
+        */
+       /* The "standard" configuration through the 860.
+       */
+/*     immap->im_ioport.iop_papar |= 0x00fc; */
+/*     immap->im_ioport.iop_padir &= ~0x00fc; */
+/*     immap->im_ioport.iop_paodr &= ~0x00fc; */
+       cp->pio_papar |= 0x00fc;
+       cp->pio_padir &= ~0x00fc;
+       /* cp->pio_paodr &= ~0x00fc; */
+
+
+       /* Since we don't yet do modem control, connect the port C pins
+        * as general purpose I/O.  This will assert CTS and CD for the
+        * SCC ports.
+        */
+       /* FIXME: see 360um p.7-365 and 860um p.34-12 
+        * I can't make sense of these bits - mleslie*/
+/*     immap->im_ioport.iop_pcdir |= 0x03c6; */
+/*     immap->im_ioport.iop_pcpar &= ~0x03c6; */
+
+/*     cp->pio_pcdir |= 0x03c6; */
+/*     cp->pio_pcpar &= ~0x03c6; */
+
+
+
+       /* Connect SCC2 and SCC3 to NMSI.  Connect BRG3 to SCC2 and
+        * BRG4 to SCC3.
+        */
+       cp->si_sicr &= ~0x00ffff00;
+       cp->si_sicr |=  0x001b1200;
+
+#ifdef CONFIG_PP04
+       /* Frequentis PP04 forced to RS-232 until we know better.
+        * Port C 12 and 13 low enables RS-232 on SCC3 and SCC4.
+        */
+       immap->im_ioport.iop_pcdir |= 0x000c;
+       immap->im_ioport.iop_pcpar &= ~0x000c;
+       immap->im_ioport.iop_pcdat &= ~0x000c;
+
+       /* This enables the TX driver.
+       */
+       cp->cp_pbpar &= ~0x6000;
+       cp->cp_pbdat &= ~0x6000;
+#endif
+
+       for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
+               state->magic = SSTATE_MAGIC;
+               state->line = i;
+               state->type = PORT_UNKNOWN;
+               state->custom_divisor = 0;
+               state->close_delay = 5*HZ/10;
+               state->closing_wait = 30*HZ;
+               state->icount.cts = state->icount.dsr = 
+                       state->icount.rng = state->icount.dcd = 0;
+               state->icount.rx = state->icount.tx = 0;
+               state->icount.frame = state->icount.parity = 0;
+               state->icount.overrun = state->icount.brk = 0;
+               printk(KERN_INFO "ttyS%d at irq 0x%02x is an %s\n",
+                      i, (unsigned int)(state->irq),
+                      (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC");
+
+#ifdef CONFIG_SERIAL_CONSOLE
+               /* If we just printed the message on the console port, and
+                * we are about to initialize it for general use, we have
+                * to wait a couple of character times for the CR/NL to
+                * make it out of the transmit buffer.
+                */
+               if (i == CONFIG_SERIAL_CONSOLE_PORT)
+                       mdelay(8);
+
+
+/*             idx = PORT_NUM(info->state->smc_scc_num); */
+/*             if (info->state->smc_scc_num & NUM_IS_SCC) */
+/*                     chan = scc_chan_map[idx]; */
+/*             else */
+/*                     chan = smc_chan_map[idx]; */
+
+/*             cp->cp_cr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG; */
+/*             while (cp->cp_cr & CPM_CR_FLG); */
+
+#endif
+               /* info = kmalloc(sizeof(ser_info_t), GFP_KERNEL); */
+               info = &quicc_ser_info[i];
+               if (info) {
+                       memset (info, 0, sizeof(ser_info_t));
+                       info->magic = SERIAL_MAGIC;
+                       info->line = i;
+                       info->flags = state->flags;
+                       INIT_WORK(&info->tqueue, do_softint, info);
+                       INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info);
+                       init_waitqueue_head(&info->open_wait);
+                       init_waitqueue_head(&info->close_wait);
+                       info->state = state;
+                       state->info = (struct async_struct *)info;
+
+                       /* We need to allocate a transmit and receive buffer
+                        * descriptors from dual port ram, and a character
+                        * buffer area from host mem.
+                        */
+                       dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * RX_NUM_FIFO);
+
+                       /* Allocate space for FIFOs in the host memory.
+                        *  (for now this is from a static array of buffers :(
+                        */
+                       /* mem_addr = m360_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE); */
+                       /* mem_addr = kmalloc (RX_NUM_FIFO * RX_BUF_SIZE, GFP_BUFFER); */
+                       mem_addr = &rx_buf_pool[i * RX_NUM_FIFO * RX_BUF_SIZE];
+
+                       /* Set the physical address of the host memory
+                        * buffers in the buffer descriptors, and the
+                        * virtual address for us to work with.
+                        */
+                       bdp = (QUICC_BD *)((uint)pquicc + dp_addr);
+                       info->rx_cur = info->rx_bd_base = bdp;
+
+                       /* initialize rx buffer descriptors */
+                       for (j=0; j<(RX_NUM_FIFO-1); j++) {
+                               bdp->buf = &rx_buf_pool[(i * RX_NUM_FIFO + j ) * RX_BUF_SIZE];
+                               bdp->status = BD_SC_EMPTY | BD_SC_INTRPT;
+                               mem_addr += RX_BUF_SIZE;
+                               bdp++;
+                       }
+                       bdp->buf = &rx_buf_pool[(i * RX_NUM_FIFO + j ) * RX_BUF_SIZE];
+                       bdp->status = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
+
+
+                       idx = PORT_NUM(info->state->smc_scc_num);
+                       if (info->state->smc_scc_num & NUM_IS_SCC) {
+
+#if defined (CONFIG_UCQUICC) && 1
+                               /* set the transceiver mode to RS232 */
+                               sipex_mode_bits &= ~(uint)SIPEX_MODE(idx,0x0f); /* clear current mode */
+                               sipex_mode_bits |= (uint)SIPEX_MODE(idx,0x02);
+                               *(uint *)_periph_base = sipex_mode_bits;
+                               /* printk ("sipex bits = 0x%08x\n", sipex_mode_bits); */
+#endif
+                       }
+
+                       dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * TX_NUM_FIFO);
+
+                       /* Allocate space for FIFOs in the host memory.
+                       */
+                       /* mem_addr = m360_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE); */
+                       /* mem_addr = kmalloc (TX_NUM_FIFO * TX_BUF_SIZE, GFP_BUFFER); */
+                       mem_addr = &tx_buf_pool[i * TX_NUM_FIFO * TX_BUF_SIZE];
+
+                       /* Set the physical address of the host memory
+                        * buffers in the buffer descriptors, and the
+                        * virtual address for us to work with.
+                        */
+                       /* bdp = (QUICC_BD *)&cp->cp_dpmem[dp_addr]; */
+                       bdp = (QUICC_BD *)((uint)pquicc + dp_addr);
+                       info->tx_cur = info->tx_bd_base = (QUICC_BD *)bdp;
+
+                       /* initialize tx buffer descriptors */
+                       for (j=0; j<(TX_NUM_FIFO-1); j++) {
+                               bdp->buf = &tx_buf_pool[(i * TX_NUM_FIFO + j ) * TX_BUF_SIZE];
+                               bdp->status = BD_SC_INTRPT;
+                               mem_addr += TX_BUF_SIZE;
+                               bdp++;
+                       }
+                       bdp->buf = &tx_buf_pool[(i * TX_NUM_FIFO + j ) * TX_BUF_SIZE];
+                       bdp->status = (BD_SC_WRAP | BD_SC_INTRPT);
+
+                       if (info->state->smc_scc_num & NUM_IS_SCC) {
+                               scp = &pquicc->scc_regs[idx];
+                               sup = &pquicc->pram[info->state->port].scc.pscc.u;
+                               sup->rbase = dp_addr;
+                               sup->tbase = dp_addr;
+
+                               /* Set up the uart parameters in the
+                                * parameter ram.
+                                */
+                               sup->rfcr = SMC_EB;
+                               sup->tfcr = SMC_EB;
+
+                               /* Set this to 1 for now, so we get single
+                                * character interrupts.  Using idle character
+                                * time requires some additional tuning.
+                                */
+                               sup->mrblr = 1;
+                               sup->max_idl = 0;
+                               sup->brkcr = 1;
+                               sup->parec = 0;
+                               sup->frmer = 0;
+                               sup->nosec = 0;
+                               sup->brkec = 0;
+                               sup->uaddr1 = 0;
+                               sup->uaddr2 = 0;
+                               sup->toseq = 0;
+                               {
+                                       int i;
+                                       for (i=0;i<8;i++)
+                                               sup->cc[i] = 0x8000;
+                               }
+                               sup->rccm = 0xc0ff;
+
+                               /* Send the CPM an initialize command.
+                               */
+                               chan = scc_chan_map[idx];
+
+                               /* execute the INIT RX & TX PARAMS command for this channel. */
+                               cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+                               while (cp->cp_cr & CPM_CR_FLG);
+
+                               /* Set UART mode, 8 bit, no parity, one stop.
+                                * Enable receive and transmit.
+                                */
+                               scp->scc_gsmr.w.high = 0;
+                               scp->scc_gsmr.w.low = 
+                                       (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
+
+                               /* Disable all interrupts and clear all pending
+                                * events.
+                                */
+                               scp->scc_sccm = 0;
+                               scp->scc_scce = 0xffff;
+                               scp->scc_dsr = 0x7e7e;
+                               scp->scc_psmr = 0x3000;
+
+                               /* If the port is the console, enable Rx and Tx.
+                               */
+#ifdef CONFIG_SERIAL_CONSOLE
+                               if (i == CONFIG_SERIAL_CONSOLE_PORT)
+                                       scp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+#endif
+                       }
+                       else {
+                               /* Configure SMCs Tx/Rx instead of port B
+                                * parallel I/O.
+                                */
+                               up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u;
+                               up->rbase = dp_addr;
+
+                               iobits = 0xc0 << (idx * 4);
+                               cp->pip_pbpar |= iobits;
+                               cp->pip_pbdir &= ~iobits;
+                               cp->pip_pbodr &= ~iobits;
+
+
+                               /* Connect the baud rate generator to the
+                                * SMC based upon index in rs_table.  Also
+                                * make sure it is connected to NMSI.
+                                */
+                               cp->si_simode &= ~(0xffff << (idx * 16));
+                               cp->si_simode |= (i << ((idx * 16) + 12));
+
+                               up->tbase = dp_addr;
+
+                               /* Set up the uart parameters in the
+                                * parameter ram.
+                                */
+                               up->rfcr = SMC_EB;
+                               up->tfcr = SMC_EB;
+
+                               /* Set this to 1 for now, so we get single
+                                * character interrupts.  Using idle character
+                                * time requires some additional tuning.
+                                */
+                               up->mrblr = 1;
+                               up->max_idl = 0;
+                               up->brkcr = 1;
+
+                               /* Send the CPM an initialize command.
+                               */
+                               chan = smc_chan_map[idx];
+
+                               cp->cp_cr = mk_cr_cmd(chan,
+                                                                         CPM_CR_INIT_TRX) | CPM_CR_FLG;
+#ifdef CONFIG_SERIAL_CONSOLE
+                               if (i == CONFIG_SERIAL_CONSOLE_PORT)
+                                       printk("");
+#endif
+                               while (cp->cp_cr & CPM_CR_FLG);
+
+                               /* Set UART mode, 8 bit, no parity, one stop.
+                                * Enable receive and transmit.
+                                */
+                               sp = &cp->smc_regs[idx];
+                               sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART;
+
+                               /* Disable all interrupts and clear all pending
+                                * events.
+                                */
+                               sp->smc_smcm = 0;
+                               sp->smc_smce = 0xff;
+
+                               /* If the port is the console, enable Rx and Tx.
+                               */
+#ifdef CONFIG_SERIAL_CONSOLE
+                               if (i == CONFIG_SERIAL_CONSOLE_PORT)
+                                       sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+#endif
+                       }
+
+                       /* Install interrupt handler.
+                       */
+                       /* cpm_install_handler(IRQ_MACHSPEC | state->irq, rs_360_interrupt, info);  */
+                       /*request_irq(IRQ_MACHSPEC | state->irq, rs_360_interrupt, */
+                       request_irq(state->irq, rs_360_interrupt,
+                                               IRQ_FLG_LOCK, "ttyS", (void *)info);
+
+                       /* Set up the baud rate generator.
+                       */
+                       m360_cpm_setbrg(i, baud_table[baud_idx]);
+
+               }
+       }
+
+       return 0;
+}
+module_init(rs_360_init);
+
+/* This must always be called before the rs_360_init() function, otherwise
+ * it blows away the port control information.
+ */
+//static int __init serial_console_setup( struct console *co, char *options)
+int serial_console_setup( struct console *co, char *options)
+{
+       struct          serial_state    *ser;
+       uint            mem_addr, dp_addr, bidx, idx, iobits;
+       ushort          chan;
+       QUICC_BD        *bdp;
+       volatile        QUICC                   *cp;
+       volatile        struct smc_regs *sp;
+       volatile        struct scc_regs *scp;
+       volatile        struct smc_uart_pram    *up;
+       volatile        struct uart_pram                *sup;
+
+/* mleslie TODO:
+ * add something to the 68k bootloader to store a desired initial console baud rate */
+
+/*     bd_t                                            *bd; */ /* a board info struct used by EPPC-bug */
+/*     bd = (bd_t *)__res; */
+
+       for (bidx = 0; bidx < (sizeof(baud_table) / sizeof(int)); bidx++)
+        /* if (bd->bi_baudrate == baud_table[bidx]) */
+               if (CONSOLE_BAUDRATE == baud_table[bidx])
+                       break;
+
+       /* co->cflag = CREAD|CLOCAL|bidx|CS8; */
+       baud_idx = bidx;
+
+       ser = rs_table + CONFIG_SERIAL_CONSOLE_PORT;
+
+       cp = pquicc;    /* Get pointer to Communication Processor */
+
+       idx = PORT_NUM(ser->smc_scc_num);
+       if (ser->smc_scc_num & NUM_IS_SCC) {
+
+               /* TODO: need to set up SCC pin assignment etc. here */
+               
+       }
+       else {
+               iobits = 0xc0 << (idx * 4);
+               cp->pip_pbpar |= iobits;
+               cp->pip_pbdir &= ~iobits;
+               cp->pip_pbodr &= ~iobits;
+
+               /* Connect the baud rate generator to the
+                * SMC based upon index in rs_table.  Also
+                * make sure it is connected to NMSI.
+                */
+               cp->si_simode &= ~(0xffff << (idx * 16));
+               cp->si_simode |= (idx << ((idx * 16) + 12));
+       }
+
+       /* When we get here, the CPM has been reset, so we need
+        * to configure the port.
+        * We need to allocate a transmit and receive buffer descriptor
+        * from dual port ram, and a character buffer area from host mem.
+        */
+
+       /* Allocate space for two buffer descriptors in the DP ram.
+       */
+       dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * CONSOLE_NUM_FIFO);
+
+       /* Allocate space for two 2 byte FIFOs in the host memory.
+        */
+       /* mem_addr = m360_cpm_hostalloc(8); */
+       mem_addr = (uint)console_fifos;
+
+
+       /* Set the physical address of the host memory buffers in
+        * the buffer descriptors.
+        */
+       /* bdp = (QUICC_BD *)&cp->cp_dpmem[dp_addr]; */
+       bdp = (QUICC_BD *)((uint)pquicc + dp_addr);
+       bdp->buf = (char *)mem_addr;
+       (bdp+1)->buf = (char *)(mem_addr+4);
+
+       /* For the receive, set empty and wrap.
+        * For transmit, set wrap.
+        */
+       bdp->status = BD_SC_EMPTY | BD_SC_WRAP;
+       (bdp+1)->status = BD_SC_WRAP;
+
+       /* Set up the uart parameters in the parameter ram.
+        */
+       if (ser->smc_scc_num & NUM_IS_SCC) {
+               scp = &cp->scc_regs[idx];
+               /* sup = (scc_uart_t *)&cp->cp_dparam[ser->port]; */
+               sup = &pquicc->pram[ser->port].scc.pscc.u;
+
+               sup->rbase = dp_addr;
+               sup->tbase = dp_addr + sizeof(QUICC_BD);
+
+               /* Set up the uart parameters in the
+                * parameter ram.
+                */
+               sup->rfcr = SMC_EB;
+               sup->tfcr = SMC_EB;
+
+               /* Set this to 1 for now, so we get single
+                * character interrupts.  Using idle character
+                * time requires some additional tuning.
+                */
+               sup->mrblr = 1;
+               sup->max_idl = 0;
+               sup->brkcr = 1;
+               sup->parec = 0;
+               sup->frmer = 0;
+               sup->nosec = 0;
+               sup->brkec = 0;
+               sup->uaddr1 = 0;
+               sup->uaddr2 = 0;
+               sup->toseq = 0;
+               {
+                       int i;
+                       for (i=0;i<8;i++)
+                               sup->cc[i] = 0x8000;
+               }
+               sup->rccm = 0xc0ff;
+
+               /* Send the CPM an initialize command.
+               */
+               chan = scc_chan_map[idx];
+
+               cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+               while (cp->cp_cr & CPM_CR_FLG);
+
+               /* Set UART mode, 8 bit, no parity, one stop.
+                * Enable receive and transmit.
+                */
+               scp->scc_gsmr.w.high = 0;
+               scp->scc_gsmr.w.low = 
+                       (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
+
+               /* Disable all interrupts and clear all pending
+                * events.
+                */
+               scp->scc_sccm = 0;
+               scp->scc_scce = 0xffff;
+               scp->scc_dsr = 0x7e7e;
+               scp->scc_psmr = 0x3000;
+
+               scp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+       }
+       else {
+               /* up = (smc_uart_t *)&cp->cp_dparam[ser->port]; */
+               up = &pquicc->pram[ser->port].scc.pothers.idma_smc.psmc.u;
+
+               up->rbase = dp_addr;    /* Base of receive buffer desc. */
+               up->tbase = dp_addr+sizeof(QUICC_BD);   /* Base of xmt buffer desc. */
+               up->rfcr = SMC_EB;
+               up->tfcr = SMC_EB;
+
+               /* Set this to 1 for now, so we get single character interrupts.
+               */
+               up->mrblr = 1;          /* receive buffer length */
+               up->max_idl = 0;                /* wait forever for next char */
+
+               /* Send the CPM an initialize command.
+               */
+               chan = smc_chan_map[idx];
+               cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+               while (cp->cp_cr & CPM_CR_FLG);
+
+               /* Set UART mode, 8 bit, no parity, one stop.
+                * Enable receive and transmit.
+                */
+               sp = &cp->smc_regs[idx];
+               sp->smc_smcmr = smcr_mk_clen(9) |  SMCMR_SM_UART;
+
+               /* And finally, enable Rx and Tx.
+               */
+               sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+       }
+
+       /* Set up the baud rate generator.
+       */
+       /* m360_cpm_setbrg((ser - rs_table), bd->bi_baudrate); */
+       m360_cpm_setbrg((ser - rs_table), CONSOLE_BAUDRATE);
+
+       return 0;
+}
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c
new file mode 100644 (file)
index 0000000..b25e6e4
--- /dev/null
@@ -0,0 +1,3377 @@
+/*
+ *  linux/drivers/char/8250.c
+ *
+ *  Driver for 8250/16550-type serial ports
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ *  Copyright (C) 2001 Russell King.
+ *
+ * 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.
+ *
+ * A note about mapbase / membase
+ *
+ *  mapbase is the physical address of the IO port.
+ *  membase is an 'ioremapped' cookie.
+ */
+
+#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/ratelimit.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_reg.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/serial_8250.h>
+#include <linux/nmi.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "8250.h"
+
+#ifdef CONFIG_SPARC
+#include "suncore.h"
+#endif
+
+/*
+ * Configuration:
+ *   share_irqs - whether we pass IRQF_SHARED to request_irq().  This option
+ *                is unsafe when used on edge-triggered interrupts.
+ */
+static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
+
+static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
+
+static struct uart_driver serial8250_reg;
+
+static int serial_index(struct uart_port *port)
+{
+       return (serial8250_reg.minor - 64) + port->line;
+}
+
+static unsigned int skip_txen_test; /* force skip of txen test at init time */
+
+/*
+ * Debugging.
+ */
+#if 0
+#define DEBUG_AUTOCONF(fmt...) printk(fmt)
+#else
+#define DEBUG_AUTOCONF(fmt...) do { } while (0)
+#endif
+
+#if 0
+#define DEBUG_INTR(fmt...)     printk(fmt)
+#else
+#define DEBUG_INTR(fmt...)     do { } while (0)
+#endif
+
+#define PASS_LIMIT     256
+
+#define BOTH_EMPTY     (UART_LSR_TEMT | UART_LSR_THRE)
+
+
+/*
+ * We default to IRQ0 for the "no irq" hack.   Some
+ * machine types want others as well - they're free
+ * to redefine this in their header file.
+ */
+#define is_real_interrupt(irq) ((irq) != 0)
+
+#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
+#define CONFIG_SERIAL_DETECT_IRQ 1
+#endif
+#ifdef CONFIG_SERIAL_8250_MANY_PORTS
+#define CONFIG_SERIAL_MANY_PORTS 1
+#endif
+
+/*
+ * HUB6 is always on.  This will be removed once the header
+ * files have been cleaned.
+ */
+#define CONFIG_HUB6 1
+
+#include <asm/serial.h>
+/*
+ * SERIAL_PORT_DFNS tells us about built-in ports that have no
+ * standard enumeration mechanism.   Platforms that can find all
+ * serial ports via mechanisms like ACPI or PCI need not supply it.
+ */
+#ifndef SERIAL_PORT_DFNS
+#define SERIAL_PORT_DFNS
+#endif
+
+static const struct old_serial_port old_serial_port[] = {
+       SERIAL_PORT_DFNS /* defined in asm/serial.h */
+};
+
+#define UART_NR        CONFIG_SERIAL_8250_NR_UARTS
+
+#ifdef CONFIG_SERIAL_8250_RSA
+
+#define PORT_RSA_MAX 4
+static unsigned long probe_rsa[PORT_RSA_MAX];
+static unsigned int probe_rsa_count;
+#endif /* CONFIG_SERIAL_8250_RSA  */
+
+struct uart_8250_port {
+       struct uart_port        port;
+       struct timer_list       timer;          /* "no irq" timer */
+       struct list_head        list;           /* ports on this IRQ */
+       unsigned short          capabilities;   /* port capabilities */
+       unsigned short          bugs;           /* port bugs */
+       unsigned int            tx_loadsz;      /* transmit fifo load size */
+       unsigned char           acr;
+       unsigned char           ier;
+       unsigned char           lcr;
+       unsigned char           mcr;
+       unsigned char           mcr_mask;       /* mask of user bits */
+       unsigned char           mcr_force;      /* mask of forced bits */
+       unsigned char           cur_iotype;     /* Running I/O type */
+
+       /*
+        * Some bits in registers are cleared on a read, so they must
+        * be saved whenever the register is read but the bits will not
+        * be immediately processed.
+        */
+#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
+       unsigned char           lsr_saved_flags;
+#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
+       unsigned char           msr_saved_flags;
+};
+
+struct irq_info {
+       struct                  hlist_node node;
+       int                     irq;
+       spinlock_t              lock;   /* Protects list not the hash */
+       struct list_head        *head;
+};
+
+#define NR_IRQ_HASH            32      /* Can be adjusted later */
+static struct hlist_head irq_lists[NR_IRQ_HASH];
+static DEFINE_MUTEX(hash_mutex);       /* Used to walk the hash */
+
+/*
+ * Here we define the default xmit fifo size used for each type of UART.
+ */
+static const struct serial8250_config uart_config[] = {
+       [PORT_UNKNOWN] = {
+               .name           = "unknown",
+               .fifo_size      = 1,
+               .tx_loadsz      = 1,
+       },
+       [PORT_8250] = {
+               .name           = "8250",
+               .fifo_size      = 1,
+               .tx_loadsz      = 1,
+       },
+       [PORT_16450] = {
+               .name           = "16450",
+               .fifo_size      = 1,
+               .tx_loadsz      = 1,
+       },
+       [PORT_16550] = {
+               .name           = "16550",
+               .fifo_size      = 1,
+               .tx_loadsz      = 1,
+       },
+       [PORT_16550A] = {
+               .name           = "16550A",
+               .fifo_size      = 16,
+               .tx_loadsz      = 16,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+               .flags          = UART_CAP_FIFO,
+       },
+       [PORT_CIRRUS] = {
+               .name           = "Cirrus",
+               .fifo_size      = 1,
+               .tx_loadsz      = 1,
+       },
+       [PORT_16650] = {
+               .name           = "ST16650",
+               .fifo_size      = 1,
+               .tx_loadsz      = 1,
+               .flags          = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
+       },
+       [PORT_16650V2] = {
+               .name           = "ST16650V2",
+               .fifo_size      = 32,
+               .tx_loadsz      = 16,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 |
+                                 UART_FCR_T_TRIG_00,
+               .flags          = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
+       },
+       [PORT_16750] = {
+               .name           = "TI16750",
+               .fifo_size      = 64,
+               .tx_loadsz      = 64,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 |
+                                 UART_FCR7_64BYTE,
+               .flags          = UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_AFE,
+       },
+       [PORT_STARTECH] = {
+               .name           = "Startech",
+               .fifo_size      = 1,
+               .tx_loadsz      = 1,
+       },
+       [PORT_16C950] = {
+               .name           = "16C950/954",
+               .fifo_size      = 128,
+               .tx_loadsz      = 128,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+               .flags          = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
+       },
+       [PORT_16654] = {
+               .name           = "ST16654",
+               .fifo_size      = 64,
+               .tx_loadsz      = 32,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 |
+                                 UART_FCR_T_TRIG_10,
+               .flags          = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
+       },
+       [PORT_16850] = {
+               .name           = "XR16850",
+               .fifo_size      = 128,
+               .tx_loadsz      = 128,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+               .flags          = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
+       },
+       [PORT_RSA] = {
+               .name           = "RSA",
+               .fifo_size      = 2048,
+               .tx_loadsz      = 2048,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11,
+               .flags          = UART_CAP_FIFO,
+       },
+       [PORT_NS16550A] = {
+               .name           = "NS16550A",
+               .fifo_size      = 16,
+               .tx_loadsz      = 16,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+               .flags          = UART_CAP_FIFO | UART_NATSEMI,
+       },
+       [PORT_XSCALE] = {
+               .name           = "XScale",
+               .fifo_size      = 32,
+               .tx_loadsz      = 32,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+               .flags          = UART_CAP_FIFO | UART_CAP_UUE,
+       },
+       [PORT_RM9000] = {
+               .name           = "RM9000",
+               .fifo_size      = 16,
+               .tx_loadsz      = 16,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+               .flags          = UART_CAP_FIFO,
+       },
+       [PORT_OCTEON] = {
+               .name           = "OCTEON",
+               .fifo_size      = 64,
+               .tx_loadsz      = 64,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+               .flags          = UART_CAP_FIFO,
+       },
+       [PORT_AR7] = {
+               .name           = "AR7",
+               .fifo_size      = 16,
+               .tx_loadsz      = 16,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00,
+               .flags          = UART_CAP_FIFO | UART_CAP_AFE,
+       },
+       [PORT_U6_16550A] = {
+               .name           = "U6_16550A",
+               .fifo_size      = 64,
+               .tx_loadsz      = 64,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+               .flags          = UART_CAP_FIFO | UART_CAP_AFE,
+       },
+};
+
+#if defined(CONFIG_MIPS_ALCHEMY)
+
+/* Au1x00 UART hardware has a weird register layout */
+static const u8 au_io_in_map[] = {
+       [UART_RX]  = 0,
+       [UART_IER] = 2,
+       [UART_IIR] = 3,
+       [UART_LCR] = 5,
+       [UART_MCR] = 6,
+       [UART_LSR] = 7,
+       [UART_MSR] = 8,
+};
+
+static const u8 au_io_out_map[] = {
+       [UART_TX]  = 1,
+       [UART_IER] = 2,
+       [UART_FCR] = 4,
+       [UART_LCR] = 5,
+       [UART_MCR] = 6,
+};
+
+/* sane hardware needs no mapping */
+static inline int map_8250_in_reg(struct uart_port *p, int offset)
+{
+       if (p->iotype != UPIO_AU)
+               return offset;
+       return au_io_in_map[offset];
+}
+
+static inline int map_8250_out_reg(struct uart_port *p, int offset)
+{
+       if (p->iotype != UPIO_AU)
+               return offset;
+       return au_io_out_map[offset];
+}
+
+#elif defined(CONFIG_SERIAL_8250_RM9K)
+
+static const u8
+       regmap_in[8] = {
+               [UART_RX]       = 0x00,
+               [UART_IER]      = 0x0c,
+               [UART_IIR]      = 0x14,
+               [UART_LCR]      = 0x1c,
+               [UART_MCR]      = 0x20,
+               [UART_LSR]      = 0x24,
+               [UART_MSR]      = 0x28,
+               [UART_SCR]      = 0x2c
+       },
+       regmap_out[8] = {
+               [UART_TX]       = 0x04,
+               [UART_IER]      = 0x0c,
+               [UART_FCR]      = 0x18,
+               [UART_LCR]      = 0x1c,
+               [UART_MCR]      = 0x20,
+               [UART_LSR]      = 0x24,
+               [UART_MSR]      = 0x28,
+               [UART_SCR]      = 0x2c
+       };
+
+static inline int map_8250_in_reg(struct uart_port *p, int offset)
+{
+       if (p->iotype != UPIO_RM9000)
+               return offset;
+       return regmap_in[offset];
+}
+
+static inline int map_8250_out_reg(struct uart_port *p, int offset)
+{
+       if (p->iotype != UPIO_RM9000)
+               return offset;
+       return regmap_out[offset];
+}
+
+#else
+
+/* sane hardware needs no mapping */
+#define map_8250_in_reg(up, offset) (offset)
+#define map_8250_out_reg(up, offset) (offset)
+
+#endif
+
+static unsigned int hub6_serial_in(struct uart_port *p, int offset)
+{
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       outb(p->hub6 - 1 + offset, p->iobase);
+       return inb(p->iobase + 1);
+}
+
+static void hub6_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       outb(p->hub6 - 1 + offset, p->iobase);
+       outb(value, p->iobase + 1);
+}
+
+static unsigned int mem_serial_in(struct uart_port *p, int offset)
+{
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       return readb(p->membase + offset);
+}
+
+static void mem_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       writeb(value, p->membase + offset);
+}
+
+static void mem32_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       writel(value, p->membase + offset);
+}
+
+static unsigned int mem32_serial_in(struct uart_port *p, int offset)
+{
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       return readl(p->membase + offset);
+}
+
+static unsigned int au_serial_in(struct uart_port *p, int offset)
+{
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       return __raw_readl(p->membase + offset);
+}
+
+static void au_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       __raw_writel(value, p->membase + offset);
+}
+
+static unsigned int tsi_serial_in(struct uart_port *p, int offset)
+{
+       unsigned int tmp;
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       if (offset == UART_IIR) {
+               tmp = readl(p->membase + (UART_IIR & ~3));
+               return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */
+       } else
+               return readb(p->membase + offset);
+}
+
+static void tsi_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       if (!((offset == UART_IER) && (value & UART_IER_UUE)))
+               writeb(value, p->membase + offset);
+}
+
+/* Save the LCR value so it can be re-written when a Busy Detect IRQ occurs. */
+static inline void dwapb_save_out_value(struct uart_port *p, int offset,
+                                       int value)
+{
+       struct uart_8250_port *up =
+               container_of(p, struct uart_8250_port, port);
+
+       if (offset == UART_LCR)
+               up->lcr = value;
+}
+
+/* Read the IER to ensure any interrupt is cleared before returning from ISR. */
+static inline void dwapb_check_clear_ier(struct uart_port *p, int offset)
+{
+       if (offset == UART_TX || offset == UART_IER)
+               p->serial_in(p, UART_IER);
+}
+
+static void dwapb_serial_out(struct uart_port *p, int offset, int value)
+{
+       int save_offset = offset;
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       dwapb_save_out_value(p, save_offset, value);
+       writeb(value, p->membase + offset);
+       dwapb_check_clear_ier(p, save_offset);
+}
+
+static void dwapb32_serial_out(struct uart_port *p, int offset, int value)
+{
+       int save_offset = offset;
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       dwapb_save_out_value(p, save_offset, value);
+       writel(value, p->membase + offset);
+       dwapb_check_clear_ier(p, save_offset);
+}
+
+static unsigned int io_serial_in(struct uart_port *p, int offset)
+{
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       return inb(p->iobase + offset);
+}
+
+static void io_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       outb(value, p->iobase + offset);
+}
+
+static void set_io_from_upio(struct uart_port *p)
+{
+       struct uart_8250_port *up =
+               container_of(p, struct uart_8250_port, port);
+       switch (p->iotype) {
+       case UPIO_HUB6:
+               p->serial_in = hub6_serial_in;
+               p->serial_out = hub6_serial_out;
+               break;
+
+       case UPIO_MEM:
+               p->serial_in = mem_serial_in;
+               p->serial_out = mem_serial_out;
+               break;
+
+       case UPIO_RM9000:
+       case UPIO_MEM32:
+               p->serial_in = mem32_serial_in;
+               p->serial_out = mem32_serial_out;
+               break;
+
+       case UPIO_AU:
+               p->serial_in = au_serial_in;
+               p->serial_out = au_serial_out;
+               break;
+
+       case UPIO_TSI:
+               p->serial_in = tsi_serial_in;
+               p->serial_out = tsi_serial_out;
+               break;
+
+       case UPIO_DWAPB:
+               p->serial_in = mem_serial_in;
+               p->serial_out = dwapb_serial_out;
+               break;
+
+       case UPIO_DWAPB32:
+               p->serial_in = mem32_serial_in;
+               p->serial_out = dwapb32_serial_out;
+               break;
+
+       default:
+               p->serial_in = io_serial_in;
+               p->serial_out = io_serial_out;
+               break;
+       }
+       /* Remember loaded iotype */
+       up->cur_iotype = p->iotype;
+}
+
+static void
+serial_out_sync(struct uart_8250_port *up, int offset, int value)
+{
+       struct uart_port *p = &up->port;
+       switch (p->iotype) {
+       case UPIO_MEM:
+       case UPIO_MEM32:
+       case UPIO_AU:
+       case UPIO_DWAPB:
+       case UPIO_DWAPB32:
+               p->serial_out(p, offset, value);
+               p->serial_in(p, UART_LCR);      /* safe, no side-effects */
+               break;
+       default:
+               p->serial_out(p, offset, value);
+       }
+}
+
+#define serial_in(up, offset)          \
+       (up->port.serial_in(&(up)->port, (offset)))
+#define serial_out(up, offset, value)  \
+       (up->port.serial_out(&(up)->port, (offset), (value)))
+/*
+ * We used to support using pause I/O for certain machines.  We
+ * haven't supported this for a while, but just in case it's badly
+ * needed for certain old 386 machines, I've left these #define's
+ * in....
+ */
+#define serial_inp(up, offset)         serial_in(up, offset)
+#define serial_outp(up, offset, value) serial_out(up, offset, value)
+
+/* Uart divisor latch read */
+static inline int _serial_dl_read(struct uart_8250_port *up)
+{
+       return serial_inp(up, UART_DLL) | serial_inp(up, UART_DLM) << 8;
+}
+
+/* Uart divisor latch write */
+static inline void _serial_dl_write(struct uart_8250_port *up, int value)
+{
+       serial_outp(up, UART_DLL, value & 0xff);
+       serial_outp(up, UART_DLM, value >> 8 & 0xff);
+}
+
+#if defined(CONFIG_MIPS_ALCHEMY)
+/* Au1x00 haven't got a standard divisor latch */
+static int serial_dl_read(struct uart_8250_port *up)
+{
+       if (up->port.iotype == UPIO_AU)
+               return __raw_readl(up->port.membase + 0x28);
+       else
+               return _serial_dl_read(up);
+}
+
+static void serial_dl_write(struct uart_8250_port *up, int value)
+{
+       if (up->port.iotype == UPIO_AU)
+               __raw_writel(value, up->port.membase + 0x28);
+       else
+               _serial_dl_write(up, value);
+}
+#elif defined(CONFIG_SERIAL_8250_RM9K)
+static int serial_dl_read(struct uart_8250_port *up)
+{
+       return  (up->port.iotype == UPIO_RM9000) ?
+               (((__raw_readl(up->port.membase + 0x10) << 8) |
+               (__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff) :
+               _serial_dl_read(up);
+}
+
+static void serial_dl_write(struct uart_8250_port *up, int value)
+{
+       if (up->port.iotype == UPIO_RM9000) {
+               __raw_writel(value, up->port.membase + 0x08);
+               __raw_writel(value >> 8, up->port.membase + 0x10);
+       } else {
+               _serial_dl_write(up, value);
+       }
+}
+#else
+#define serial_dl_read(up) _serial_dl_read(up)
+#define serial_dl_write(up, value) _serial_dl_write(up, value)
+#endif
+
+/*
+ * For the 16C950
+ */
+static void serial_icr_write(struct uart_8250_port *up, int offset, int value)
+{
+       serial_out(up, UART_SCR, offset);
+       serial_out(up, UART_ICR, value);
+}
+
+static unsigned int serial_icr_read(struct uart_8250_port *up, int offset)
+{
+       unsigned int value;
+
+       serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD);
+       serial_out(up, UART_SCR, offset);
+       value = serial_in(up, UART_ICR);
+       serial_icr_write(up, UART_ACR, up->acr);
+
+       return value;
+}
+
+/*
+ * FIFO support.
+ */
+static void serial8250_clear_fifos(struct uart_8250_port *p)
+{
+       if (p->capabilities & UART_CAP_FIFO) {
+               serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO);
+               serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO |
+                              UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+               serial_outp(p, UART_FCR, 0);
+       }
+}
+
+/*
+ * IER sleep support.  UARTs which have EFRs need the "extended
+ * capability" bit enabled.  Note that on XR16C850s, we need to
+ * reset LCR to write to IER.
+ */
+static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
+{
+       if (p->capabilities & UART_CAP_SLEEP) {
+               if (p->capabilities & UART_CAP_EFR) {
+                       serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_B);
+                       serial_outp(p, UART_EFR, UART_EFR_ECB);
+                       serial_outp(p, UART_LCR, 0);
+               }
+               serial_outp(p, UART_IER, sleep ? UART_IERX_SLEEP : 0);
+               if (p->capabilities & UART_CAP_EFR) {
+                       serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_B);
+                       serial_outp(p, UART_EFR, 0);
+                       serial_outp(p, UART_LCR, 0);
+               }
+       }
+}
+
+#ifdef CONFIG_SERIAL_8250_RSA
+/*
+ * Attempts to turn on the RSA FIFO.  Returns zero on failure.
+ * We set the port uart clock rate if we succeed.
+ */
+static int __enable_rsa(struct uart_8250_port *up)
+{
+       unsigned char mode;
+       int result;
+
+       mode = serial_inp(up, UART_RSA_MSR);
+       result = mode & UART_RSA_MSR_FIFO;
+
+       if (!result) {
+               serial_outp(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
+               mode = serial_inp(up, UART_RSA_MSR);
+               result = mode & UART_RSA_MSR_FIFO;
+       }
+
+       if (result)
+               up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16;
+
+       return result;
+}
+
+static void enable_rsa(struct uart_8250_port *up)
+{
+       if (up->port.type == PORT_RSA) {
+               if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) {
+                       spin_lock_irq(&up->port.lock);
+                       __enable_rsa(up);
+                       spin_unlock_irq(&up->port.lock);
+               }
+               if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16)
+                       serial_outp(up, UART_RSA_FRR, 0);
+       }
+}
+
+/*
+ * Attempts to turn off the RSA FIFO.  Returns zero on failure.
+ * It is unknown why interrupts were disabled in here.  However,
+ * the caller is expected to preserve this behaviour by grabbing
+ * the spinlock before calling this function.
+ */
+static void disable_rsa(struct uart_8250_port *up)
+{
+       unsigned char mode;
+       int result;
+
+       if (up->port.type == PORT_RSA &&
+           up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) {
+               spin_lock_irq(&up->port.lock);
+
+               mode = serial_inp(up, UART_RSA_MSR);
+               result = !(mode & UART_RSA_MSR_FIFO);
+
+               if (!result) {
+                       serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
+                       mode = serial_inp(up, UART_RSA_MSR);
+                       result = !(mode & UART_RSA_MSR_FIFO);
+               }
+
+               if (result)
+                       up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16;
+               spin_unlock_irq(&up->port.lock);
+       }
+}
+#endif /* CONFIG_SERIAL_8250_RSA */
+
+/*
+ * This is a quickie test to see how big the FIFO is.
+ * It doesn't work at all the time, more's the pity.
+ */
+static int size_fifo(struct uart_8250_port *up)
+{
+       unsigned char old_fcr, old_mcr, old_lcr;
+       unsigned short old_dl;
+       int count;
+
+       old_lcr = serial_inp(up, UART_LCR);
+       serial_outp(up, UART_LCR, 0);
+       old_fcr = serial_inp(up, UART_FCR);
+       old_mcr = serial_inp(up, UART_MCR);
+       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+                   UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+       serial_outp(up, UART_MCR, UART_MCR_LOOP);
+       serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A);
+       old_dl = serial_dl_read(up);
+       serial_dl_write(up, 0x0001);
+       serial_outp(up, UART_LCR, 0x03);
+       for (count = 0; count < 256; count++)
+               serial_outp(up, UART_TX, count);
+       mdelay(20);/* FIXME - schedule_timeout */
+       for (count = 0; (serial_inp(up, UART_LSR) & UART_LSR_DR) &&
+            (count < 256); count++)
+               serial_inp(up, UART_RX);
+       serial_outp(up, UART_FCR, old_fcr);
+       serial_outp(up, UART_MCR, old_mcr);
+       serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A);
+       serial_dl_write(up, old_dl);
+       serial_outp(up, UART_LCR, old_lcr);
+
+       return count;
+}
+
+/*
+ * Read UART ID using the divisor method - set DLL and DLM to zero
+ * and the revision will be in DLL and device type in DLM.  We
+ * preserve the device state across this.
+ */
+static unsigned int autoconfig_read_divisor_id(struct uart_8250_port *p)
+{
+       unsigned char old_dll, old_dlm, old_lcr;
+       unsigned int id;
+
+       old_lcr = serial_inp(p, UART_LCR);
+       serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_A);
+
+       old_dll = serial_inp(p, UART_DLL);
+       old_dlm = serial_inp(p, UART_DLM);
+
+       serial_outp(p, UART_DLL, 0);
+       serial_outp(p, UART_DLM, 0);
+
+       id = serial_inp(p, UART_DLL) | serial_inp(p, UART_DLM) << 8;
+
+       serial_outp(p, UART_DLL, old_dll);
+       serial_outp(p, UART_DLM, old_dlm);
+       serial_outp(p, UART_LCR, old_lcr);
+
+       return id;
+}
+
+/*
+ * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's.
+ * When this function is called we know it is at least a StarTech
+ * 16650 V2, but it might be one of several StarTech UARTs, or one of
+ * its clones.  (We treat the broken original StarTech 16650 V1 as a
+ * 16550, and why not?  Startech doesn't seem to even acknowledge its
+ * existence.)
+ *
+ * What evil have men's minds wrought...
+ */
+static void autoconfig_has_efr(struct uart_8250_port *up)
+{
+       unsigned int id1, id2, id3, rev;
+
+       /*
+        * Everything with an EFR has SLEEP
+        */
+       up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP;
+
+       /*
+        * First we check to see if it's an Oxford Semiconductor UART.
+        *
+        * If we have to do this here because some non-National
+        * Semiconductor clone chips lock up if you try writing to the
+        * LSR register (which serial_icr_read does)
+        */
+
+       /*
+        * Check for Oxford Semiconductor 16C950.
+        *
+        * EFR [4] must be set else this test fails.
+        *
+        * This shouldn't be necessary, but Mike Hudson (Exoray@isys.ca)
+        * claims that it's needed for 952 dual UART's (which are not
+        * recommended for new designs).
+        */
+       up->acr = 0;
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+       serial_out(up, UART_EFR, UART_EFR_ECB);
+       serial_out(up, UART_LCR, 0x00);
+       id1 = serial_icr_read(up, UART_ID1);
+       id2 = serial_icr_read(up, UART_ID2);
+       id3 = serial_icr_read(up, UART_ID3);
+       rev = serial_icr_read(up, UART_REV);
+
+       DEBUG_AUTOCONF("950id=%02x:%02x:%02x:%02x ", id1, id2, id3, rev);
+
+       if (id1 == 0x16 && id2 == 0xC9 &&
+           (id3 == 0x50 || id3 == 0x52 || id3 == 0x54)) {
+               up->port.type = PORT_16C950;
+
+               /*
+                * Enable work around for the Oxford Semiconductor 952 rev B
+                * chip which causes it to seriously miscalculate baud rates
+                * when DLL is 0.
+                */
+               if (id3 == 0x52 && rev == 0x01)
+                       up->bugs |= UART_BUG_QUOT;
+               return;
+       }
+
+       /*
+        * We check for a XR16C850 by setting DLL and DLM to 0, and then
+        * reading back DLL and DLM.  The chip type depends on the DLM
+        * value read back:
+        *  0x10 - XR16C850 and the DLL contains the chip revision.
+        *  0x12 - XR16C2850.
+        *  0x14 - XR16C854.
+        */
+       id1 = autoconfig_read_divisor_id(up);
+       DEBUG_AUTOCONF("850id=%04x ", id1);
+
+       id2 = id1 >> 8;
+       if (id2 == 0x10 || id2 == 0x12 || id2 == 0x14) {
+               up->port.type = PORT_16850;
+               return;
+       }
+
+       /*
+        * It wasn't an XR16C850.
+        *
+        * We distinguish between the '654 and the '650 by counting
+        * how many bytes are in the FIFO.  I'm using this for now,
+        * since that's the technique that was sent to me in the
+        * serial driver update, but I'm not convinced this works.
+        * I've had problems doing this in the past.  -TYT
+        */
+       if (size_fifo(up) == 64)
+               up->port.type = PORT_16654;
+       else
+               up->port.type = PORT_16650V2;
+}
+
+/*
+ * We detected a chip without a FIFO.  Only two fall into
+ * this category - the original 8250 and the 16450.  The
+ * 16450 has a scratch register (accessible with LCR=0)
+ */
+static void autoconfig_8250(struct uart_8250_port *up)
+{
+       unsigned char scratch, status1, status2;
+
+       up->port.type = PORT_8250;
+
+       scratch = serial_in(up, UART_SCR);
+       serial_outp(up, UART_SCR, 0xa5);
+       status1 = serial_in(up, UART_SCR);
+       serial_outp(up, UART_SCR, 0x5a);
+       status2 = serial_in(up, UART_SCR);
+       serial_outp(up, UART_SCR, scratch);
+
+       if (status1 == 0xa5 && status2 == 0x5a)
+               up->port.type = PORT_16450;
+}
+
+static int broken_efr(struct uart_8250_port *up)
+{
+       /*
+        * Exar ST16C2550 "A2" devices incorrectly detect as
+        * having an EFR, and report an ID of 0x0201.  See
+        * http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-11/4812.html 
+        */
+       if (autoconfig_read_divisor_id(up) == 0x0201 && size_fifo(up) == 16)
+               return 1;
+
+       return 0;
+}
+
+/*
+ * We know that the chip has FIFOs.  Does it have an EFR?  The
+ * EFR is located in the same register position as the IIR and
+ * we know the top two bits of the IIR are currently set.  The
+ * EFR should contain zero.  Try to read the EFR.
+ */
+static void autoconfig_16550a(struct uart_8250_port *up)
+{
+       unsigned char status1, status2;
+       unsigned int iersave;
+
+       up->port.type = PORT_16550A;
+       up->capabilities |= UART_CAP_FIFO;
+
+       /*
+        * Check for presence of the EFR when DLAB is set.
+        * Only ST16C650V1 UARTs pass this test.
+        */
+       serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A);
+       if (serial_in(up, UART_EFR) == 0) {
+               serial_outp(up, UART_EFR, 0xA8);
+               if (serial_in(up, UART_EFR) != 0) {
+                       DEBUG_AUTOCONF("EFRv1 ");
+                       up->port.type = PORT_16650;
+                       up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP;
+               } else {
+                       DEBUG_AUTOCONF("Motorola 8xxx DUART ");
+               }
+               serial_outp(up, UART_EFR, 0);
+               return;
+       }
+
+       /*
+        * Maybe it requires 0xbf to be written to the LCR.
+        * (other ST16C650V2 UARTs, TI16C752A, etc)
+        */
+       serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
+       if (serial_in(up, UART_EFR) == 0 && !broken_efr(up)) {
+               DEBUG_AUTOCONF("EFRv2 ");
+               autoconfig_has_efr(up);
+               return;
+       }
+
+       /*
+        * Check for a National Semiconductor SuperIO chip.
+        * Attempt to switch to bank 2, read the value of the LOOP bit
+        * from EXCR1. Switch back to bank 0, change it in MCR. Then
+        * switch back to bank 2, read it from EXCR1 again and check
+        * it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2
+        */
+       serial_outp(up, UART_LCR, 0);
+       status1 = serial_in(up, UART_MCR);
+       serial_outp(up, UART_LCR, 0xE0);
+       status2 = serial_in(up, 0x02); /* EXCR1 */
+
+       if (!((status2 ^ status1) & UART_MCR_LOOP)) {
+               serial_outp(up, UART_LCR, 0);
+               serial_outp(up, UART_MCR, status1 ^ UART_MCR_LOOP);
+               serial_outp(up, UART_LCR, 0xE0);
+               status2 = serial_in(up, 0x02); /* EXCR1 */
+               serial_outp(up, UART_LCR, 0);
+               serial_outp(up, UART_MCR, status1);
+
+               if ((status2 ^ status1) & UART_MCR_LOOP) {
+                       unsigned short quot;
+
+                       serial_outp(up, UART_LCR, 0xE0);
+
+                       quot = serial_dl_read(up);
+                       quot <<= 3;
+
+                       status1 = serial_in(up, 0x04); /* EXCR2 */
+                       status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
+                       status1 |= 0x10;  /* 1.625 divisor for baud_base --> 921600 */
+                       serial_outp(up, 0x04, status1);
+
+                       serial_dl_write(up, quot);
+
+                       serial_outp(up, UART_LCR, 0);
+
+                       up->port.uartclk = 921600*16;
+                       up->port.type = PORT_NS16550A;
+                       up->capabilities |= UART_NATSEMI;
+                       return;
+               }
+       }
+
+       /*
+        * No EFR.  Try to detect a TI16750, which only sets bit 5 of
+        * the IIR when 64 byte FIFO mode is enabled when DLAB is set.
+        * Try setting it with and without DLAB set.  Cheap clones
+        * set bit 5 without DLAB set.
+        */
+       serial_outp(up, UART_LCR, 0);
+       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
+       status1 = serial_in(up, UART_IIR) >> 5;
+       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+       serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A);
+       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
+       status2 = serial_in(up, UART_IIR) >> 5;
+       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+       serial_outp(up, UART_LCR, 0);
+
+       DEBUG_AUTOCONF("iir1=%d iir2=%d ", status1, status2);
+
+       if (status1 == 6 && status2 == 7) {
+               up->port.type = PORT_16750;
+               up->capabilities |= UART_CAP_AFE | UART_CAP_SLEEP;
+               return;
+       }
+
+       /*
+        * Try writing and reading the UART_IER_UUE bit (b6).
+        * If it works, this is probably one of the Xscale platform's
+        * internal UARTs.
+        * We're going to explicitly set the UUE bit to 0 before
+        * trying to write and read a 1 just to make sure it's not
+        * already a 1 and maybe locked there before we even start start.
+        */
+       iersave = serial_in(up, UART_IER);
+       serial_outp(up, UART_IER, iersave & ~UART_IER_UUE);
+       if (!(serial_in(up, UART_IER) & UART_IER_UUE)) {
+               /*
+                * OK it's in a known zero state, try writing and reading
+                * without disturbing the current state of the other bits.
+                */
+               serial_outp(up, UART_IER, iersave | UART_IER_UUE);
+               if (serial_in(up, UART_IER) & UART_IER_UUE) {
+                       /*
+                        * It's an Xscale.
+                        * We'll leave the UART_IER_UUE bit set to 1 (enabled).
+                        */
+                       DEBUG_AUTOCONF("Xscale ");
+                       up->port.type = PORT_XSCALE;
+                       up->capabilities |= UART_CAP_UUE;
+                       return;
+               }
+       } else {
+               /*
+                * If we got here we couldn't force the IER_UUE bit to 0.
+                * Log it and continue.
+                */
+               DEBUG_AUTOCONF("Couldn't force IER_UUE to 0 ");
+       }
+       serial_outp(up, UART_IER, iersave);
+
+       /*
+        * We distinguish between 16550A and U6 16550A by counting
+        * how many bytes are in the FIFO.
+        */
+       if (up->port.type == PORT_16550A && size_fifo(up) == 64) {
+               up->port.type = PORT_U6_16550A;
+               up->capabilities |= UART_CAP_AFE;
+       }
+}
+
+/*
+ * This routine is called by rs_init() to initialize a specific serial
+ * port.  It determines what type of UART chip this serial port is
+ * using: 8250, 16450, 16550, 16550A.  The important question is
+ * whether or not this UART is a 16550A or not, since this will
+ * determine whether or not we can use its FIFO features or not.
+ */
+static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
+{
+       unsigned char status1, scratch, scratch2, scratch3;
+       unsigned char save_lcr, save_mcr;
+       unsigned long flags;
+
+       if (!up->port.iobase && !up->port.mapbase && !up->port.membase)
+               return;
+
+       DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04lx, 0x%p): ",
+                      serial_index(&up->port), up->port.iobase, up->port.membase);
+
+       /*
+        * We really do need global IRQs disabled here - we're going to
+        * be frobbing the chips IRQ enable register to see if it exists.
+        */
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       up->capabilities = 0;
+       up->bugs = 0;
+
+       if (!(up->port.flags & UPF_BUGGY_UART)) {
+               /*
+                * Do a simple existence test first; if we fail this,
+                * there's no point trying anything else.
+                *
+                * 0x80 is used as a nonsense port to prevent against
+                * false positives due to ISA bus float.  The
+                * assumption is that 0x80 is a non-existent port;
+                * which should be safe since include/asm/io.h also
+                * makes this assumption.
+                *
+                * Note: this is safe as long as MCR bit 4 is clear
+                * and the device is in "PC" mode.
+                */
+               scratch = serial_inp(up, UART_IER);
+               serial_outp(up, UART_IER, 0);
+#ifdef __i386__
+               outb(0xff, 0x080);
+#endif
+               /*
+                * Mask out IER[7:4] bits for test as some UARTs (e.g. TL
+                * 16C754B) allow only to modify them if an EFR bit is set.
+                */
+               scratch2 = serial_inp(up, UART_IER) & 0x0f;
+               serial_outp(up, UART_IER, 0x0F);
+#ifdef __i386__
+               outb(0, 0x080);
+#endif
+               scratch3 = serial_inp(up, UART_IER) & 0x0f;
+               serial_outp(up, UART_IER, scratch);
+               if (scratch2 != 0 || scratch3 != 0x0F) {
+                       /*
+                        * We failed; there's nothing here
+                        */
+                       DEBUG_AUTOCONF("IER test failed (%02x, %02x) ",
+                                      scratch2, scratch3);
+                       goto out;
+               }
+       }
+
+       save_mcr = serial_in(up, UART_MCR);
+       save_lcr = serial_in(up, UART_LCR);
+
+       /*
+        * Check to see if a UART is really there.  Certain broken
+        * internal modems based on the Rockwell chipset fail this
+        * test, because they apparently don't implement the loopback
+        * test mode.  So this test is skipped on the COM 1 through
+        * COM 4 ports.  This *should* be safe, since no board
+        * manufacturer would be stupid enough to design a board
+        * that conflicts with COM 1-4 --- we hope!
+        */
+       if (!(up->port.flags & UPF_SKIP_TEST)) {
+               serial_outp(up, UART_MCR, UART_MCR_LOOP | 0x0A);
+               status1 = serial_inp(up, UART_MSR) & 0xF0;
+               serial_outp(up, UART_MCR, save_mcr);
+               if (status1 != 0x90) {
+                       DEBUG_AUTOCONF("LOOP test failed (%02x) ",
+                                      status1);
+                       goto out;
+               }
+       }
+
+       /*
+        * We're pretty sure there's a port here.  Lets find out what
+        * type of port it is.  The IIR top two bits allows us to find
+        * out if it's 8250 or 16450, 16550, 16550A or later.  This
+        * determines what we test for next.
+        *
+        * We also initialise the EFR (if any) to zero for later.  The
+        * EFR occupies the same register location as the FCR and IIR.
+        */
+       serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
+       serial_outp(up, UART_EFR, 0);
+       serial_outp(up, UART_LCR, 0);
+
+       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+       scratch = serial_in(up, UART_IIR) >> 6;
+
+       DEBUG_AUTOCONF("iir=%d ", scratch);
+
+       switch (scratch) {
+       case 0:
+               autoconfig_8250(up);
+               break;
+       case 1:
+               up->port.type = PORT_UNKNOWN;
+               break;
+       case 2:
+               up->port.type = PORT_16550;
+               break;
+       case 3:
+               autoconfig_16550a(up);
+               break;
+       }
+
+#ifdef CONFIG_SERIAL_8250_RSA
+       /*
+        * Only probe for RSA ports if we got the region.
+        */
+       if (up->port.type == PORT_16550A && probeflags & PROBE_RSA) {
+               int i;
+
+               for (i = 0 ; i < probe_rsa_count; ++i) {
+                       if (probe_rsa[i] == up->port.iobase &&
+                           __enable_rsa(up)) {
+                               up->port.type = PORT_RSA;
+                               break;
+                       }
+               }
+       }
+#endif
+
+       serial_outp(up, UART_LCR, save_lcr);
+
+       if (up->capabilities != uart_config[up->port.type].flags) {
+               printk(KERN_WARNING
+                      "ttyS%d: detected caps %08x should be %08x\n",
+                      serial_index(&up->port), up->capabilities,
+                      uart_config[up->port.type].flags);
+       }
+
+       up->port.fifosize = uart_config[up->port.type].fifo_size;
+       up->capabilities = uart_config[up->port.type].flags;
+       up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
+
+       if (up->port.type == PORT_UNKNOWN)
+               goto out;
+
+       /*
+        * Reset the UART.
+        */
+#ifdef CONFIG_SERIAL_8250_RSA
+       if (up->port.type == PORT_RSA)
+               serial_outp(up, UART_RSA_FRR, 0);
+#endif
+       serial_outp(up, UART_MCR, save_mcr);
+       serial8250_clear_fifos(up);
+       serial_in(up, UART_RX);
+       if (up->capabilities & UART_CAP_UUE)
+               serial_outp(up, UART_IER, UART_IER_UUE);
+       else
+               serial_outp(up, UART_IER, 0);
+
+ out:
+       spin_unlock_irqrestore(&up->port.lock, flags);
+       DEBUG_AUTOCONF("type=%s\n", uart_config[up->port.type].name);
+}
+
+static void autoconfig_irq(struct uart_8250_port *up)
+{
+       unsigned char save_mcr, save_ier;
+       unsigned char save_ICP = 0;
+       unsigned int ICP = 0;
+       unsigned long irqs;
+       int irq;
+
+       if (up->port.flags & UPF_FOURPORT) {
+               ICP = (up->port.iobase & 0xfe0) | 0x1f;
+               save_ICP = inb_p(ICP);
+               outb_p(0x80, ICP);
+               (void) inb_p(ICP);
+       }
+
+       /* forget possible initially masked and pending IRQ */
+       probe_irq_off(probe_irq_on());
+       save_mcr = serial_inp(up, UART_MCR);
+       save_ier = serial_inp(up, UART_IER);
+       serial_outp(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2);
+
+       irqs = probe_irq_on();
+       serial_outp(up, UART_MCR, 0);
+       udelay(10);
+       if (up->port.flags & UPF_FOURPORT) {
+               serial_outp(up, UART_MCR,
+                           UART_MCR_DTR | UART_MCR_RTS);
+       } else {
+               serial_outp(up, UART_MCR,
+                           UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
+       }
+       serial_outp(up, UART_IER, 0x0f);        /* enable all intrs */
+       (void)serial_inp(up, UART_LSR);
+       (void)serial_inp(up, UART_RX);
+       (void)serial_inp(up, UART_IIR);
+       (void)serial_inp(up, UART_MSR);
+       serial_outp(up, UART_TX, 0xFF);
+       udelay(20);
+       irq = probe_irq_off(irqs);
+
+       serial_outp(up, UART_MCR, save_mcr);
+       serial_outp(up, UART_IER, save_ier);
+
+       if (up->port.flags & UPF_FOURPORT)
+               outb_p(save_ICP, ICP);
+
+       up->port.irq = (irq > 0) ? irq : 0;
+}
+
+static inline void __stop_tx(struct uart_8250_port *p)
+{
+       if (p->ier & UART_IER_THRI) {
+               p->ier &= ~UART_IER_THRI;
+               serial_out(p, UART_IER, p->ier);
+       }
+}
+
+static void serial8250_stop_tx(struct uart_port *port)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+
+       __stop_tx(up);
+
+       /*
+        * We really want to stop the transmitter from sending.
+        */
+       if (up->port.type == PORT_16C950) {
+               up->acr |= UART_ACR_TXDIS;
+               serial_icr_write(up, UART_ACR, up->acr);
+       }
+}
+
+static void transmit_chars(struct uart_8250_port *up);
+
+static void serial8250_start_tx(struct uart_port *port)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+
+       if (!(up->ier & UART_IER_THRI)) {
+               up->ier |= UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+
+               if (up->bugs & UART_BUG_TXEN) {
+                       unsigned char lsr;
+                       lsr = serial_in(up, UART_LSR);
+                       up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
+                       if ((up->port.type == PORT_RM9000) ?
+                               (lsr & UART_LSR_THRE) :
+                               (lsr & UART_LSR_TEMT))
+                               transmit_chars(up);
+               }
+       }
+
+       /*
+        * Re-enable the transmitter if we disabled it.
+        */
+       if (up->port.type == PORT_16C950 && up->acr & UART_ACR_TXDIS) {
+               up->acr &= ~UART_ACR_TXDIS;
+               serial_icr_write(up, UART_ACR, up->acr);
+       }
+}
+
+static void serial8250_stop_rx(struct uart_port *port)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+
+       up->ier &= ~UART_IER_RLSI;
+       up->port.read_status_mask &= ~UART_LSR_DR;
+       serial_out(up, UART_IER, up->ier);
+}
+
+static void serial8250_enable_ms(struct uart_port *port)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+
+       /* no MSR capabilities */
+       if (up->bugs & UART_BUG_NOMSR)
+               return;
+
+       up->ier |= UART_IER_MSI;
+       serial_out(up, UART_IER, up->ier);
+}
+
+static void
+receive_chars(struct uart_8250_port *up, unsigned int *status)
+{
+       struct tty_struct *tty = up->port.state->port.tty;
+       unsigned char ch, lsr = *status;
+       int max_count = 256;
+       char flag;
+
+       do {
+               if (likely(lsr & UART_LSR_DR))
+                       ch = serial_inp(up, UART_RX);
+               else
+                       /*
+                        * Intel 82571 has a Serial Over Lan device that will
+                        * set UART_LSR_BI without setting UART_LSR_DR when
+                        * it receives a break. To avoid reading from the
+                        * receive buffer without UART_LSR_DR bit set, we
+                        * just force the read character to be 0
+                        */
+                       ch = 0;
+
+               flag = TTY_NORMAL;
+               up->port.icount.rx++;
+
+               lsr |= up->lsr_saved_flags;
+               up->lsr_saved_flags = 0;
+
+               if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
+                       /*
+                        * For statistics only
+                        */
+                       if (lsr & UART_LSR_BI) {
+                               lsr &= ~(UART_LSR_FE | UART_LSR_PE);
+                               up->port.icount.brk++;
+                               /*
+                                * We do the SysRQ and SAK checking
+                                * here because otherwise the break
+                                * may get masked by ignore_status_mask
+                                * or read_status_mask.
+                                */
+                               if (uart_handle_break(&up->port))
+                                       goto ignore_char;
+                       } else if (lsr & UART_LSR_PE)
+                               up->port.icount.parity++;
+                       else if (lsr & UART_LSR_FE)
+                               up->port.icount.frame++;
+                       if (lsr & UART_LSR_OE)
+                               up->port.icount.overrun++;
+
+                       /*
+                        * Mask off conditions which should be ignored.
+                        */
+                       lsr &= up->port.read_status_mask;
+
+                       if (lsr & UART_LSR_BI) {
+                               DEBUG_INTR("handling break....");
+                               flag = TTY_BREAK;
+                       } else if (lsr & UART_LSR_PE)
+                               flag = TTY_PARITY;
+                       else if (lsr & UART_LSR_FE)
+                               flag = TTY_FRAME;
+               }
+               if (uart_handle_sysrq_char(&up->port, ch))
+                       goto ignore_char;
+
+               uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);
+
+ignore_char:
+               lsr = serial_inp(up, UART_LSR);
+       } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0));
+       spin_unlock(&up->port.lock);
+       tty_flip_buffer_push(tty);
+       spin_lock(&up->port.lock);
+       *status = lsr;
+}
+
+static void transmit_chars(struct uart_8250_port *up)
+{
+       struct circ_buf *xmit = &up->port.state->xmit;
+       int count;
+
+       if (up->port.x_char) {
+               serial_outp(up, UART_TX, up->port.x_char);
+               up->port.icount.tx++;
+               up->port.x_char = 0;
+               return;
+       }
+       if (uart_tx_stopped(&up->port)) {
+               serial8250_stop_tx(&up->port);
+               return;
+       }
+       if (uart_circ_empty(xmit)) {
+               __stop_tx(up);
+               return;
+       }
+
+       count = up->tx_loadsz;
+       do {
+               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               up->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (--count > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+       DEBUG_INTR("THRE...");
+
+       if (uart_circ_empty(xmit))
+               __stop_tx(up);
+}
+
+static unsigned int check_modem_status(struct uart_8250_port *up)
+{
+       unsigned int status = serial_in(up, UART_MSR);
+
+       status |= up->msr_saved_flags;
+       up->msr_saved_flags = 0;
+       if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&
+           up->port.state != NULL) {
+               if (status & UART_MSR_TERI)
+                       up->port.icount.rng++;
+               if (status & UART_MSR_DDSR)
+                       up->port.icount.dsr++;
+               if (status & UART_MSR_DDCD)
+                       uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
+               if (status & UART_MSR_DCTS)
+                       uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
+
+               wake_up_interruptible(&up->port.state->port.delta_msr_wait);
+       }
+
+       return status;
+}
+
+/*
+ * This handles the interrupt from one port.
+ */
+static void serial8250_handle_port(struct uart_8250_port *up)
+{
+       unsigned int status;
+       unsigned long flags;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       status = serial_inp(up, UART_LSR);
+
+       DEBUG_INTR("status = %x...", status);
+
+       if (status & (UART_LSR_DR | UART_LSR_BI))
+               receive_chars(up, &status);
+       check_modem_status(up);
+       if (status & UART_LSR_THRE)
+               transmit_chars(up);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+/*
+ * This is the serial driver's interrupt routine.
+ *
+ * Arjan thinks the old way was overly complex, so it got simplified.
+ * Alan disagrees, saying that need the complexity to handle the weird
+ * nature of ISA shared interrupts.  (This is a special exception.)
+ *
+ * In order to handle ISA shared interrupts properly, we need to check
+ * that all ports have been serviced, and therefore the ISA interrupt
+ * line has been de-asserted.
+ *
+ * This means we need to loop through all ports. checking that they
+ * don't have an interrupt pending.
+ */
+static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
+{
+       struct irq_info *i = dev_id;
+       struct list_head *l, *end = NULL;
+       int pass_counter = 0, handled = 0;
+
+       DEBUG_INTR("serial8250_interrupt(%d)...", irq);
+
+       spin_lock(&i->lock);
+
+       l = i->head;
+       do {
+               struct uart_8250_port *up;
+               unsigned int iir;
+
+               up = list_entry(l, struct uart_8250_port, list);
+
+               iir = serial_in(up, UART_IIR);
+               if (!(iir & UART_IIR_NO_INT)) {
+                       serial8250_handle_port(up);
+
+                       handled = 1;
+
+                       end = NULL;
+               } else if ((up->port.iotype == UPIO_DWAPB ||
+                           up->port.iotype == UPIO_DWAPB32) &&
+                         (iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
+                       /* The DesignWare APB UART has an Busy Detect (0x07)
+                        * interrupt meaning an LCR write attempt occured while the
+                        * UART was busy. The interrupt must be cleared by reading
+                        * the UART status register (USR) and the LCR re-written. */
+                       unsigned int status;
+                       status = *(volatile u32 *)up->port.private_data;
+                       serial_out(up, UART_LCR, up->lcr);
+
+                       handled = 1;
+
+                       end = NULL;
+               } else if (end == NULL)
+                       end = l;
+
+               l = l->next;
+
+               if (l == i->head && pass_counter++ > PASS_LIMIT) {
+                       /* If we hit this, we're dead. */
+                       printk_ratelimited(KERN_ERR
+                               "serial8250: too much work for irq%d\n", irq);
+                       break;
+               }
+       } while (l != end);
+
+       spin_unlock(&i->lock);
+
+       DEBUG_INTR("end.\n");
+
+       return IRQ_RETVAL(handled);
+}
+
+/*
+ * To support ISA shared interrupts, we need to have one interrupt
+ * handler that ensures that the IRQ line has been deasserted
+ * before returning.  Failing to do this will result in the IRQ
+ * line being stuck active, and, since ISA irqs are edge triggered,
+ * no more IRQs will be seen.
+ */
+static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up)
+{
+       spin_lock_irq(&i->lock);
+
+       if (!list_empty(i->head)) {
+               if (i->head == &up->list)
+                       i->head = i->head->next;
+               list_del(&up->list);
+       } else {
+               BUG_ON(i->head != &up->list);
+               i->head = NULL;
+       }
+       spin_unlock_irq(&i->lock);
+       /* List empty so throw away the hash node */
+       if (i->head == NULL) {
+               hlist_del(&i->node);
+               kfree(i);
+       }
+}
+
+static int serial_link_irq_chain(struct uart_8250_port *up)
+{
+       struct hlist_head *h;
+       struct hlist_node *n;
+       struct irq_info *i;
+       int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0;
+
+       mutex_lock(&hash_mutex);
+
+       h = &irq_lists[up->port.irq % NR_IRQ_HASH];
+
+       hlist_for_each(n, h) {
+               i = hlist_entry(n, struct irq_info, node);
+               if (i->irq == up->port.irq)
+                       break;
+       }
+
+       if (n == NULL) {
+               i = kzalloc(sizeof(struct irq_info), GFP_KERNEL);
+               if (i == NULL) {
+                       mutex_unlock(&hash_mutex);
+                       return -ENOMEM;
+               }
+               spin_lock_init(&i->lock);
+               i->irq = up->port.irq;
+               hlist_add_head(&i->node, h);
+       }
+       mutex_unlock(&hash_mutex);
+
+       spin_lock_irq(&i->lock);
+
+       if (i->head) {
+               list_add(&up->list, i->head);
+               spin_unlock_irq(&i->lock);
+
+               ret = 0;
+       } else {
+               INIT_LIST_HEAD(&up->list);
+               i->head = &up->list;
+               spin_unlock_irq(&i->lock);
+               irq_flags |= up->port.irqflags;
+               ret = request_irq(up->port.irq, serial8250_interrupt,
+                                 irq_flags, "serial", i);
+               if (ret < 0)
+                       serial_do_unlink(i, up);
+       }
+
+       return ret;
+}
+
+static void serial_unlink_irq_chain(struct uart_8250_port *up)
+{
+       struct irq_info *i;
+       struct hlist_node *n;
+       struct hlist_head *h;
+
+       mutex_lock(&hash_mutex);
+
+       h = &irq_lists[up->port.irq % NR_IRQ_HASH];
+
+       hlist_for_each(n, h) {
+               i = hlist_entry(n, struct irq_info, node);
+               if (i->irq == up->port.irq)
+                       break;
+       }
+
+       BUG_ON(n == NULL);
+       BUG_ON(i->head == NULL);
+
+       if (list_empty(i->head))
+               free_irq(up->port.irq, i);
+
+       serial_do_unlink(i, up);
+       mutex_unlock(&hash_mutex);
+}
+
+/*
+ * This function is used to handle ports that do not have an
+ * interrupt.  This doesn't work very well for 16450's, but gives
+ * barely passable results for a 16550A.  (Although at the expense
+ * of much CPU overhead).
+ */
+static void serial8250_timeout(unsigned long data)
+{
+       struct uart_8250_port *up = (struct uart_8250_port *)data;
+       unsigned int iir;
+
+       iir = serial_in(up, UART_IIR);
+       if (!(iir & UART_IIR_NO_INT))
+               serial8250_handle_port(up);
+       mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port));
+}
+
+static void serial8250_backup_timeout(unsigned long data)
+{
+       struct uart_8250_port *up = (struct uart_8250_port *)data;
+       unsigned int iir, ier = 0, lsr;
+       unsigned long flags;
+
+       /*
+        * Must disable interrupts or else we risk racing with the interrupt
+        * based handler.
+        */
+       if (is_real_interrupt(up->port.irq)) {
+               ier = serial_in(up, UART_IER);
+               serial_out(up, UART_IER, 0);
+       }
+
+       iir = serial_in(up, UART_IIR);
+
+       /*
+        * This should be a safe test for anyone who doesn't trust the
+        * IIR bits on their UART, but it's specifically designed for
+        * the "Diva" UART used on the management processor on many HP
+        * ia64 and parisc boxes.
+        */
+       spin_lock_irqsave(&up->port.lock, flags);
+       lsr = serial_in(up, UART_LSR);
+       up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
+       spin_unlock_irqrestore(&up->port.lock, flags);
+       if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) &&
+           (!uart_circ_empty(&up->port.state->xmit) || up->port.x_char) &&
+           (lsr & UART_LSR_THRE)) {
+               iir &= ~(UART_IIR_ID | UART_IIR_NO_INT);
+               iir |= UART_IIR_THRI;
+       }
+
+       if (!(iir & UART_IIR_NO_INT))
+               serial8250_handle_port(up);
+
+       if (is_real_interrupt(up->port.irq))
+               serial_out(up, UART_IER, ier);
+
+       /* Standard timer interval plus 0.2s to keep the port running */
+       mod_timer(&up->timer,
+               jiffies + uart_poll_timeout(&up->port) + HZ / 5);
+}
+
+static unsigned int serial8250_tx_empty(struct uart_port *port)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+       unsigned long flags;
+       unsigned int lsr;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       lsr = serial_in(up, UART_LSR);
+       up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int serial8250_get_mctrl(struct uart_port *port)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+       unsigned int status;
+       unsigned int ret;
+
+       status = check_modem_status(up);
+
+       ret = 0;
+       if (status & UART_MSR_DCD)
+               ret |= TIOCM_CAR;
+       if (status & UART_MSR_RI)
+               ret |= TIOCM_RNG;
+       if (status & UART_MSR_DSR)
+               ret |= TIOCM_DSR;
+       if (status & UART_MSR_CTS)
+               ret |= TIOCM_CTS;
+       return ret;
+}
+
+static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+       unsigned char mcr = 0;
+
+       if (mctrl & TIOCM_RTS)
+               mcr |= UART_MCR_RTS;
+       if (mctrl & TIOCM_DTR)
+               mcr |= UART_MCR_DTR;
+       if (mctrl & TIOCM_OUT1)
+               mcr |= UART_MCR_OUT1;
+       if (mctrl & TIOCM_OUT2)
+               mcr |= UART_MCR_OUT2;
+       if (mctrl & TIOCM_LOOP)
+               mcr |= UART_MCR_LOOP;
+
+       mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr;
+
+       serial_out(up, UART_MCR, mcr);
+}
+
+static void serial8250_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+       unsigned long flags;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       if (break_state == -1)
+               up->lcr |= UART_LCR_SBC;
+       else
+               up->lcr &= ~UART_LCR_SBC;
+       serial_out(up, UART_LCR, up->lcr);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+/*
+ *     Wait for transmitter & holding register to empty
+ */
+static void wait_for_xmitr(struct uart_8250_port *up, int bits)
+{
+       unsigned int status, tmout = 10000;
+
+       /* Wait up to 10ms for the character(s) to be sent. */
+       for (;;) {
+               status = serial_in(up, UART_LSR);
+
+               up->lsr_saved_flags |= status & LSR_SAVE_FLAGS;
+
+               if ((status & bits) == bits)
+                       break;
+               if (--tmout == 0)
+                       break;
+               udelay(1);
+       }
+
+       /* Wait up to 1s for flow control if necessary */
+       if (up->port.flags & UPF_CONS_FLOW) {
+               unsigned int tmout;
+               for (tmout = 1000000; tmout; tmout--) {
+                       unsigned int msr = serial_in(up, UART_MSR);
+                       up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
+                       if (msr & UART_MSR_CTS)
+                               break;
+                       udelay(1);
+                       touch_nmi_watchdog();
+               }
+       }
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+/*
+ * Console polling routines for writing and reading from the uart while
+ * in an interrupt or debug context.
+ */
+
+static int serial8250_get_poll_char(struct uart_port *port)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+       unsigned char lsr = serial_inp(up, UART_LSR);
+
+       if (!(lsr & UART_LSR_DR))
+               return NO_POLL_CHAR;
+
+       return serial_inp(up, UART_RX);
+}
+
+
+static void serial8250_put_poll_char(struct uart_port *port,
+                        unsigned char c)
+{
+       unsigned int ier;
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+
+       /*
+        *      First save the IER then disable the interrupts
+        */
+       ier = serial_in(up, UART_IER);
+       if (up->capabilities & UART_CAP_UUE)
+               serial_out(up, UART_IER, UART_IER_UUE);
+       else
+               serial_out(up, UART_IER, 0);
+
+       wait_for_xmitr(up, BOTH_EMPTY);
+       /*
+        *      Send the character out.
+        *      If a LF, also do CR...
+        */
+       serial_out(up, UART_TX, c);
+       if (c == 10) {
+               wait_for_xmitr(up, BOTH_EMPTY);
+               serial_out(up, UART_TX, 13);
+       }
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the IER
+        */
+       wait_for_xmitr(up, BOTH_EMPTY);
+       serial_out(up, UART_IER, ier);
+}
+
+#endif /* CONFIG_CONSOLE_POLL */
+
+static int serial8250_startup(struct uart_port *port)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+       unsigned long flags;
+       unsigned char lsr, iir;
+       int retval;
+
+       up->port.fifosize = uart_config[up->port.type].fifo_size;
+       up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
+       up->capabilities = uart_config[up->port.type].flags;
+       up->mcr = 0;
+
+       if (up->port.iotype != up->cur_iotype)
+               set_io_from_upio(port);
+
+       if (up->port.type == PORT_16C950) {
+               /* Wake up and initialize UART */
+               up->acr = 0;
+               serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
+               serial_outp(up, UART_EFR, UART_EFR_ECB);
+               serial_outp(up, UART_IER, 0);
+               serial_outp(up, UART_LCR, 0);
+               serial_icr_write(up, UART_CSR, 0); /* Reset the UART */
+               serial_outp(up, UART_LCR, 0xBF);
+               serial_outp(up, UART_EFR, UART_EFR_ECB);
+               serial_outp(up, UART_LCR, 0);
+       }
+
+#ifdef CONFIG_SERIAL_8250_RSA
+       /*
+        * If this is an RSA port, see if we can kick it up to the
+        * higher speed clock.
+        */
+       enable_rsa(up);
+#endif
+
+       /*
+        * Clear the FIFO buffers and disable them.
+        * (they will be reenabled in set_termios())
+        */
+       serial8250_clear_fifos(up);
+
+       /*
+        * Clear the interrupt registers.
+        */
+       (void) serial_inp(up, UART_LSR);
+       (void) serial_inp(up, UART_RX);
+       (void) serial_inp(up, UART_IIR);
+       (void) serial_inp(up, UART_MSR);
+
+       /*
+        * At this point, there's no way the LSR could still be 0xff;
+        * if it is, then bail out, because there's likely no UART
+        * here.
+        */
+       if (!(up->port.flags & UPF_BUGGY_UART) &&
+           (serial_inp(up, UART_LSR) == 0xff)) {
+               printk(KERN_INFO "ttyS%d: LSR safety check engaged!\n",
+                      serial_index(&up->port));
+               return -ENODEV;
+       }
+
+       /*
+        * For a XR16C850, we need to set the trigger levels
+        */
+       if (up->port.type == PORT_16850) {
+               unsigned char fctr;
+
+               serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
+
+               fctr = serial_inp(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX);
+               serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_RX);
+               serial_outp(up, UART_TRG, UART_TRG_96);
+               serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_TX);
+               serial_outp(up, UART_TRG, UART_TRG_96);
+
+               serial_outp(up, UART_LCR, 0);
+       }
+
+       if (is_real_interrupt(up->port.irq)) {
+               unsigned char iir1;
+               /*
+                * Test for UARTs that do not reassert THRE when the
+                * transmitter is idle and the interrupt has already
+                * been cleared.  Real 16550s should always reassert
+                * this interrupt whenever the transmitter is idle and
+                * the interrupt is enabled.  Delays are necessary to
+                * allow register changes to become visible.
+                */
+               spin_lock_irqsave(&up->port.lock, flags);
+               if (up->port.irqflags & IRQF_SHARED)
+                       disable_irq_nosync(up->port.irq);
+
+               wait_for_xmitr(up, UART_LSR_THRE);
+               serial_out_sync(up, UART_IER, UART_IER_THRI);
+               udelay(1); /* allow THRE to set */
+               iir1 = serial_in(up, UART_IIR);
+               serial_out(up, UART_IER, 0);
+               serial_out_sync(up, UART_IER, UART_IER_THRI);
+               udelay(1); /* allow a working UART time to re-assert THRE */
+               iir = serial_in(up, UART_IIR);
+               serial_out(up, UART_IER, 0);
+
+               if (up->port.irqflags & IRQF_SHARED)
+                       enable_irq(up->port.irq);
+               spin_unlock_irqrestore(&up->port.lock, flags);
+
+               /*
+                * If the interrupt is not reasserted, setup a timer to
+                * kick the UART on a regular basis.
+                */
+               if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) {
+                       up->bugs |= UART_BUG_THRE;
+                       pr_debug("ttyS%d - using backup timer\n",
+                                serial_index(port));
+               }
+       }
+
+       /*
+        * The above check will only give an accurate result the first time
+        * the port is opened so this value needs to be preserved.
+        */
+       if (up->bugs & UART_BUG_THRE) {
+               up->timer.function = serial8250_backup_timeout;
+               up->timer.data = (unsigned long)up;
+               mod_timer(&up->timer, jiffies +
+                       uart_poll_timeout(port) + HZ / 5);
+       }
+
+       /*
+        * If the "interrupt" for this port doesn't correspond with any
+        * hardware interrupt, we use a timer-based system.  The original
+        * driver used to do this with IRQ0.
+        */
+       if (!is_real_interrupt(up->port.irq)) {
+               up->timer.data = (unsigned long)up;
+               mod_timer(&up->timer, jiffies + uart_poll_timeout(port));
+       } else {
+               retval = serial_link_irq_chain(up);
+               if (retval)
+                       return retval;
+       }
+
+       /*
+        * Now, initialize the UART
+        */
+       serial_outp(up, UART_LCR, UART_LCR_WLEN8);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       if (up->port.flags & UPF_FOURPORT) {
+               if (!is_real_interrupt(up->port.irq))
+                       up->port.mctrl |= TIOCM_OUT1;
+       } else
+               /*
+                * Most PC uarts need OUT2 raised to enable interrupts.
+                */
+               if (is_real_interrupt(up->port.irq))
+                       up->port.mctrl |= TIOCM_OUT2;
+
+       serial8250_set_mctrl(&up->port, up->port.mctrl);
+
+       /* Serial over Lan (SoL) hack:
+          Intel 8257x Gigabit ethernet chips have a
+          16550 emulation, to be used for Serial Over Lan.
+          Those chips take a longer time than a normal
+          serial device to signalize that a transmission
+          data was queued. Due to that, the above test generally
+          fails. One solution would be to delay the reading of
+          iir. However, this is not reliable, since the timeout
+          is variable. So, let's just don't test if we receive
+          TX irq. This way, we'll never enable UART_BUG_TXEN.
+        */
+       if (skip_txen_test || up->port.flags & UPF_NO_TXEN_TEST)
+               goto dont_test_tx_en;
+
+       /*
+        * Do a quick test to see if we receive an
+        * interrupt when we enable the TX irq.
+        */
+       serial_outp(up, UART_IER, UART_IER_THRI);
+       lsr = serial_in(up, UART_LSR);
+       iir = serial_in(up, UART_IIR);
+       serial_outp(up, UART_IER, 0);
+
+       if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {
+               if (!(up->bugs & UART_BUG_TXEN)) {
+                       up->bugs |= UART_BUG_TXEN;
+                       pr_debug("ttyS%d - enabling bad tx status workarounds\n",
+                                serial_index(port));
+               }
+       } else {
+               up->bugs &= ~UART_BUG_TXEN;
+       }
+
+dont_test_tx_en:
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       /*
+        * Clear the interrupt registers again for luck, and clear the
+        * saved flags to avoid getting false values from polling
+        * routines or the previous session.
+        */
+       serial_inp(up, UART_LSR);
+       serial_inp(up, UART_RX);
+       serial_inp(up, UART_IIR);
+       serial_inp(up, UART_MSR);
+       up->lsr_saved_flags = 0;
+       up->msr_saved_flags = 0;
+
+       /*
+        * Finally, enable interrupts.  Note: Modem status interrupts
+        * are set via set_termios(), which will be occurring imminently
+        * anyway, so we don't enable them here.
+        */
+       up->ier = UART_IER_RLSI | UART_IER_RDI;
+       serial_outp(up, UART_IER, up->ier);
+
+       if (up->port.flags & UPF_FOURPORT) {
+               unsigned int icp;
+               /*
+                * Enable interrupts on the AST Fourport board
+                */
+               icp = (up->port.iobase & 0xfe0) | 0x01f;
+               outb_p(0x80, icp);
+               (void) inb_p(icp);
+       }
+
+       return 0;
+}
+
+static void serial8250_shutdown(struct uart_port *port)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+       unsigned long flags;
+
+       /*
+        * Disable interrupts from this port
+        */
+       up->ier = 0;
+       serial_outp(up, UART_IER, 0);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       if (up->port.flags & UPF_FOURPORT) {
+               /* reset interrupts on the AST Fourport board */
+               inb((up->port.iobase & 0xfe0) | 0x1f);
+               up->port.mctrl |= TIOCM_OUT1;
+       } else
+               up->port.mctrl &= ~TIOCM_OUT2;
+
+       serial8250_set_mctrl(&up->port, up->port.mctrl);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       /*
+        * Disable break condition and FIFOs
+        */
+       serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC);
+       serial8250_clear_fifos(up);
+
+#ifdef CONFIG_SERIAL_8250_RSA
+       /*
+        * Reset the RSA board back to 115kbps compat mode.
+        */
+       disable_rsa(up);
+#endif
+
+       /*
+        * Read data port to reset things, and then unlink from
+        * the IRQ chain.
+        */
+       (void) serial_in(up, UART_RX);
+
+       del_timer_sync(&up->timer);
+       up->timer.function = serial8250_timeout;
+       if (is_real_interrupt(up->port.irq))
+               serial_unlink_irq_chain(up);
+}
+
+static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud)
+{
+       unsigned int quot;
+
+       /*
+        * Handle magic divisors for baud rates above baud_base on
+        * SMSC SuperIO chips.
+        */
+       if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
+           baud == (port->uartclk/4))
+               quot = 0x8001;
+       else if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
+                baud == (port->uartclk/8))
+               quot = 0x8002;
+       else
+               quot = uart_get_divisor(port, baud);
+
+       return quot;
+}
+
+void
+serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
+                         struct ktermios *old)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+       unsigned char cval, fcr = 0;
+       unsigned long flags;
+       unsigned int baud, quot;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               cval = UART_LCR_WLEN5;
+               break;
+       case CS6:
+               cval = UART_LCR_WLEN6;
+               break;
+       case CS7:
+               cval = UART_LCR_WLEN7;
+               break;
+       default:
+       case CS8:
+               cval = UART_LCR_WLEN8;
+               break;
+       }
+
+       if (termios->c_cflag & CSTOPB)
+               cval |= UART_LCR_STOP;
+       if (termios->c_cflag & PARENB)
+               cval |= UART_LCR_PARITY;
+       if (!(termios->c_cflag & PARODD))
+               cval |= UART_LCR_EPAR;
+#ifdef CMSPAR
+       if (termios->c_cflag & CMSPAR)
+               cval |= UART_LCR_SPAR;
+#endif
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old,
+                                 port->uartclk / 16 / 0xffff,
+                                 port->uartclk / 16);
+       quot = serial8250_get_divisor(port, baud);
+
+       /*
+        * Oxford Semi 952 rev B workaround
+        */
+       if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0)
+               quot++;
+
+       if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) {
+               if (baud < 2400)
+                       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
+               else
+                       fcr = uart_config[up->port.type].fcr;
+       }
+
+       /*
+        * MCR-based auto flow control.  When AFE is enabled, RTS will be
+        * deasserted when the receive FIFO contains more characters than
+        * the trigger, or the MCR RTS bit is cleared.  In the case where
+        * the remote UART is not using CTS auto flow control, we must
+        * have sufficient FIFO entries for the latency of the remote
+        * UART to respond.  IOW, at least 32 bytes of FIFO.
+        */
+       if (up->capabilities & UART_CAP_AFE && up->port.fifosize >= 32) {
+               up->mcr &= ~UART_MCR_AFE;
+               if (termios->c_cflag & CRTSCTS)
+                       up->mcr |= UART_MCR_AFE;
+       }
+
+       /*
+        * Ok, we're now changing the port state.  Do it with
+        * interrupts disabled.
+        */
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+       if (termios->c_iflag & INPCK)
+               up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               up->port.read_status_mask |= UART_LSR_BI;
+
+       /*
+        * Characteres to ignore
+        */
+       up->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+       if (termios->c_iflag & IGNBRK) {
+               up->port.ignore_status_mask |= UART_LSR_BI;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       up->port.ignore_status_mask |= UART_LSR_OE;
+       }
+
+       /*
+        * ignore all characters if CREAD is not set
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               up->port.ignore_status_mask |= UART_LSR_DR;
+
+       /*
+        * CTS flow control flag and modem status interrupts
+        */
+       up->ier &= ~UART_IER_MSI;
+       if (!(up->bugs & UART_BUG_NOMSR) &&
+                       UART_ENABLE_MS(&up->port, termios->c_cflag))
+               up->ier |= UART_IER_MSI;
+       if (up->capabilities & UART_CAP_UUE)
+               up->ier |= UART_IER_UUE | UART_IER_RTOIE;
+
+       serial_out(up, UART_IER, up->ier);
+
+       if (up->capabilities & UART_CAP_EFR) {
+               unsigned char efr = 0;
+               /*
+                * TI16C752/Startech hardware flow control.  FIXME:
+                * - TI16C752 requires control thresholds to be set.
+                * - UART_MCR_RTS is ineffective if auto-RTS mode is enabled.
+                */
+               if (termios->c_cflag & CRTSCTS)
+                       efr |= UART_EFR_CTS;
+
+               serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
+               serial_outp(up, UART_EFR, efr);
+       }
+
+#ifdef CONFIG_ARCH_OMAP
+       /* Workaround to enable 115200 baud on OMAP1510 internal ports */
+       if (cpu_is_omap1510() && is_omap_port(up)) {
+               if (baud == 115200) {
+                       quot = 1;
+                       serial_out(up, UART_OMAP_OSC_12M_SEL, 1);
+               } else
+                       serial_out(up, UART_OMAP_OSC_12M_SEL, 0);
+       }
+#endif
+
+       if (up->capabilities & UART_NATSEMI) {
+               /* Switch to bank 2 not bank 1, to avoid resetting EXCR2 */
+               serial_outp(up, UART_LCR, 0xe0);
+       } else {
+               serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
+       }
+
+       serial_dl_write(up, quot);
+
+       /*
+        * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
+        * is written without DLAB set, this mode will be disabled.
+        */
+       if (up->port.type == PORT_16750)
+               serial_outp(up, UART_FCR, fcr);
+
+       serial_outp(up, UART_LCR, cval);                /* reset DLAB */
+       up->lcr = cval;                                 /* Save LCR */
+       if (up->port.type != PORT_16750) {
+               if (fcr & UART_FCR_ENABLE_FIFO) {
+                       /* emulated UARTs (Lucent Venus 167x) need two steps */
+                       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+               }
+               serial_outp(up, UART_FCR, fcr);         /* set fcr */
+       }
+       serial8250_set_mctrl(&up->port, up->port.mctrl);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+       /* Don't rewrite B0 */
+       if (tty_termios_baud_rate(termios))
+               tty_termios_encode_baud_rate(termios, baud, baud);
+}
+EXPORT_SYMBOL(serial8250_do_set_termios);
+
+static void
+serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
+                      struct ktermios *old)
+{
+       if (port->set_termios)
+               port->set_termios(port, termios, old);
+       else
+               serial8250_do_set_termios(port, termios, old);
+}
+
+static void
+serial8250_set_ldisc(struct uart_port *port, int new)
+{
+       if (new == N_PPS) {
+               port->flags |= UPF_HARDPPS_CD;
+               serial8250_enable_ms(port);
+       } else
+               port->flags &= ~UPF_HARDPPS_CD;
+}
+
+
+void serial8250_do_pm(struct uart_port *port, unsigned int state,
+                     unsigned int oldstate)
+{
+       struct uart_8250_port *p =
+               container_of(port, struct uart_8250_port, port);
+
+       serial8250_set_sleep(p, state != 0);
+}
+EXPORT_SYMBOL(serial8250_do_pm);
+
+static void
+serial8250_pm(struct uart_port *port, unsigned int state,
+             unsigned int oldstate)
+{
+       if (port->pm)
+               port->pm(port, state, oldstate);
+       else
+               serial8250_do_pm(port, state, oldstate);
+}
+
+static unsigned int serial8250_port_size(struct uart_8250_port *pt)
+{
+       if (pt->port.iotype == UPIO_AU)
+               return 0x1000;
+#ifdef CONFIG_ARCH_OMAP
+       if (is_omap_port(pt))
+               return 0x16 << pt->port.regshift;
+#endif
+       return 8 << pt->port.regshift;
+}
+
+/*
+ * Resource handling.
+ */
+static int serial8250_request_std_resource(struct uart_8250_port *up)
+{
+       unsigned int size = serial8250_port_size(up);
+       int ret = 0;
+
+       switch (up->port.iotype) {
+       case UPIO_AU:
+       case UPIO_TSI:
+       case UPIO_MEM32:
+       case UPIO_MEM:
+       case UPIO_DWAPB:
+       case UPIO_DWAPB32:
+               if (!up->port.mapbase)
+                       break;
+
+               if (!request_mem_region(up->port.mapbase, size, "serial")) {
+                       ret = -EBUSY;
+                       break;
+               }
+
+               if (up->port.flags & UPF_IOREMAP) {
+                       up->port.membase = ioremap_nocache(up->port.mapbase,
+                                                                       size);
+                       if (!up->port.membase) {
+                               release_mem_region(up->port.mapbase, size);
+                               ret = -ENOMEM;
+                       }
+               }
+               break;
+
+       case UPIO_HUB6:
+       case UPIO_PORT:
+               if (!request_region(up->port.iobase, size, "serial"))
+                       ret = -EBUSY;
+               break;
+       }
+       return ret;
+}
+
+static void serial8250_release_std_resource(struct uart_8250_port *up)
+{
+       unsigned int size = serial8250_port_size(up);
+
+       switch (up->port.iotype) {
+       case UPIO_AU:
+       case UPIO_TSI:
+       case UPIO_MEM32:
+       case UPIO_MEM:
+       case UPIO_DWAPB:
+       case UPIO_DWAPB32:
+               if (!up->port.mapbase)
+                       break;
+
+               if (up->port.flags & UPF_IOREMAP) {
+                       iounmap(up->port.membase);
+                       up->port.membase = NULL;
+               }
+
+               release_mem_region(up->port.mapbase, size);
+               break;
+
+       case UPIO_HUB6:
+       case UPIO_PORT:
+               release_region(up->port.iobase, size);
+               break;
+       }
+}
+
+static int serial8250_request_rsa_resource(struct uart_8250_port *up)
+{
+       unsigned long start = UART_RSA_BASE << up->port.regshift;
+       unsigned int size = 8 << up->port.regshift;
+       int ret = -EINVAL;
+
+       switch (up->port.iotype) {
+       case UPIO_HUB6:
+       case UPIO_PORT:
+               start += up->port.iobase;
+               if (request_region(start, size, "serial-rsa"))
+                       ret = 0;
+               else
+                       ret = -EBUSY;
+               break;
+       }
+
+       return ret;
+}
+
+static void serial8250_release_rsa_resource(struct uart_8250_port *up)
+{
+       unsigned long offset = UART_RSA_BASE << up->port.regshift;
+       unsigned int size = 8 << up->port.regshift;
+
+       switch (up->port.iotype) {
+       case UPIO_HUB6:
+       case UPIO_PORT:
+               release_region(up->port.iobase + offset, size);
+               break;
+       }
+}
+
+static void serial8250_release_port(struct uart_port *port)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+
+       serial8250_release_std_resource(up);
+       if (up->port.type == PORT_RSA)
+               serial8250_release_rsa_resource(up);
+}
+
+static int serial8250_request_port(struct uart_port *port)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+       int ret = 0;
+
+       ret = serial8250_request_std_resource(up);
+       if (ret == 0 && up->port.type == PORT_RSA) {
+               ret = serial8250_request_rsa_resource(up);
+               if (ret < 0)
+                       serial8250_release_std_resource(up);
+       }
+
+       return ret;
+}
+
+static void serial8250_config_port(struct uart_port *port, int flags)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+       int probeflags = PROBE_ANY;
+       int ret;
+
+       /*
+        * Find the region that we can probe for.  This in turn
+        * tells us whether we can probe for the type of port.
+        */
+       ret = serial8250_request_std_resource(up);
+       if (ret < 0)
+               return;
+
+       ret = serial8250_request_rsa_resource(up);
+       if (ret < 0)
+               probeflags &= ~PROBE_RSA;
+
+       if (up->port.iotype != up->cur_iotype)
+               set_io_from_upio(port);
+
+       if (flags & UART_CONFIG_TYPE)
+               autoconfig(up, probeflags);
+
+       /* if access method is AU, it is a 16550 with a quirk */
+       if (up->port.type == PORT_16550A && up->port.iotype == UPIO_AU)
+               up->bugs |= UART_BUG_NOMSR;
+
+       if (up->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ)
+               autoconfig_irq(up);
+
+       if (up->port.type != PORT_RSA && probeflags & PROBE_RSA)
+               serial8250_release_rsa_resource(up);
+       if (up->port.type == PORT_UNKNOWN)
+               serial8250_release_std_resource(up);
+}
+
+static int
+serial8250_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       if (ser->irq >= nr_irqs || ser->irq < 0 ||
+           ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||
+           ser->type >= ARRAY_SIZE(uart_config) || ser->type == PORT_CIRRUS ||
+           ser->type == PORT_STARTECH)
+               return -EINVAL;
+       return 0;
+}
+
+static const char *
+serial8250_type(struct uart_port *port)
+{
+       int type = port->type;
+
+       if (type >= ARRAY_SIZE(uart_config))
+               type = 0;
+       return uart_config[type].name;
+}
+
+static struct uart_ops serial8250_pops = {
+       .tx_empty       = serial8250_tx_empty,
+       .set_mctrl      = serial8250_set_mctrl,
+       .get_mctrl      = serial8250_get_mctrl,
+       .stop_tx        = serial8250_stop_tx,
+       .start_tx       = serial8250_start_tx,
+       .stop_rx        = serial8250_stop_rx,
+       .enable_ms      = serial8250_enable_ms,
+       .break_ctl      = serial8250_break_ctl,
+       .startup        = serial8250_startup,
+       .shutdown       = serial8250_shutdown,
+       .set_termios    = serial8250_set_termios,
+       .set_ldisc      = serial8250_set_ldisc,
+       .pm             = serial8250_pm,
+       .type           = serial8250_type,
+       .release_port   = serial8250_release_port,
+       .request_port   = serial8250_request_port,
+       .config_port    = serial8250_config_port,
+       .verify_port    = serial8250_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char = serial8250_get_poll_char,
+       .poll_put_char = serial8250_put_poll_char,
+#endif
+};
+
+static struct uart_8250_port serial8250_ports[UART_NR];
+
+static void (*serial8250_isa_config)(int port, struct uart_port *up,
+       unsigned short *capabilities);
+
+void serial8250_set_isa_configurator(
+       void (*v)(int port, struct uart_port *up, unsigned short *capabilities))
+{
+       serial8250_isa_config = v;
+}
+EXPORT_SYMBOL(serial8250_set_isa_configurator);
+
+static void __init serial8250_isa_init_ports(void)
+{
+       struct uart_8250_port *up;
+       static int first = 1;
+       int i, irqflag = 0;
+
+       if (!first)
+               return;
+       first = 0;
+
+       for (i = 0; i < nr_uarts; i++) {
+               struct uart_8250_port *up = &serial8250_ports[i];
+
+               up->port.line = i;
+               spin_lock_init(&up->port.lock);
+
+               init_timer(&up->timer);
+               up->timer.function = serial8250_timeout;
+
+               /*
+                * ALPHA_KLUDGE_MCR needs to be killed.
+                */
+               up->mcr_mask = ~ALPHA_KLUDGE_MCR;
+               up->mcr_force = ALPHA_KLUDGE_MCR;
+
+               up->port.ops = &serial8250_pops;
+       }
+
+       if (share_irqs)
+               irqflag = IRQF_SHARED;
+
+       for (i = 0, up = serial8250_ports;
+            i < ARRAY_SIZE(old_serial_port) && i < nr_uarts;
+            i++, up++) {
+               up->port.iobase   = old_serial_port[i].port;
+               up->port.irq      = irq_canonicalize(old_serial_port[i].irq);
+               up->port.irqflags = old_serial_port[i].irqflags;
+               up->port.uartclk  = old_serial_port[i].baud_base * 16;
+               up->port.flags    = old_serial_port[i].flags;
+               up->port.hub6     = old_serial_port[i].hub6;
+               up->port.membase  = old_serial_port[i].iomem_base;
+               up->port.iotype   = old_serial_port[i].io_type;
+               up->port.regshift = old_serial_port[i].iomem_reg_shift;
+               set_io_from_upio(&up->port);
+               up->port.irqflags |= irqflag;
+               if (serial8250_isa_config != NULL)
+                       serial8250_isa_config(i, &up->port, &up->capabilities);
+
+       }
+}
+
+static void
+serial8250_init_fixed_type_port(struct uart_8250_port *up, unsigned int type)
+{
+       up->port.type = type;
+       up->port.fifosize = uart_config[type].fifo_size;
+       up->capabilities = uart_config[type].flags;
+       up->tx_loadsz = uart_config[type].tx_loadsz;
+}
+
+static void __init
+serial8250_register_ports(struct uart_driver *drv, struct device *dev)
+{
+       int i;
+
+       for (i = 0; i < nr_uarts; i++) {
+               struct uart_8250_port *up = &serial8250_ports[i];
+               up->cur_iotype = 0xFF;
+       }
+
+       serial8250_isa_init_ports();
+
+       for (i = 0; i < nr_uarts; i++) {
+               struct uart_8250_port *up = &serial8250_ports[i];
+
+               up->port.dev = dev;
+
+               if (up->port.flags & UPF_FIXED_TYPE)
+                       serial8250_init_fixed_type_port(up, up->port.type);
+
+               uart_add_one_port(drv, &up->port);
+       }
+}
+
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+
+static void serial8250_console_putchar(struct uart_port *port, int ch)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+
+       wait_for_xmitr(up, UART_LSR_THRE);
+       serial_out(up, UART_TX, ch);
+}
+
+/*
+ *     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.
+ */
+static void
+serial8250_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct uart_8250_port *up = &serial8250_ports[co->index];
+       unsigned long flags;
+       unsigned int ier;
+       int locked = 1;
+
+       touch_nmi_watchdog();
+
+       local_irq_save(flags);
+       if (up->port.sysrq) {
+               /* serial8250_handle_port() already took the lock */
+               locked = 0;
+       } else if (oops_in_progress) {
+               locked = spin_trylock(&up->port.lock);
+       } else
+               spin_lock(&up->port.lock);
+
+       /*
+        *      First save the IER then disable the interrupts
+        */
+       ier = serial_in(up, UART_IER);
+
+       if (up->capabilities & UART_CAP_UUE)
+               serial_out(up, UART_IER, UART_IER_UUE);
+       else
+               serial_out(up, UART_IER, 0);
+
+       uart_console_write(&up->port, s, count, serial8250_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the IER
+        */
+       wait_for_xmitr(up, BOTH_EMPTY);
+       serial_out(up, UART_IER, ier);
+
+       /*
+        *      The receive handling will happen properly because the
+        *      receive ready bit will still be set; it is not cleared
+        *      on read.  However, modem control will not, we must
+        *      call it if we have saved something in the saved flags
+        *      while processing with interrupts off.
+        */
+       if (up->msr_saved_flags)
+               check_modem_status(up);
+
+       if (locked)
+               spin_unlock(&up->port.lock);
+       local_irq_restore(flags);
+}
+
+static int __init serial8250_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       int baud = 9600;
+       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.
+        */
+       if (co->index >= nr_uarts)
+               co->index = 0;
+       port = &serial8250_ports[co->index].port;
+       if (!port->iobase && !port->membase)
+               return -ENODEV;
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static int serial8250_console_early_setup(void)
+{
+       return serial8250_find_port_for_earlycon();
+}
+
+static struct console serial8250_console = {
+       .name           = "ttyS",
+       .write          = serial8250_console_write,
+       .device         = uart_console_device,
+       .setup          = serial8250_console_setup,
+       .early_setup    = serial8250_console_early_setup,
+       .flags          = CON_PRINTBUFFER | CON_ANYTIME,
+       .index          = -1,
+       .data           = &serial8250_reg,
+};
+
+static int __init serial8250_console_init(void)
+{
+       if (nr_uarts > UART_NR)
+               nr_uarts = UART_NR;
+
+       serial8250_isa_init_ports();
+       register_console(&serial8250_console);
+       return 0;
+}
+console_initcall(serial8250_console_init);
+
+int serial8250_find_port(struct uart_port *p)
+{
+       int line;
+       struct uart_port *port;
+
+       for (line = 0; line < nr_uarts; line++) {
+               port = &serial8250_ports[line].port;
+               if (uart_match_port(p, port))
+                       return line;
+       }
+       return -ENODEV;
+}
+
+#define SERIAL8250_CONSOLE     &serial8250_console
+#else
+#define SERIAL8250_CONSOLE     NULL
+#endif
+
+static struct uart_driver serial8250_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "serial",
+       .dev_name               = "ttyS",
+       .major                  = TTY_MAJOR,
+       .minor                  = 64,
+       .cons                   = SERIAL8250_CONSOLE,
+};
+
+/*
+ * early_serial_setup - early registration for 8250 ports
+ *
+ * Setup an 8250 port structure prior to console initialisation.  Use
+ * after console initialisation will cause undefined behaviour.
+ */
+int __init early_serial_setup(struct uart_port *port)
+{
+       struct uart_port *p;
+
+       if (port->line >= ARRAY_SIZE(serial8250_ports))
+               return -ENODEV;
+
+       serial8250_isa_init_ports();
+       p = &serial8250_ports[port->line].port;
+       p->iobase       = port->iobase;
+       p->membase      = port->membase;
+       p->irq          = port->irq;
+       p->irqflags     = port->irqflags;
+       p->uartclk      = port->uartclk;
+       p->fifosize     = port->fifosize;
+       p->regshift     = port->regshift;
+       p->iotype       = port->iotype;
+       p->flags        = port->flags;
+       p->mapbase      = port->mapbase;
+       p->private_data = port->private_data;
+       p->type         = port->type;
+       p->line         = port->line;
+
+       set_io_from_upio(p);
+       if (port->serial_in)
+               p->serial_in = port->serial_in;
+       if (port->serial_out)
+               p->serial_out = port->serial_out;
+
+       return 0;
+}
+
+/**
+ *     serial8250_suspend_port - suspend one serial port
+ *     @line:  serial line number
+ *
+ *     Suspend one serial port.
+ */
+void serial8250_suspend_port(int line)
+{
+       uart_suspend_port(&serial8250_reg, &serial8250_ports[line].port);
+}
+
+/**
+ *     serial8250_resume_port - resume one serial port
+ *     @line:  serial line number
+ *
+ *     Resume one serial port.
+ */
+void serial8250_resume_port(int line)
+{
+       struct uart_8250_port *up = &serial8250_ports[line];
+
+       if (up->capabilities & UART_NATSEMI) {
+               unsigned char tmp;
+
+               /* Ensure it's still in high speed mode */
+               serial_outp(up, UART_LCR, 0xE0);
+
+               tmp = serial_in(up, 0x04); /* EXCR2 */
+               tmp &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
+               tmp |= 0x10;  /* 1.625 divisor for baud_base --> 921600 */
+               serial_outp(up, 0x04, tmp);
+
+               serial_outp(up, UART_LCR, 0);
+       }
+       uart_resume_port(&serial8250_reg, &up->port);
+}
+
+/*
+ * Register a set of serial devices attached to a platform device.  The
+ * list is terminated with a zero flags entry, which means we expect
+ * all entries to have at least UPF_BOOT_AUTOCONF set.
+ */
+static int __devinit serial8250_probe(struct platform_device *dev)
+{
+       struct plat_serial8250_port *p = dev->dev.platform_data;
+       struct uart_port port;
+       int ret, i, irqflag = 0;
+
+       memset(&port, 0, sizeof(struct uart_port));
+
+       if (share_irqs)
+               irqflag = IRQF_SHARED;
+
+       for (i = 0; p && p->flags != 0; p++, i++) {
+               port.iobase             = p->iobase;
+               port.membase            = p->membase;
+               port.irq                = p->irq;
+               port.irqflags           = p->irqflags;
+               port.uartclk            = p->uartclk;
+               port.regshift           = p->regshift;
+               port.iotype             = p->iotype;
+               port.flags              = p->flags;
+               port.mapbase            = p->mapbase;
+               port.hub6               = p->hub6;
+               port.private_data       = p->private_data;
+               port.type               = p->type;
+               port.serial_in          = p->serial_in;
+               port.serial_out         = p->serial_out;
+               port.set_termios        = p->set_termios;
+               port.pm                 = p->pm;
+               port.dev                = &dev->dev;
+               port.irqflags           |= irqflag;
+               ret = serial8250_register_port(&port);
+               if (ret < 0) {
+                       dev_err(&dev->dev, "unable to register port at index %d "
+                               "(IO%lx MEM%llx IRQ%d): %d\n", i,
+                               p->iobase, (unsigned long long)p->mapbase,
+                               p->irq, ret);
+               }
+       }
+       return 0;
+}
+
+/*
+ * Remove serial ports registered against a platform device.
+ */
+static int __devexit serial8250_remove(struct platform_device *dev)
+{
+       int i;
+
+       for (i = 0; i < nr_uarts; i++) {
+               struct uart_8250_port *up = &serial8250_ports[i];
+
+               if (up->port.dev == &dev->dev)
+                       serial8250_unregister_port(i);
+       }
+       return 0;
+}
+
+static int serial8250_suspend(struct platform_device *dev, pm_message_t state)
+{
+       int i;
+
+       for (i = 0; i < UART_NR; i++) {
+               struct uart_8250_port *up = &serial8250_ports[i];
+
+               if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
+                       uart_suspend_port(&serial8250_reg, &up->port);
+       }
+
+       return 0;
+}
+
+static int serial8250_resume(struct platform_device *dev)
+{
+       int i;
+
+       for (i = 0; i < UART_NR; i++) {
+               struct uart_8250_port *up = &serial8250_ports[i];
+
+               if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
+                       serial8250_resume_port(i);
+       }
+
+       return 0;
+}
+
+static struct platform_driver serial8250_isa_driver = {
+       .probe          = serial8250_probe,
+       .remove         = __devexit_p(serial8250_remove),
+       .suspend        = serial8250_suspend,
+       .resume         = serial8250_resume,
+       .driver         = {
+               .name   = "serial8250",
+               .owner  = THIS_MODULE,
+       },
+};
+
+/*
+ * This "device" covers _all_ ISA 8250-compatible serial devices listed
+ * in the table in include/asm/serial.h
+ */
+static struct platform_device *serial8250_isa_devs;
+
+/*
+ * serial8250_register_port and serial8250_unregister_port allows for
+ * 16x50 serial ports to be configured at run-time, to support PCMCIA
+ * modems and PCI multiport cards.
+ */
+static DEFINE_MUTEX(serial_mutex);
+
+static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *port)
+{
+       int i;
+
+       /*
+        * First, find a port entry which matches.
+        */
+       for (i = 0; i < nr_uarts; i++)
+               if (uart_match_port(&serial8250_ports[i].port, port))
+                       return &serial8250_ports[i];
+
+       /*
+        * We didn't find a matching entry, so look for the first
+        * free entry.  We look for one which hasn't been previously
+        * used (indicated by zero iobase).
+        */
+       for (i = 0; i < nr_uarts; i++)
+               if (serial8250_ports[i].port.type == PORT_UNKNOWN &&
+                   serial8250_ports[i].port.iobase == 0)
+                       return &serial8250_ports[i];
+
+       /*
+        * That also failed.  Last resort is to find any entry which
+        * doesn't have a real port associated with it.
+        */
+       for (i = 0; i < nr_uarts; i++)
+               if (serial8250_ports[i].port.type == PORT_UNKNOWN)
+                       return &serial8250_ports[i];
+
+       return NULL;
+}
+
+/**
+ *     serial8250_register_port - register a serial port
+ *     @port: serial port template
+ *
+ *     Configure the serial port specified by the request. If the
+ *     port exists and is in use, it is hung up and unregistered
+ *     first.
+ *
+ *     The port is then probed and if necessary the IRQ is autodetected
+ *     If this fails an error is returned.
+ *
+ *     On success the port is ready to use and the line number is returned.
+ */
+int serial8250_register_port(struct uart_port *port)
+{
+       struct uart_8250_port *uart;
+       int ret = -ENOSPC;
+
+       if (port->uartclk == 0)
+               return -EINVAL;
+
+       mutex_lock(&serial_mutex);
+
+       uart = serial8250_find_match_or_unused(port);
+       if (uart) {
+               uart_remove_one_port(&serial8250_reg, &uart->port);
+
+               uart->port.iobase       = port->iobase;
+               uart->port.membase      = port->membase;
+               uart->port.irq          = port->irq;
+               uart->port.irqflags     = port->irqflags;
+               uart->port.uartclk      = port->uartclk;
+               uart->port.fifosize     = port->fifosize;
+               uart->port.regshift     = port->regshift;
+               uart->port.iotype       = port->iotype;
+               uart->port.flags        = port->flags | UPF_BOOT_AUTOCONF;
+               uart->port.mapbase      = port->mapbase;
+               uart->port.private_data = port->private_data;
+               if (port->dev)
+                       uart->port.dev = port->dev;
+
+               if (port->flags & UPF_FIXED_TYPE)
+                       serial8250_init_fixed_type_port(uart, port->type);
+
+               set_io_from_upio(&uart->port);
+               /* Possibly override default I/O functions.  */
+               if (port->serial_in)
+                       uart->port.serial_in = port->serial_in;
+               if (port->serial_out)
+                       uart->port.serial_out = port->serial_out;
+               /*  Possibly override set_termios call */
+               if (port->set_termios)
+                       uart->port.set_termios = port->set_termios;
+               if (port->pm)
+                       uart->port.pm = port->pm;
+
+               if (serial8250_isa_config != NULL)
+                       serial8250_isa_config(0, &uart->port,
+                                       &uart->capabilities);
+
+               ret = uart_add_one_port(&serial8250_reg, &uart->port);
+               if (ret == 0)
+                       ret = uart->port.line;
+       }
+       mutex_unlock(&serial_mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL(serial8250_register_port);
+
+/**
+ *     serial8250_unregister_port - remove a 16x50 serial port at runtime
+ *     @line: serial line number
+ *
+ *     Remove one serial port.  This may not be called from interrupt
+ *     context.  We hand the port back to the our control.
+ */
+void serial8250_unregister_port(int line)
+{
+       struct uart_8250_port *uart = &serial8250_ports[line];
+
+       mutex_lock(&serial_mutex);
+       uart_remove_one_port(&serial8250_reg, &uart->port);
+       if (serial8250_isa_devs) {
+               uart->port.flags &= ~UPF_BOOT_AUTOCONF;
+               uart->port.type = PORT_UNKNOWN;
+               uart->port.dev = &serial8250_isa_devs->dev;
+               uart_add_one_port(&serial8250_reg, &uart->port);
+       } else {
+               uart->port.dev = NULL;
+       }
+       mutex_unlock(&serial_mutex);
+}
+EXPORT_SYMBOL(serial8250_unregister_port);
+
+static int __init serial8250_init(void)
+{
+       int ret;
+
+       if (nr_uarts > UART_NR)
+               nr_uarts = UART_NR;
+
+       printk(KERN_INFO "Serial: 8250/16550 driver, "
+               "%d ports, IRQ sharing %sabled\n", nr_uarts,
+               share_irqs ? "en" : "dis");
+
+#ifdef CONFIG_SPARC
+       ret = sunserial_register_minors(&serial8250_reg, UART_NR);
+#else
+       serial8250_reg.nr = UART_NR;
+       ret = uart_register_driver(&serial8250_reg);
+#endif
+       if (ret)
+               goto out;
+
+       serial8250_isa_devs = platform_device_alloc("serial8250",
+                                                   PLAT8250_DEV_LEGACY);
+       if (!serial8250_isa_devs) {
+               ret = -ENOMEM;
+               goto unreg_uart_drv;
+       }
+
+       ret = platform_device_add(serial8250_isa_devs);
+       if (ret)
+               goto put_dev;
+
+       serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev);
+
+       ret = platform_driver_register(&serial8250_isa_driver);
+       if (ret == 0)
+               goto out;
+
+       platform_device_del(serial8250_isa_devs);
+put_dev:
+       platform_device_put(serial8250_isa_devs);
+unreg_uart_drv:
+#ifdef CONFIG_SPARC
+       sunserial_unregister_minors(&serial8250_reg, UART_NR);
+#else
+       uart_unregister_driver(&serial8250_reg);
+#endif
+out:
+       return ret;
+}
+
+static void __exit serial8250_exit(void)
+{
+       struct platform_device *isa_dev = serial8250_isa_devs;
+
+       /*
+        * This tells serial8250_unregister_port() not to re-register
+        * the ports (thereby making serial8250_isa_driver permanently
+        * in use.)
+        */
+       serial8250_isa_devs = NULL;
+
+       platform_driver_unregister(&serial8250_isa_driver);
+       platform_device_unregister(isa_dev);
+
+#ifdef CONFIG_SPARC
+       sunserial_unregister_minors(&serial8250_reg, UART_NR);
+#else
+       uart_unregister_driver(&serial8250_reg);
+#endif
+}
+
+module_init(serial8250_init);
+module_exit(serial8250_exit);
+
+EXPORT_SYMBOL(serial8250_suspend_port);
+EXPORT_SYMBOL(serial8250_resume_port);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic 8250/16x50 serial driver");
+
+module_param(share_irqs, uint, 0644);
+MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices"
+       " (unsafe)");
+
+module_param(nr_uarts, uint, 0644);
+MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")");
+
+module_param(skip_txen_test, uint, 0644);
+MODULE_PARM_DESC(skip_txen_test, "Skip checking for the TXEN bug at init time");
+
+#ifdef CONFIG_SERIAL_8250_RSA
+module_param_array(probe_rsa, ulong, &probe_rsa_count, 0444);
+MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
+#endif
+MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
diff --git a/drivers/tty/serial/8250.h b/drivers/tty/serial/8250.h
new file mode 100644 (file)
index 0000000..6e19ea3
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ *  linux/drivers/char/8250.h
+ *
+ *  Driver for 8250/16550-type serial ports
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ *  Copyright (C) 2001 Russell King.
+ *
+ * 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.
+ */
+
+#include <linux/serial_8250.h>
+
+struct old_serial_port {
+       unsigned int uart;
+       unsigned int baud_base;
+       unsigned int port;
+       unsigned int irq;
+       unsigned int flags;
+       unsigned char hub6;
+       unsigned char io_type;
+       unsigned char *iomem_base;
+       unsigned short iomem_reg_shift;
+       unsigned long irqflags;
+};
+
+/*
+ * This replaces serial_uart_config in include/linux/serial.h
+ */
+struct serial8250_config {
+       const char      *name;
+       unsigned short  fifo_size;
+       unsigned short  tx_loadsz;
+       unsigned char   fcr;
+       unsigned int    flags;
+};
+
+#define UART_CAP_FIFO  (1 << 8)        /* UART has FIFO */
+#define UART_CAP_EFR   (1 << 9)        /* UART has EFR */
+#define UART_CAP_SLEEP (1 << 10)       /* UART has IER sleep */
+#define UART_CAP_AFE   (1 << 11)       /* MCR-based hw flow control */
+#define UART_CAP_UUE   (1 << 12)       /* UART needs IER bit 6 set (Xscale) */
+
+#define UART_BUG_QUOT  (1 << 0)        /* UART has buggy quot LSB */
+#define UART_BUG_TXEN  (1 << 1)        /* UART has buggy TX IIR status */
+#define UART_BUG_NOMSR (1 << 2)        /* UART has buggy MSR status bits (Au1x00) */
+#define UART_BUG_THRE  (1 << 3)        /* UART has buggy THRE reassertion */
+
+#define PROBE_RSA      (1 << 0)
+#define PROBE_ANY      (~0)
+
+#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
+
+#ifdef CONFIG_SERIAL_8250_SHARE_IRQ
+#define SERIAL8250_SHARE_IRQS 1
+#else
+#define SERIAL8250_SHARE_IRQS 0
+#endif
+
+#if defined(__alpha__) && !defined(CONFIG_PCI)
+/*
+ * Digital did something really horribly wrong with the OUT1 and OUT2
+ * lines on at least some ALPHA's.  The failure mode is that if either
+ * is cleared, the machine locks up with endless interrupts.
+ */
+#define ALPHA_KLUDGE_MCR  (UART_MCR_OUT2 | UART_MCR_OUT1)
+#elif defined(CONFIG_SBC8560)
+/*
+ * WindRiver did something similarly broken on their SBC8560 board. The
+ * UART tristates its IRQ output while OUT2 is clear, but they pulled
+ * the interrupt line _up_ instead of down, so if we register the IRQ
+ * while the UART is in that state, we die in an IRQ storm. */
+#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2)
+#else
+#define ALPHA_KLUDGE_MCR 0
+#endif
diff --git a/drivers/tty/serial/8250_accent.c b/drivers/tty/serial/8250_accent.c
new file mode 100644 (file)
index 0000000..9c10262
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ *  linux/drivers/serial/8250_accent.c
+ *
+ *  Copyright (C) 2005 Russell King.
+ *  Data taken from include/asm-i386/serial.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/serial_8250.h>
+
+#define PORT(_base,_irq)                               \
+       {                                               \
+               .iobase         = _base,                \
+               .irq            = _irq,                 \
+               .uartclk        = 1843200,              \
+               .iotype         = UPIO_PORT,            \
+               .flags          = UPF_BOOT_AUTOCONF,    \
+       }
+
+static struct plat_serial8250_port accent_data[] = {
+       PORT(0x330, 4),
+       PORT(0x338, 4),
+       { },
+};
+
+static struct platform_device accent_device = {
+       .name                   = "serial8250",
+       .id                     = PLAT8250_DEV_ACCENT,
+       .dev                    = {
+               .platform_data  = accent_data,
+       },
+};
+
+static int __init accent_init(void)
+{
+       return platform_device_register(&accent_device);
+}
+
+module_init(accent_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("8250 serial probe module for Accent Async cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250_acorn.c b/drivers/tty/serial/8250_acorn.c
new file mode 100644 (file)
index 0000000..b0ce8c5
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ *  linux/drivers/serial/acorn.c
+ *
+ *  Copyright (C) 1996-2003 Russell King.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/tty.h>
+#include <linux/serial_core.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/ecard.h>
+#include <asm/string.h>
+
+#include "8250.h"
+
+#define MAX_PORTS      3
+
+struct serial_card_type {
+       unsigned int    num_ports;
+       unsigned int    uartclk;
+       unsigned int    type;
+       unsigned int    offset[MAX_PORTS];
+};
+
+struct serial_card_info {
+       unsigned int    num_ports;
+       int             ports[MAX_PORTS];
+       void __iomem *vaddr;
+};
+
+static int __devinit
+serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+       struct serial_card_info *info;
+       struct serial_card_type *type = id->data;
+       struct uart_port port;
+       unsigned long bus_addr;
+       unsigned int i;
+
+       info = kzalloc(sizeof(struct serial_card_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       info->num_ports = type->num_ports;
+
+       bus_addr = ecard_resource_start(ec, type->type);
+       info->vaddr = ecardm_iomap(ec, type->type, 0, 0);
+       if (!info->vaddr) {
+               kfree(info);
+               return -ENOMEM;
+       }
+
+       ecard_set_drvdata(ec, info);
+
+       memset(&port, 0, sizeof(struct uart_port));
+       port.irq        = ec->irq;
+       port.flags      = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+       port.uartclk    = type->uartclk;
+       port.iotype     = UPIO_MEM;
+       port.regshift   = 2;
+       port.dev        = &ec->dev;
+
+       for (i = 0; i < info->num_ports; i ++) {
+               port.membase = info->vaddr + type->offset[i];
+               port.mapbase = bus_addr + type->offset[i];
+
+               info->ports[i] = serial8250_register_port(&port);
+       }
+
+       return 0;
+}
+
+static void __devexit serial_card_remove(struct expansion_card *ec)
+{
+       struct serial_card_info *info = ecard_get_drvdata(ec);
+       int i;
+
+       ecard_set_drvdata(ec, NULL);
+
+       for (i = 0; i < info->num_ports; i++)
+               if (info->ports[i] > 0)
+                       serial8250_unregister_port(info->ports[i]);
+
+       kfree(info);
+}
+
+static struct serial_card_type atomwide_type = {
+       .num_ports      = 3,
+       .uartclk        = 7372800,
+       .type           = ECARD_RES_IOCSLOW,
+       .offset         = { 0x2800, 0x2400, 0x2000 },
+};
+
+static struct serial_card_type serport_type = {
+       .num_ports      = 2,
+       .uartclk        = 3686400,
+       .type           = ECARD_RES_IOCSLOW,
+       .offset         = { 0x2000, 0x2020 },
+};
+
+static const struct ecard_id serial_cids[] = {
+       { MANU_ATOMWIDE,        PROD_ATOMWIDE_3PSERIAL, &atomwide_type  },
+       { MANU_SERPORT,         PROD_SERPORT_DSPORT,    &serport_type   },
+       { 0xffff, 0xffff }
+};
+
+static struct ecard_driver serial_card_driver = {
+       .probe          = serial_card_probe,
+       .remove         = __devexit_p(serial_card_remove),
+       .id_table       = serial_cids,
+       .drv = {
+               .name   = "8250_acorn",
+       },
+};
+
+static int __init serial_card_init(void)
+{
+       return ecard_register_driver(&serial_card_driver);
+}
+
+static void __exit serial_card_exit(void)
+{
+       ecard_remove_driver(&serial_card_driver);
+}
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("Acorn 8250-compatible serial port expansion card driver");
+MODULE_LICENSE("GPL");
+
+module_init(serial_card_init);
+module_exit(serial_card_exit);
diff --git a/drivers/tty/serial/8250_boca.c b/drivers/tty/serial/8250_boca.c
new file mode 100644 (file)
index 0000000..3bfe0f7
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ *  linux/drivers/serial/8250_boca.c
+ *
+ *  Copyright (C) 2005 Russell King.
+ *  Data taken from include/asm-i386/serial.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/serial_8250.h>
+
+#define PORT(_base,_irq)                               \
+       {                                               \
+               .iobase         = _base,                \
+               .irq            = _irq,                 \
+               .uartclk        = 1843200,              \
+               .iotype         = UPIO_PORT,            \
+               .flags          = UPF_BOOT_AUTOCONF,    \
+       }
+
+static struct plat_serial8250_port boca_data[] = {
+       PORT(0x100, 12),
+       PORT(0x108, 12),
+       PORT(0x110, 12),
+       PORT(0x118, 12),
+       PORT(0x120, 12),
+       PORT(0x128, 12),
+       PORT(0x130, 12),
+       PORT(0x138, 12),
+       PORT(0x140, 12),
+       PORT(0x148, 12),
+       PORT(0x150, 12),
+       PORT(0x158, 12),
+       PORT(0x160, 12),
+       PORT(0x168, 12),
+       PORT(0x170, 12),
+       PORT(0x178, 12),
+       { },
+};
+
+static struct platform_device boca_device = {
+       .name                   = "serial8250",
+       .id                     = PLAT8250_DEV_BOCA,
+       .dev                    = {
+               .platform_data  = boca_data,
+       },
+};
+
+static int __init boca_init(void)
+{
+       return platform_device_register(&boca_device);
+}
+
+module_init(boca_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("8250 serial probe module for Boca cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250_early.c b/drivers/tty/serial/8250_early.c
new file mode 100644 (file)
index 0000000..eaafb98
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * Early serial console for 8250/16550 devices
+ *
+ * (c) Copyright 2004 Hewlett-Packard Development Company, L.P.
+ *     Bjorn Helgaas <bjorn.helgaas@hp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Based on the 8250.c serial driver, Copyright (C) 2001 Russell King,
+ * and on early_printk.c by Andi Kleen.
+ *
+ * This is for use before the serial driver has initialized, in
+ * particular, before the UARTs have been discovered and named.
+ * Instead of specifying the console device as, e.g., "ttyS0",
+ * we locate the device directly by its MMIO or I/O port address.
+ *
+ * The user can specify the device directly, e.g.,
+ *     earlycon=uart8250,io,0x3f8,9600n8
+ *     earlycon=uart8250,mmio,0xff5e0000,115200n8
+ *     earlycon=uart8250,mmio32,0xff5e0000,115200n8
+ * or
+ *     console=uart8250,io,0x3f8,9600n8
+ *     console=uart8250,mmio,0xff5e0000,115200n8
+ *     console=uart8250,mmio32,0xff5e0000,115200n8
+ */
+
+#include <linux/tty.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/serial.h>
+#include <linux/serial_8250.h>
+#include <asm/io.h>
+#include <asm/serial.h>
+#ifdef CONFIG_FIX_EARLYCON_MEM
+#include <asm/pgtable.h>
+#include <asm/fixmap.h>
+#endif
+
+struct early_serial8250_device {
+       struct uart_port port;
+       char options[16];               /* e.g., 115200n8 */
+       unsigned int baud;
+};
+
+static struct early_serial8250_device early_device;
+
+static unsigned int __init serial_in(struct uart_port *port, int offset)
+{
+       switch (port->iotype) {
+       case UPIO_MEM:
+               return readb(port->membase + offset);
+       case UPIO_MEM32:
+               return readl(port->membase + (offset << 2));
+       case UPIO_PORT:
+               return inb(port->iobase + offset);
+       default:
+               return 0;
+       }
+}
+
+static void __init serial_out(struct uart_port *port, int offset, int value)
+{
+       switch (port->iotype) {
+       case UPIO_MEM:
+               writeb(value, port->membase + offset);
+               break;
+       case UPIO_MEM32:
+               writel(value, port->membase + (offset << 2));
+               break;
+       case UPIO_PORT:
+               outb(value, port->iobase + offset);
+               break;
+       }
+}
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+static void __init wait_for_xmitr(struct uart_port *port)
+{
+       unsigned int status;
+
+       for (;;) {
+               status = serial_in(port, UART_LSR);
+               if ((status & BOTH_EMPTY) == BOTH_EMPTY)
+                       return;
+               cpu_relax();
+       }
+}
+
+static void __init serial_putc(struct uart_port *port, int c)
+{
+       wait_for_xmitr(port);
+       serial_out(port, UART_TX, c);
+}
+
+static void __init early_serial8250_write(struct console *console,
+                                       const char *s, unsigned int count)
+{
+       struct uart_port *port = &early_device.port;
+       unsigned int ier;
+
+       /* Save the IER and disable interrupts */
+       ier = serial_in(port, UART_IER);
+       serial_out(port, UART_IER, 0);
+
+       uart_console_write(port, s, count, serial_putc);
+
+       /* Wait for transmitter to become empty and restore the IER */
+       wait_for_xmitr(port);
+       serial_out(port, UART_IER, ier);
+}
+
+static unsigned int __init probe_baud(struct uart_port *port)
+{
+       unsigned char lcr, dll, dlm;
+       unsigned int quot;
+
+       lcr = serial_in(port, UART_LCR);
+       serial_out(port, UART_LCR, lcr | UART_LCR_DLAB);
+       dll = serial_in(port, UART_DLL);
+       dlm = serial_in(port, UART_DLM);
+       serial_out(port, UART_LCR, lcr);
+
+       quot = (dlm << 8) | dll;
+       return (port->uartclk / 16) / quot;
+}
+
+static void __init init_port(struct early_serial8250_device *device)
+{
+       struct uart_port *port = &device->port;
+       unsigned int divisor;
+       unsigned char c;
+
+       serial_out(port, UART_LCR, 0x3);        /* 8n1 */
+       serial_out(port, UART_IER, 0);          /* no interrupt */
+       serial_out(port, UART_FCR, 0);          /* no fifo */
+       serial_out(port, UART_MCR, 0x3);        /* DTR + RTS */
+
+       divisor = port->uartclk / (16 * device->baud);
+       c = serial_in(port, UART_LCR);
+       serial_out(port, UART_LCR, c | UART_LCR_DLAB);
+       serial_out(port, UART_DLL, divisor & 0xff);
+       serial_out(port, UART_DLM, (divisor >> 8) & 0xff);
+       serial_out(port, UART_LCR, c & ~UART_LCR_DLAB);
+}
+
+static int __init parse_options(struct early_serial8250_device *device,
+                                                               char *options)
+{
+       struct uart_port *port = &device->port;
+       int mmio, mmio32, length;
+
+       if (!options)
+               return -ENODEV;
+
+       port->uartclk = BASE_BAUD * 16;
+
+       mmio = !strncmp(options, "mmio,", 5);
+       mmio32 = !strncmp(options, "mmio32,", 7);
+       if (mmio || mmio32) {
+               port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32);
+               port->mapbase = simple_strtoul(options + (mmio ? 5 : 7),
+                                              &options, 0);
+               if (mmio32)
+                       port->regshift = 2;
+#ifdef CONFIG_FIX_EARLYCON_MEM
+               set_fixmap_nocache(FIX_EARLYCON_MEM_BASE,
+                                       port->mapbase & PAGE_MASK);
+               port->membase =
+                       (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
+               port->membase += port->mapbase & ~PAGE_MASK;
+#else
+               port->membase = ioremap_nocache(port->mapbase, 64);
+               if (!port->membase) {
+                       printk(KERN_ERR "%s: Couldn't ioremap 0x%llx\n",
+                               __func__,
+                              (unsigned long long) port->mapbase);
+                       return -ENOMEM;
+               }
+#endif
+       } else if (!strncmp(options, "io,", 3)) {
+               port->iotype = UPIO_PORT;
+               port->iobase = simple_strtoul(options + 3, &options, 0);
+               mmio = 0;
+       } else
+               return -EINVAL;
+
+       options = strchr(options, ',');
+       if (options) {
+               options++;
+               device->baud = simple_strtoul(options, NULL, 0);
+               length = min(strcspn(options, " "), sizeof(device->options));
+               strncpy(device->options, options, length);
+       } else {
+               device->baud = probe_baud(port);
+               snprintf(device->options, sizeof(device->options), "%u",
+                       device->baud);
+       }
+
+       if (mmio || mmio32)
+               printk(KERN_INFO
+                      "Early serial console at MMIO%s 0x%llx (options '%s')\n",
+                       mmio32 ? "32" : "",
+                       (unsigned long long)port->mapbase,
+                       device->options);
+       else
+               printk(KERN_INFO
+                     "Early serial console at I/O port 0x%lx (options '%s')\n",
+                       port->iobase,
+                       device->options);
+
+       return 0;
+}
+
+static struct console early_serial8250_console __initdata = {
+       .name   = "uart",
+       .write  = early_serial8250_write,
+       .flags  = CON_PRINTBUFFER | CON_BOOT,
+       .index  = -1,
+};
+
+static int __init early_serial8250_setup(char *options)
+{
+       struct early_serial8250_device *device = &early_device;
+       int err;
+
+       if (device->port.membase || device->port.iobase)
+               return 0;
+
+       err = parse_options(device, options);
+       if (err < 0)
+               return err;
+
+       init_port(device);
+       return 0;
+}
+
+int __init setup_early_serial8250_console(char *cmdline)
+{
+       char *options;
+       int err;
+
+       options = strstr(cmdline, "uart8250,");
+       if (!options) {
+               options = strstr(cmdline, "uart,");
+               if (!options)
+                       return 0;
+       }
+
+       options = strchr(cmdline, ',') + 1;
+       err = early_serial8250_setup(options);
+       if (err < 0)
+               return err;
+
+       register_console(&early_serial8250_console);
+
+       return 0;
+}
+
+int serial8250_find_port_for_earlycon(void)
+{
+       struct early_serial8250_device *device = &early_device;
+       struct uart_port *port = &device->port;
+       int line;
+       int ret;
+
+       if (!device->port.membase && !device->port.iobase)
+               return -ENODEV;
+
+       line = serial8250_find_port(port);
+       if (line < 0)
+               return -ENODEV;
+
+       ret = update_console_cmdline("uart", 8250,
+                            "ttyS", line, device->options);
+       if (ret < 0)
+               ret = update_console_cmdline("uart", 0,
+                                    "ttyS", line, device->options);
+
+       return ret;
+}
+
+early_param("earlycon", setup_early_serial8250_console);
diff --git a/drivers/tty/serial/8250_exar_st16c554.c b/drivers/tty/serial/8250_exar_st16c554.c
new file mode 100644 (file)
index 0000000..567143a
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ *  linux/drivers/serial/8250_exar.c
+ *
+ *  Written by Paul B Schroeder < pschroeder "at" uplogix "dot" com >
+ *  Based on 8250_boca.
+ *
+ *  Copyright (C) 2005 Russell King.
+ *  Data taken from include/asm-i386/serial.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/serial_8250.h>
+
+#define PORT(_base,_irq)                               \
+       {                                               \
+               .iobase         = _base,                \
+               .irq            = _irq,                 \
+               .uartclk        = 1843200,              \
+               .iotype         = UPIO_PORT,            \
+               .flags          = UPF_BOOT_AUTOCONF,    \
+       }
+
+static struct plat_serial8250_port exar_data[] = {
+       PORT(0x100, 5),
+       PORT(0x108, 5),
+       PORT(0x110, 5),
+       PORT(0x118, 5),
+       { },
+};
+
+static struct platform_device exar_device = {
+       .name                   = "serial8250",
+       .id                     = PLAT8250_DEV_EXAR_ST16C554,
+       .dev                    = {
+               .platform_data  = exar_data,
+       },
+};
+
+static int __init exar_init(void)
+{
+       return platform_device_register(&exar_device);
+}
+
+module_init(exar_init);
+
+MODULE_AUTHOR("Paul B Schroeder");
+MODULE_DESCRIPTION("8250 serial probe module for Exar cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250_fourport.c b/drivers/tty/serial/8250_fourport.c
new file mode 100644 (file)
index 0000000..6375d68
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *  linux/drivers/serial/8250_fourport.c
+ *
+ *  Copyright (C) 2005 Russell King.
+ *  Data taken from include/asm-i386/serial.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/serial_8250.h>
+
+#define PORT(_base,_irq)                                               \
+       {                                                               \
+               .iobase         = _base,                                \
+               .irq            = _irq,                                 \
+               .uartclk        = 1843200,                              \
+               .iotype         = UPIO_PORT,                            \
+               .flags          = UPF_BOOT_AUTOCONF | UPF_FOURPORT,     \
+       }
+
+static struct plat_serial8250_port fourport_data[] = {
+       PORT(0x1a0, 9),
+       PORT(0x1a8, 9),
+       PORT(0x1b0, 9),
+       PORT(0x1b8, 9),
+       PORT(0x2a0, 5),
+       PORT(0x2a8, 5),
+       PORT(0x2b0, 5),
+       PORT(0x2b8, 5),
+       { },
+};
+
+static struct platform_device fourport_device = {
+       .name                   = "serial8250",
+       .id                     = PLAT8250_DEV_FOURPORT,
+       .dev                    = {
+               .platform_data  = fourport_data,
+       },
+};
+
+static int __init fourport_init(void)
+{
+       return platform_device_register(&fourport_device);
+}
+
+module_init(fourport_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("8250 serial probe module for AST Fourport cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250_gsc.c b/drivers/tty/serial/8250_gsc.c
new file mode 100644 (file)
index 0000000..d8c0ffb
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ *     Serial Device Initialisation for Lasi/Asp/Wax/Dino
+ *
+ *     (c) Copyright Matthew Wilcox <willy@debian.org> 2001-2002
+ *
+ *     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.
+ */
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/serial_core.h>
+#include <linux/signal.h>
+#include <linux/types.h>
+
+#include <asm/hardware.h>
+#include <asm/parisc-device.h>
+#include <asm/io.h>
+
+#include "8250.h"
+
+static int __init serial_init_chip(struct parisc_device *dev)
+{
+       struct uart_port port;
+       unsigned long address;
+       int err;
+
+       if (!dev->irq) {
+               /* We find some unattached serial ports by walking native
+                * busses.  These should be silently ignored.  Otherwise,
+                * what we have here is a missing parent device, so tell
+                * the user what they're missing.
+                */
+               if (parisc_parent(dev)->id.hw_type != HPHW_IOA)
+                       printk(KERN_INFO
+                               "Serial: device 0x%llx not configured.\n"
+                               "Enable support for Wax, Lasi, Asp or Dino.\n",
+                               (unsigned long long)dev->hpa.start);
+               return -ENODEV;
+       }
+
+       address = dev->hpa.start;
+       if (dev->id.sversion != 0x8d)
+               address += 0x800;
+
+       memset(&port, 0, sizeof(port));
+       port.iotype     = UPIO_MEM;
+       /* 7.272727MHz on Lasi.  Assumed the same for Dino, Wax and Timi. */
+       port.uartclk    = 7272727;
+       port.mapbase    = address;
+       port.membase    = ioremap_nocache(address, 16);
+       port.irq        = dev->irq;
+       port.flags      = UPF_BOOT_AUTOCONF;
+       port.dev        = &dev->dev;
+
+       err = serial8250_register_port(&port);
+       if (err < 0) {
+               printk(KERN_WARNING
+                       "serial8250_register_port returned error %d\n", err);
+               iounmap(port.membase);
+               return err;
+       }
+
+       return 0;
+}
+
+static struct parisc_device_id serial_tbl[] = {
+       { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00075 },
+       { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008c },
+       { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008d },
+       { 0 }
+};
+
+/* Hack.  Some machines have SERIAL_0 attached to Lasi and SERIAL_1
+ * attached to Dino.  Unfortunately, Dino appears before Lasi in the device
+ * tree.  To ensure that ttyS0 == SERIAL_0, we register two drivers; one
+ * which only knows about Lasi and then a second which will find all the
+ * other serial ports.  HPUX ignores this problem.
+ */
+static struct parisc_device_id lasi_tbl[] = {
+       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03B, 0x0008C }, /* C1xx/C1xxL */
+       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03C, 0x0008C }, /* B132L */
+       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03D, 0x0008C }, /* B160L */
+       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03E, 0x0008C }, /* B132L+ */
+       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03F, 0x0008C }, /* B180L+ */
+       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x046, 0x0008C }, /* Rocky2 120 */
+       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x047, 0x0008C }, /* Rocky2 150 */
+       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x04E, 0x0008C }, /* Kiji L2 132 */
+       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x056, 0x0008C }, /* Raven+ */
+       { 0 }
+};
+
+
+MODULE_DEVICE_TABLE(parisc, serial_tbl);
+
+static struct parisc_driver lasi_driver = {
+       .name           = "serial_1",
+       .id_table       = lasi_tbl,
+       .probe          = serial_init_chip,
+};
+
+static struct parisc_driver serial_driver = {
+       .name           = "serial",
+       .id_table       = serial_tbl,
+       .probe          = serial_init_chip,
+};
+
+static int __init probe_serial_gsc(void)
+{
+       register_parisc_driver(&lasi_driver);
+       register_parisc_driver(&serial_driver);
+       return 0;
+}
+
+module_init(probe_serial_gsc);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250_hp300.c b/drivers/tty/serial/8250_hp300.c
new file mode 100644 (file)
index 0000000..c13438c
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * Driver for the 98626/98644/internal serial interface on hp300/hp400
+ * (based on the National Semiconductor INS8250/NS16550AF/WD16C552 UARTs)
+ *
+ * Ported from 2.2 and modified to use the normal 8250 driver
+ * by Kars de Jong <jongk@linux-m68k.org>, May 2004.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+#include <linux/delay.h>
+#include <linux/dio.h>
+#include <linux/console.h>
+#include <linux/slab.h>
+#include <asm/io.h>
+
+#include "8250.h"
+
+#if !defined(CONFIG_HPDCA) && !defined(CONFIG_HPAPCI)
+#warning CONFIG_8250 defined but neither CONFIG_HPDCA nor CONFIG_HPAPCI defined, are you sure?
+#endif
+
+#ifdef CONFIG_HPAPCI
+struct hp300_port
+{
+       struct hp300_port *next;        /* next port */
+       int line;                       /* line (tty) number */
+};
+
+static struct hp300_port *hp300_ports;
+#endif
+
+#ifdef CONFIG_HPDCA
+
+static int __devinit hpdca_init_one(struct dio_dev *d,
+                                       const struct dio_device_id *ent);
+static void __devexit hpdca_remove_one(struct dio_dev *d);
+
+static struct dio_device_id hpdca_dio_tbl[] = {
+       { DIO_ID_DCA0 },
+       { DIO_ID_DCA0REM },
+       { DIO_ID_DCA1 },
+       { DIO_ID_DCA1REM },
+       { 0 }
+};
+
+static struct dio_driver hpdca_driver = {
+       .name      = "hpdca",
+       .id_table  = hpdca_dio_tbl,
+       .probe     = hpdca_init_one,
+       .remove    = __devexit_p(hpdca_remove_one),
+};
+
+#endif
+
+static unsigned int num_ports;
+
+extern int hp300_uart_scode;
+
+/* Offset to UART registers from base of DCA */
+#define UART_OFFSET    17
+
+#define DCA_ID         0x01    /* ID (read), reset (write) */
+#define DCA_IC         0x03    /* Interrupt control        */
+
+/* Interrupt control */
+#define DCA_IC_IE      0x80    /* Master interrupt enable  */
+
+#define HPDCA_BAUD_BASE 153600
+
+/* Base address of the Frodo part */
+#define FRODO_BASE     (0x41c000)
+
+/*
+ * Where we find the 8250-like APCI ports, and how far apart they are.
+ */
+#define FRODO_APCIBASE         0x0
+#define FRODO_APCISPACE                0x20
+#define FRODO_APCI_OFFSET(x)   (FRODO_APCIBASE + ((x) * FRODO_APCISPACE))
+
+#define HPAPCI_BAUD_BASE 500400
+
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+/*
+ * Parse the bootinfo to find descriptions for headless console and
+ * debug serial ports and register them with the 8250 driver.
+ * This function should be called before serial_console_init() is called
+ * to make sure the serial console will be available for use. IA-64 kernel
+ * calls this function from setup_arch() after the EFI and ACPI tables have
+ * been parsed.
+ */
+int __init hp300_setup_serial_console(void)
+{
+       int scode;
+       struct uart_port port;
+
+       memset(&port, 0, sizeof(port));
+
+       if (hp300_uart_scode < 0 || hp300_uart_scode > DIO_SCMAX)
+               return 0;
+
+       if (DIO_SCINHOLE(hp300_uart_scode))
+               return 0;
+
+       scode = hp300_uart_scode;
+
+       /* Memory mapped I/O */
+       port.iotype = UPIO_MEM;
+       port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF;
+       port.type = PORT_UNKNOWN;
+
+       /* Check for APCI console */
+       if (scode == 256) {
+#ifdef CONFIG_HPAPCI
+               printk(KERN_INFO "Serial console is HP APCI 1\n");
+
+               port.uartclk = HPAPCI_BAUD_BASE * 16;
+               port.mapbase = (FRODO_BASE + FRODO_APCI_OFFSET(1));
+               port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE);
+               port.regshift = 2;
+               add_preferred_console("ttyS", port.line, "9600n8");
+#else
+               printk(KERN_WARNING "Serial console is APCI but support is disabled (CONFIG_HPAPCI)!\n");
+               return 0;
+#endif
+       } else {
+#ifdef CONFIG_HPDCA
+               unsigned long pa = dio_scodetophysaddr(scode);
+               if (!pa)
+                       return 0;
+
+               printk(KERN_INFO "Serial console is HP DCA at select code %d\n", scode);
+
+               port.uartclk = HPDCA_BAUD_BASE * 16;
+               port.mapbase = (pa + UART_OFFSET);
+               port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE);
+               port.regshift = 1;
+               port.irq = DIO_IPL(pa + DIO_VIRADDRBASE);
+
+               /* Enable board-interrupts */
+               out_8(pa + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE);
+
+               if (DIO_ID(pa + DIO_VIRADDRBASE) & 0x80)
+                       add_preferred_console("ttyS", port.line, "9600n8");
+#else
+               printk(KERN_WARNING "Serial console is DCA but support is disabled (CONFIG_HPDCA)!\n");
+               return 0;
+#endif
+       }
+
+       if (early_serial_setup(&port) < 0)
+               printk(KERN_WARNING "hp300_setup_serial_console(): early_serial_setup() failed.\n");
+       return 0;
+}
+#endif /* CONFIG_SERIAL_8250_CONSOLE */
+
+#ifdef CONFIG_HPDCA
+static int __devinit hpdca_init_one(struct dio_dev *d,
+                               const struct dio_device_id *ent)
+{
+       struct uart_port port;
+       int line;
+
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+       if (hp300_uart_scode == d->scode) {
+               /* Already got it. */
+               return 0;
+       }
+#endif
+       memset(&port, 0, sizeof(struct uart_port));
+
+       /* Memory mapped I/O */
+       port.iotype = UPIO_MEM;
+       port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF;
+       port.irq = d->ipl;
+       port.uartclk = HPDCA_BAUD_BASE * 16;
+       port.mapbase = (d->resource.start + UART_OFFSET);
+       port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE);
+       port.regshift = 1;
+       port.dev = &d->dev;
+       line = serial8250_register_port(&port);
+
+       if (line < 0) {
+               printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d"
+                      " irq %d failed\n", d->scode, port.irq);
+               return -ENOMEM;
+       }
+
+       /* Enable board-interrupts */
+       out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE);
+       dio_set_drvdata(d, (void *)line);
+
+       /* Reset the DCA */
+       out_8(d->resource.start + DIO_VIRADDRBASE + DCA_ID, 0xff);
+       udelay(100);
+
+       num_ports++;
+
+       return 0;
+}
+#endif
+
+static int __init hp300_8250_init(void)
+{
+       static int called;
+#ifdef CONFIG_HPAPCI
+       int line;
+       unsigned long base;
+       struct uart_port uport;
+       struct hp300_port *port;
+       int i;
+#endif
+       if (called)
+               return -ENODEV;
+       called = 1;
+
+       if (!MACH_IS_HP300)
+               return -ENODEV;
+
+#ifdef CONFIG_HPDCA
+       dio_register_driver(&hpdca_driver);
+#endif
+#ifdef CONFIG_HPAPCI
+       if (hp300_model < HP_400) {
+               if (!num_ports)
+                       return -ENODEV;
+               return 0;
+       }
+       /* These models have the Frodo chip.
+        * Port 0 is reserved for the Apollo Domain keyboard.
+        * Port 1 is either the console or the DCA.
+        */
+       for (i = 1; i < 4; i++) {
+               /* Port 1 is the console on a 425e, on other machines it's
+                * mapped to DCA.
+                */
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+               if (i == 1)
+                       continue;
+#endif
+
+               /* Create new serial device */
+               port = kmalloc(sizeof(struct hp300_port), GFP_KERNEL);
+               if (!port)
+                       return -ENOMEM;
+
+               memset(&uport, 0, sizeof(struct uart_port));
+
+               base = (FRODO_BASE + FRODO_APCI_OFFSET(i));
+
+               /* Memory mapped I/O */
+               uport.iotype = UPIO_MEM;
+               uport.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ \
+                             | UPF_BOOT_AUTOCONF;
+               /* XXX - no interrupt support yet */
+               uport.irq = 0;
+               uport.uartclk = HPAPCI_BAUD_BASE * 16;
+               uport.mapbase = base;
+               uport.membase = (char *)(base + DIO_VIRADDRBASE);
+               uport.regshift = 2;
+
+               line = serial8250_register_port(&uport);
+
+               if (line < 0) {
+                       printk(KERN_NOTICE "8250_hp300: register_serial() APCI"
+                              " %d irq %d failed\n", i, uport.irq);
+                       kfree(port);
+                       continue;
+               }
+
+               port->line = line;
+               port->next = hp300_ports;
+               hp300_ports = port;
+
+               num_ports++;
+       }
+#endif
+
+       /* Any boards found? */
+       if (!num_ports)
+               return -ENODEV;
+
+       return 0;
+}
+
+#ifdef CONFIG_HPDCA
+static void __devexit hpdca_remove_one(struct dio_dev *d)
+{
+       int line;
+
+       line = (int) dio_get_drvdata(d);
+       if (d->resource.start) {
+               /* Disable board-interrupts */
+               out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, 0);
+       }
+       serial8250_unregister_port(line);
+}
+#endif
+
+static void __exit hp300_8250_exit(void)
+{
+#ifdef CONFIG_HPAPCI
+       struct hp300_port *port, *to_free;
+
+       for (port = hp300_ports; port; ) {
+               serial8250_unregister_port(port->line);
+               to_free = port;
+               port = port->next;
+               kfree(to_free);
+       }
+
+       hp300_ports = NULL;
+#endif
+#ifdef CONFIG_HPDCA
+       dio_unregister_driver(&hpdca_driver);
+#endif
+}
+
+module_init(hp300_8250_init);
+module_exit(hp300_8250_exit);
+MODULE_DESCRIPTION("HP DCA/APCI serial driver");
+MODULE_AUTHOR("Kars de Jong <jongk@linux-m68k.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250_hub6.c b/drivers/tty/serial/8250_hub6.c
new file mode 100644 (file)
index 0000000..7609150
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ *  linux/drivers/serial/8250_hub6.c
+ *
+ *  Copyright (C) 2005 Russell King.
+ *  Data taken from include/asm-i386/serial.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/serial_8250.h>
+
+#define HUB6(card,port)                                                        \
+       {                                                               \
+               .iobase         = 0x302,                                \
+               .irq            = 3,                                    \
+               .uartclk        = 1843200,                              \
+               .iotype         = UPIO_HUB6,                            \
+               .flags          = UPF_BOOT_AUTOCONF,                    \
+               .hub6           = (card) << 6 | (port) << 3 | 1,        \
+       }
+
+static struct plat_serial8250_port hub6_data[] = {
+       HUB6(0, 0),
+       HUB6(0, 1),
+       HUB6(0, 2),
+       HUB6(0, 3),
+       HUB6(0, 4),
+       HUB6(0, 5),
+       HUB6(1, 0),
+       HUB6(1, 1),
+       HUB6(1, 2),
+       HUB6(1, 3),
+       HUB6(1, 4),
+       HUB6(1, 5),
+       { },
+};
+
+static struct platform_device hub6_device = {
+       .name                   = "serial8250",
+       .id                     = PLAT8250_DEV_HUB6,
+       .dev                    = {
+               .platform_data  = hub6_data,
+       },
+};
+
+static int __init hub6_init(void)
+{
+       return platform_device_register(&hub6_device);
+}
+
+module_init(hub6_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("8250 serial probe module for Hub6 cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250_mca.c b/drivers/tty/serial/8250_mca.c
new file mode 100644 (file)
index 0000000..d10be94
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *  linux/drivers/serial/8250_mca.c
+ *
+ *  Copyright (C) 2005 Russell King.
+ *  Data taken from include/asm-i386/serial.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mca.h>
+#include <linux/serial_8250.h>
+
+/*
+ * FIXME: Should we be doing AUTO_IRQ here?
+ */
+#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
+#define MCA_FLAGS      UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ
+#else
+#define MCA_FLAGS      UPF_BOOT_AUTOCONF | UPF_SKIP_TEST
+#endif
+
+#define PORT(_base,_irq)                       \
+       {                                       \
+               .iobase         = _base,        \
+               .irq            = _irq,         \
+               .uartclk        = 1843200,      \
+               .iotype         = UPIO_PORT,    \
+               .flags          = MCA_FLAGS,    \
+       }
+
+static struct plat_serial8250_port mca_data[] = {
+       PORT(0x3220, 3),
+       PORT(0x3228, 3),
+       PORT(0x4220, 3),
+       PORT(0x4228, 3),
+       PORT(0x5220, 3),
+       PORT(0x5228, 3),
+       { },
+};
+
+static struct platform_device mca_device = {
+       .name                   = "serial8250",
+       .id                     = PLAT8250_DEV_MCA,
+       .dev                    = {
+               .platform_data  = mca_data,
+       },
+};
+
+static int __init mca_init(void)
+{
+       if (!MCA_bus)
+               return -ENODEV;
+       return platform_device_register(&mca_device);
+}
+
+module_init(mca_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("8250 serial probe module for MCA ports");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250_pci.c b/drivers/tty/serial/8250_pci.c
new file mode 100644 (file)
index 0000000..8b8930f
--- /dev/null
@@ -0,0 +1,3850 @@
+/*
+ *  linux/drivers/char/8250_pci.c
+ *
+ *  Probe module for 8250/16550-type PCI serial ports.
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ *  Copyright (C) 2001 Russell King, 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.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/serial_core.h>
+#include <linux/8250_pci.h>
+#include <linux/bitops.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+
+#include "8250.h"
+
+#undef SERIAL_DEBUG_PCI
+
+/*
+ * init function returns:
+ *  > 0 - number of ports
+ *  = 0 - use board->num_ports
+ *  < 0 - error
+ */
+struct pci_serial_quirk {
+       u32     vendor;
+       u32     device;
+       u32     subvendor;
+       u32     subdevice;
+       int     (*init)(struct pci_dev *dev);
+       int     (*setup)(struct serial_private *,
+                        const struct pciserial_board *,
+                        struct uart_port *, int);
+       void    (*exit)(struct pci_dev *dev);
+};
+
+#define PCI_NUM_BAR_RESOURCES  6
+
+struct serial_private {
+       struct pci_dev          *dev;
+       unsigned int            nr;
+       void __iomem            *remapped_bar[PCI_NUM_BAR_RESOURCES];
+       struct pci_serial_quirk *quirk;
+       int                     line[0];
+};
+
+static void moan_device(const char *str, struct pci_dev *dev)
+{
+       printk(KERN_WARNING
+              "%s: %s\n"
+              "Please send the output of lspci -vv, this\n"
+              "message (0x%04x,0x%04x,0x%04x,0x%04x), the\n"
+              "manufacturer and name of serial board or\n"
+              "modem board to rmk+serial@arm.linux.org.uk.\n",
+              pci_name(dev), str, dev->vendor, dev->device,
+              dev->subsystem_vendor, dev->subsystem_device);
+}
+
+static int
+setup_port(struct serial_private *priv, struct uart_port *port,
+          int bar, int offset, int regshift)
+{
+       struct pci_dev *dev = priv->dev;
+       unsigned long base, len;
+
+       if (bar >= PCI_NUM_BAR_RESOURCES)
+               return -EINVAL;
+
+       base = pci_resource_start(dev, bar);
+
+       if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) {
+               len =  pci_resource_len(dev, bar);
+
+               if (!priv->remapped_bar[bar])
+                       priv->remapped_bar[bar] = ioremap_nocache(base, len);
+               if (!priv->remapped_bar[bar])
+                       return -ENOMEM;
+
+               port->iotype = UPIO_MEM;
+               port->iobase = 0;
+               port->mapbase = base + offset;
+               port->membase = priv->remapped_bar[bar] + offset;
+               port->regshift = regshift;
+       } else {
+               port->iotype = UPIO_PORT;
+               port->iobase = base + offset;
+               port->mapbase = 0;
+               port->membase = NULL;
+               port->regshift = 0;
+       }
+       return 0;
+}
+
+/*
+ * ADDI-DATA GmbH communication cards <info@addi-data.com>
+ */
+static int addidata_apci7800_setup(struct serial_private *priv,
+                               const struct pciserial_board *board,
+                               struct uart_port *port, int idx)
+{
+       unsigned int bar = 0, offset = board->first_offset;
+       bar = FL_GET_BASE(board->flags);
+
+       if (idx < 2) {
+               offset += idx * board->uart_offset;
+       } else if ((idx >= 2) && (idx < 4)) {
+               bar += 1;
+               offset += ((idx - 2) * board->uart_offset);
+       } else if ((idx >= 4) && (idx < 6)) {
+               bar += 2;
+               offset += ((idx - 4) * board->uart_offset);
+       } else if (idx >= 6) {
+               bar += 3;
+               offset += ((idx - 6) * board->uart_offset);
+       }
+
+       return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+/*
+ * AFAVLAB uses a different mixture of BARs and offsets
+ * Not that ugly ;) -- HW
+ */
+static int
+afavlab_setup(struct serial_private *priv, const struct pciserial_board *board,
+             struct uart_port *port, int idx)
+{
+       unsigned int bar, offset = board->first_offset;
+
+       bar = FL_GET_BASE(board->flags);
+       if (idx < 4)
+               bar += idx;
+       else {
+               bar = 4;
+               offset += (idx - 4) * board->uart_offset;
+       }
+
+       return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+/*
+ * HP's Remote Management Console.  The Diva chip came in several
+ * different versions.  N-class, L2000 and A500 have two Diva chips, each
+ * with 3 UARTs (the third UART on the second chip is unused).  Superdome
+ * and Keystone have one Diva chip with 3 UARTs.  Some later machines have
+ * one Diva chip, but it has been expanded to 5 UARTs.
+ */
+static int pci_hp_diva_init(struct pci_dev *dev)
+{
+       int rc = 0;
+
+       switch (dev->subsystem_device) {
+       case PCI_DEVICE_ID_HP_DIVA_TOSCA1:
+       case PCI_DEVICE_ID_HP_DIVA_HALFDOME:
+       case PCI_DEVICE_ID_HP_DIVA_KEYSTONE:
+       case PCI_DEVICE_ID_HP_DIVA_EVEREST:
+               rc = 3;
+               break;
+       case PCI_DEVICE_ID_HP_DIVA_TOSCA2:
+               rc = 2;
+               break;
+       case PCI_DEVICE_ID_HP_DIVA_MAESTRO:
+               rc = 4;
+               break;
+       case PCI_DEVICE_ID_HP_DIVA_POWERBAR:
+       case PCI_DEVICE_ID_HP_DIVA_HURRICANE:
+               rc = 1;
+               break;
+       }
+
+       return rc;
+}
+
+/*
+ * HP's Diva chip puts the 4th/5th serial port further out, and
+ * some serial ports are supposed to be hidden on certain models.
+ */
+static int
+pci_hp_diva_setup(struct serial_private *priv,
+               const struct pciserial_board *board,
+               struct uart_port *port, int idx)
+{
+       unsigned int offset = board->first_offset;
+       unsigned int bar = FL_GET_BASE(board->flags);
+
+       switch (priv->dev->subsystem_device) {
+       case PCI_DEVICE_ID_HP_DIVA_MAESTRO:
+               if (idx == 3)
+                       idx++;
+               break;
+       case PCI_DEVICE_ID_HP_DIVA_EVEREST:
+               if (idx > 0)
+                       idx++;
+               if (idx > 2)
+                       idx++;
+               break;
+       }
+       if (idx > 2)
+               offset = 0x18;
+
+       offset += idx * board->uart_offset;
+
+       return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+/*
+ * Added for EKF Intel i960 serial boards
+ */
+static int pci_inteli960ni_init(struct pci_dev *dev)
+{
+       unsigned long oldval;
+
+       if (!(dev->subsystem_device & 0x1000))
+               return -ENODEV;
+
+       /* is firmware started? */
+       pci_read_config_dword(dev, 0x44, (void *)&oldval);
+       if (oldval == 0x00001000L) { /* RESET value */
+               printk(KERN_DEBUG "Local i960 firmware missing");
+               return -ENODEV;
+       }
+       return 0;
+}
+
+/*
+ * Some PCI serial cards using the PLX 9050 PCI interface chip require
+ * that the card interrupt be explicitly enabled or disabled.  This
+ * seems to be mainly needed on card using the PLX which also use I/O
+ * mapped memory.
+ */
+static int pci_plx9050_init(struct pci_dev *dev)
+{
+       u8 irq_config;
+       void __iomem *p;
+
+       if ((pci_resource_flags(dev, 0) & IORESOURCE_MEM) == 0) {
+               moan_device("no memory in bar 0", dev);
+               return 0;
+       }
+
+       irq_config = 0x41;
+       if (dev->vendor == PCI_VENDOR_ID_PANACOM ||
+           dev->subsystem_vendor == PCI_SUBVENDOR_ID_EXSYS)
+               irq_config = 0x43;
+
+       if ((dev->vendor == PCI_VENDOR_ID_PLX) &&
+           (dev->device == PCI_DEVICE_ID_PLX_ROMULUS))
+               /*
+                * As the megawolf cards have the int pins active
+                * high, and have 2 UART chips, both ints must be
+                * enabled on the 9050. Also, the UARTS are set in
+                * 16450 mode by default, so we have to enable the
+                * 16C950 'enhanced' mode so that we can use the
+                * deep FIFOs
+                */
+               irq_config = 0x5b;
+       /*
+        * enable/disable interrupts
+        */
+       p = ioremap_nocache(pci_resource_start(dev, 0), 0x80);
+       if (p == NULL)
+               return -ENOMEM;
+       writel(irq_config, p + 0x4c);
+
+       /*
+        * Read the register back to ensure that it took effect.
+        */
+       readl(p + 0x4c);
+       iounmap(p);
+
+       return 0;
+}
+
+static void __devexit pci_plx9050_exit(struct pci_dev *dev)
+{
+       u8 __iomem *p;
+
+       if ((pci_resource_flags(dev, 0) & IORESOURCE_MEM) == 0)
+               return;
+
+       /*
+        * disable interrupts
+        */
+       p = ioremap_nocache(pci_resource_start(dev, 0), 0x80);
+       if (p != NULL) {
+               writel(0, p + 0x4c);
+
+               /*
+                * Read the register back to ensure that it took effect.
+                */
+               readl(p + 0x4c);
+               iounmap(p);
+       }
+}
+
+#define NI8420_INT_ENABLE_REG  0x38
+#define NI8420_INT_ENABLE_BIT  0x2000
+
+static void __devexit pci_ni8420_exit(struct pci_dev *dev)
+{
+       void __iomem *p;
+       unsigned long base, len;
+       unsigned int bar = 0;
+
+       if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) {
+               moan_device("no memory in bar", dev);
+               return;
+       }
+
+       base = pci_resource_start(dev, bar);
+       len =  pci_resource_len(dev, bar);
+       p = ioremap_nocache(base, len);
+       if (p == NULL)
+               return;
+
+       /* Disable the CPU Interrupt */
+       writel(readl(p + NI8420_INT_ENABLE_REG) & ~(NI8420_INT_ENABLE_BIT),
+              p + NI8420_INT_ENABLE_REG);
+       iounmap(p);
+}
+
+
+/* MITE registers */
+#define MITE_IOWBSR1   0xc4
+#define MITE_IOWCR1    0xf4
+#define MITE_LCIMR1    0x08
+#define MITE_LCIMR2    0x10
+
+#define MITE_LCIMR2_CLR_CPU_IE (1 << 30)
+
+static void __devexit pci_ni8430_exit(struct pci_dev *dev)
+{
+       void __iomem *p;
+       unsigned long base, len;
+       unsigned int bar = 0;
+
+       if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) {
+               moan_device("no memory in bar", dev);
+               return;
+       }
+
+       base = pci_resource_start(dev, bar);
+       len =  pci_resource_len(dev, bar);
+       p = ioremap_nocache(base, len);
+       if (p == NULL)
+               return;
+
+       /* Disable the CPU Interrupt */
+       writel(MITE_LCIMR2_CLR_CPU_IE, p + MITE_LCIMR2);
+       iounmap(p);
+}
+
+/* SBS Technologies Inc. PMC-OCTPRO and P-OCTAL cards */
+static int
+sbs_setup(struct serial_private *priv, const struct pciserial_board *board,
+               struct uart_port *port, int idx)
+{
+       unsigned int bar, offset = board->first_offset;
+
+       bar = 0;
+
+       if (idx < 4) {
+               /* first four channels map to 0, 0x100, 0x200, 0x300 */
+               offset += idx * board->uart_offset;
+       } else if (idx < 8) {
+               /* last four channels map to 0x1000, 0x1100, 0x1200, 0x1300 */
+               offset += idx * board->uart_offset + 0xC00;
+       } else /* we have only 8 ports on PMC-OCTALPRO */
+               return 1;
+
+       return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+/*
+* This does initialization for PMC OCTALPRO cards:
+* maps the device memory, resets the UARTs (needed, bc
+* if the module is removed and inserted again, the card
+* is in the sleep mode) and enables global interrupt.
+*/
+
+/* global control register offset for SBS PMC-OctalPro */
+#define OCT_REG_CR_OFF         0x500
+
+static int sbs_init(struct pci_dev *dev)
+{
+       u8 __iomem *p;
+
+       p = pci_ioremap_bar(dev, 0);
+
+       if (p == NULL)
+               return -ENOMEM;
+       /* Set bit-4 Control Register (UART RESET) in to reset the uarts */
+       writeb(0x10, p + OCT_REG_CR_OFF);
+       udelay(50);
+       writeb(0x0, p + OCT_REG_CR_OFF);
+
+       /* Set bit-2 (INTENABLE) of Control Register */
+       writeb(0x4, p + OCT_REG_CR_OFF);
+       iounmap(p);
+
+       return 0;
+}
+
+/*
+ * Disables the global interrupt of PMC-OctalPro
+ */
+
+static void __devexit sbs_exit(struct pci_dev *dev)
+{
+       u8 __iomem *p;
+
+       p = pci_ioremap_bar(dev, 0);
+       /* FIXME: What if resource_len < OCT_REG_CR_OFF */
+       if (p != NULL)
+               writeb(0, p + OCT_REG_CR_OFF);
+       iounmap(p);
+}
+
+/*
+ * SIIG serial cards have an PCI interface chip which also controls
+ * the UART clocking frequency. Each UART can be clocked independently
+ * (except cards equiped with 4 UARTs) and initial clocking settings
+ * are stored in the EEPROM chip. It can cause problems because this
+ * version of serial driver doesn't support differently clocked UART's
+ * on single PCI card. To prevent this, initialization functions set
+ * high frequency clocking for all UART's on given card. It is safe (I
+ * hope) because it doesn't touch EEPROM settings to prevent conflicts
+ * with other OSes (like M$ DOS).
+ *
+ *  SIIG support added by Andrey Panin <pazke@donpac.ru>, 10/1999
+ *
+ * There is two family of SIIG serial cards with different PCI
+ * interface chip and different configuration methods:
+ *     - 10x cards have control registers in IO and/or memory space;
+ *     - 20x cards have control registers in standard PCI configuration space.
+ *
+ * Note: all 10x cards have PCI device ids 0x10..
+ *       all 20x cards have PCI device ids 0x20..
+ *
+ * There are also Quartet Serial cards which use Oxford Semiconductor
+ * 16954 quad UART PCI chip clocked by 18.432 MHz quartz.
+ *
+ * Note: some SIIG cards are probed by the parport_serial object.
+ */
+
+#define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc)
+#define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8)
+
+static int pci_siig10x_init(struct pci_dev *dev)
+{
+       u16 data;
+       void __iomem *p;
+
+       switch (dev->device & 0xfff8) {
+       case PCI_DEVICE_ID_SIIG_1S_10x: /* 1S */
+               data = 0xffdf;
+               break;
+       case PCI_DEVICE_ID_SIIG_2S_10x: /* 2S, 2S1P */
+               data = 0xf7ff;
+               break;
+       default:                        /* 1S1P, 4S */
+               data = 0xfffb;
+               break;
+       }
+
+       p = ioremap_nocache(pci_resource_start(dev, 0), 0x80);
+       if (p == NULL)
+               return -ENOMEM;
+
+       writew(readw(p + 0x28) & data, p + 0x28);
+       readw(p + 0x28);
+       iounmap(p);
+       return 0;
+}
+
+#define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc)
+#define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc)
+
+static int pci_siig20x_init(struct pci_dev *dev)
+{
+       u8 data;
+
+       /* Change clock frequency for the first UART. */
+       pci_read_config_byte(dev, 0x6f, &data);
+       pci_write_config_byte(dev, 0x6f, data & 0xef);
+
+       /* If this card has 2 UART, we have to do the same with second UART. */
+       if (((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S_20x) ||
+           ((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S1P_20x)) {
+               pci_read_config_byte(dev, 0x73, &data);
+               pci_write_config_byte(dev, 0x73, data & 0xef);
+       }
+       return 0;
+}
+
+static int pci_siig_init(struct pci_dev *dev)
+{
+       unsigned int type = dev->device & 0xff00;
+
+       if (type == 0x1000)
+               return pci_siig10x_init(dev);
+       else if (type == 0x2000)
+               return pci_siig20x_init(dev);
+
+       moan_device("Unknown SIIG card", dev);
+       return -ENODEV;
+}
+
+static int pci_siig_setup(struct serial_private *priv,
+                         const struct pciserial_board *board,
+                         struct uart_port *port, int idx)
+{
+       unsigned int bar = FL_GET_BASE(board->flags) + idx, offset = 0;
+
+       if (idx > 3) {
+               bar = 4;
+               offset = (idx - 4) * 8;
+       }
+
+       return setup_port(priv, port, bar, offset, 0);
+}
+
+/*
+ * Timedia has an explosion of boards, and to avoid the PCI table from
+ * growing *huge*, we use this function to collapse some 70 entries
+ * in the PCI table into one, for sanity's and compactness's sake.
+ */
+static const unsigned short timedia_single_port[] = {
+       0x4025, 0x4027, 0x4028, 0x5025, 0x5027, 0
+};
+
+static const unsigned short timedia_dual_port[] = {
+       0x0002, 0x4036, 0x4037, 0x4038, 0x4078, 0x4079, 0x4085,
+       0x4088, 0x4089, 0x5037, 0x5078, 0x5079, 0x5085, 0x6079,
+       0x7079, 0x8079, 0x8137, 0x8138, 0x8237, 0x8238, 0x9079,
+       0x9137, 0x9138, 0x9237, 0x9238, 0xA079, 0xB079, 0xC079,
+       0xD079, 0
+};
+
+static const unsigned short timedia_quad_port[] = {
+       0x4055, 0x4056, 0x4095, 0x4096, 0x5056, 0x8156, 0x8157,
+       0x8256, 0x8257, 0x9056, 0x9156, 0x9157, 0x9158, 0x9159,
+       0x9256, 0x9257, 0xA056, 0xA157, 0xA158, 0xA159, 0xB056,
+       0xB157, 0
+};
+
+static const unsigned short timedia_eight_port[] = {
+       0x4065, 0x4066, 0x5065, 0x5066, 0x8166, 0x9066, 0x9166,
+       0x9167, 0x9168, 0xA066, 0xA167, 0xA168, 0
+};
+
+static const struct timedia_struct {
+       int num;
+       const unsigned short *ids;
+} timedia_data[] = {
+       { 1, timedia_single_port },
+       { 2, timedia_dual_port },
+       { 4, timedia_quad_port },
+       { 8, timedia_eight_port }
+};
+
+static int pci_timedia_init(struct pci_dev *dev)
+{
+       const unsigned short *ids;
+       int i, j;
+
+       for (i = 0; i < ARRAY_SIZE(timedia_data); i++) {
+               ids = timedia_data[i].ids;
+               for (j = 0; ids[j]; j++)
+                       if (dev->subsystem_device == ids[j])
+                               return timedia_data[i].num;
+       }
+       return 0;
+}
+
+/*
+ * Timedia/SUNIX uses a mixture of BARs and offsets
+ * Ugh, this is ugly as all hell --- TYT
+ */
+static int
+pci_timedia_setup(struct serial_private *priv,
+                 const struct pciserial_board *board,
+                 struct uart_port *port, int idx)
+{
+       unsigned int bar = 0, offset = board->first_offset;
+
+       switch (idx) {
+       case 0:
+               bar = 0;
+               break;
+       case 1:
+               offset = board->uart_offset;
+               bar = 0;
+               break;
+       case 2:
+               bar = 1;
+               break;
+       case 3:
+               offset = board->uart_offset;
+               /* FALLTHROUGH */
+       case 4: /* BAR 2 */
+       case 5: /* BAR 3 */
+       case 6: /* BAR 4 */
+       case 7: /* BAR 5 */
+               bar = idx - 2;
+       }
+
+       return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+/*
+ * Some Titan cards are also a little weird
+ */
+static int
+titan_400l_800l_setup(struct serial_private *priv,
+                     const struct pciserial_board *board,
+                     struct uart_port *port, int idx)
+{
+       unsigned int bar, offset = board->first_offset;
+
+       switch (idx) {
+       case 0:
+               bar = 1;
+               break;
+       case 1:
+               bar = 2;
+               break;
+       default:
+               bar = 4;
+               offset = (idx - 2) * board->uart_offset;
+       }
+
+       return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+static int pci_xircom_init(struct pci_dev *dev)
+{
+       msleep(100);
+       return 0;
+}
+
+static int pci_ni8420_init(struct pci_dev *dev)
+{
+       void __iomem *p;
+       unsigned long base, len;
+       unsigned int bar = 0;
+
+       if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) {
+               moan_device("no memory in bar", dev);
+               return 0;
+       }
+
+       base = pci_resource_start(dev, bar);
+       len =  pci_resource_len(dev, bar);
+       p = ioremap_nocache(base, len);
+       if (p == NULL)
+               return -ENOMEM;
+
+       /* Enable CPU Interrupt */
+       writel(readl(p + NI8420_INT_ENABLE_REG) | NI8420_INT_ENABLE_BIT,
+              p + NI8420_INT_ENABLE_REG);
+
+       iounmap(p);
+       return 0;
+}
+
+#define MITE_IOWBSR1_WSIZE     0xa
+#define MITE_IOWBSR1_WIN_OFFSET        0x800
+#define MITE_IOWBSR1_WENAB     (1 << 7)
+#define MITE_LCIMR1_IO_IE_0    (1 << 24)
+#define MITE_LCIMR2_SET_CPU_IE (1 << 31)
+#define MITE_IOWCR1_RAMSEL_MASK        0xfffffffe
+
+static int pci_ni8430_init(struct pci_dev *dev)
+{
+       void __iomem *p;
+       unsigned long base, len;
+       u32 device_window;
+       unsigned int bar = 0;
+
+       if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) {
+               moan_device("no memory in bar", dev);
+               return 0;
+       }
+
+       base = pci_resource_start(dev, bar);
+       len =  pci_resource_len(dev, bar);
+       p = ioremap_nocache(base, len);
+       if (p == NULL)
+               return -ENOMEM;
+
+       /* Set device window address and size in BAR0 */
+       device_window = ((base + MITE_IOWBSR1_WIN_OFFSET) & 0xffffff00)
+                       | MITE_IOWBSR1_WENAB | MITE_IOWBSR1_WSIZE;
+       writel(device_window, p + MITE_IOWBSR1);
+
+       /* Set window access to go to RAMSEL IO address space */
+       writel((readl(p + MITE_IOWCR1) & MITE_IOWCR1_RAMSEL_MASK),
+              p + MITE_IOWCR1);
+
+       /* Enable IO Bus Interrupt 0 */
+       writel(MITE_LCIMR1_IO_IE_0, p + MITE_LCIMR1);
+
+       /* Enable CPU Interrupt */
+       writel(MITE_LCIMR2_SET_CPU_IE, p + MITE_LCIMR2);
+
+       iounmap(p);
+       return 0;
+}
+
+/* UART Port Control Register */
+#define NI8430_PORTCON 0x0f
+#define NI8430_PORTCON_TXVR_ENABLE     (1 << 3)
+
+static int
+pci_ni8430_setup(struct serial_private *priv,
+                const struct pciserial_board *board,
+                struct uart_port *port, int idx)
+{
+       void __iomem *p;
+       unsigned long base, len;
+       unsigned int bar, offset = board->first_offset;
+
+       if (idx >= board->num_ports)
+               return 1;
+
+       bar = FL_GET_BASE(board->flags);
+       offset += idx * board->uart_offset;
+
+       base = pci_resource_start(priv->dev, bar);
+       len =  pci_resource_len(priv->dev, bar);
+       p = ioremap_nocache(base, len);
+
+       /* enable the transciever */
+       writeb(readb(p + offset + NI8430_PORTCON) | NI8430_PORTCON_TXVR_ENABLE,
+              p + offset + NI8430_PORTCON);
+
+       iounmap(p);
+
+       return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+
+static int pci_netmos_init(struct pci_dev *dev)
+{
+       /* subdevice 0x00PS means <P> parallel, <S> serial */
+       unsigned int num_serial = dev->subsystem_device & 0xf;
+
+       if ((dev->device == PCI_DEVICE_ID_NETMOS_9901) ||
+               (dev->device == PCI_DEVICE_ID_NETMOS_9865))
+               return 0;
+       if (dev->subsystem_vendor == PCI_VENDOR_ID_IBM &&
+                       dev->subsystem_device == 0x0299)
+               return 0;
+
+       if (num_serial == 0)
+               return -ENODEV;
+       return num_serial;
+}
+
+/*
+ * These chips are available with optionally one parallel port and up to
+ * two serial ports. Unfortunately they all have the same product id.
+ *
+ * Basic configuration is done over a region of 32 I/O ports. The base
+ * ioport is called INTA or INTC, depending on docs/other drivers.
+ *
+ * The region of the 32 I/O ports is configured in POSIO0R...
+ */
+
+/* registers */
+#define ITE_887x_MISCR         0x9c
+#define ITE_887x_INTCBAR       0x78
+#define ITE_887x_UARTBAR       0x7c
+#define ITE_887x_PS0BAR                0x10
+#define ITE_887x_POSIO0                0x60
+
+/* I/O space size */
+#define ITE_887x_IOSIZE                32
+/* I/O space size (bits 26-24; 8 bytes = 011b) */
+#define ITE_887x_POSIO_IOSIZE_8                (3 << 24)
+/* I/O space size (bits 26-24; 32 bytes = 101b) */
+#define ITE_887x_POSIO_IOSIZE_32       (5 << 24)
+/* Decoding speed (1 = slow, 2 = medium, 3 = fast) */
+#define ITE_887x_POSIO_SPEED           (3 << 29)
+/* enable IO_Space bit */
+#define ITE_887x_POSIO_ENABLE          (1 << 31)
+
+static int pci_ite887x_init(struct pci_dev *dev)
+{
+       /* inta_addr are the configuration addresses of the ITE */
+       static const short inta_addr[] = { 0x2a0, 0x2c0, 0x220, 0x240, 0x1e0,
+                                                       0x200, 0x280, 0 };
+       int ret, i, type;
+       struct resource *iobase = NULL;
+       u32 miscr, uartbar, ioport;
+
+       /* search for the base-ioport */
+       i = 0;
+       while (inta_addr[i] && iobase == NULL) {
+               iobase = request_region(inta_addr[i], ITE_887x_IOSIZE,
+                                                               "ite887x");
+               if (iobase != NULL) {
+                       /* write POSIO0R - speed | size | ioport */
+                       pci_write_config_dword(dev, ITE_887x_POSIO0,
+                               ITE_887x_POSIO_ENABLE | ITE_887x_POSIO_SPEED |
+                               ITE_887x_POSIO_IOSIZE_32 | inta_addr[i]);
+                       /* write INTCBAR - ioport */
+                       pci_write_config_dword(dev, ITE_887x_INTCBAR,
+                                                               inta_addr[i]);
+                       ret = inb(inta_addr[i]);
+                       if (ret != 0xff) {
+                               /* ioport connected */
+                               break;
+                       }
+                       release_region(iobase->start, ITE_887x_IOSIZE);
+                       iobase = NULL;
+               }
+               i++;
+       }
+
+       if (!inta_addr[i]) {
+               printk(KERN_ERR "ite887x: could not find iobase\n");
+               return -ENODEV;
+       }
+
+       /* start of undocumented type checking (see parport_pc.c) */
+       type = inb(iobase->start + 0x18) & 0x0f;
+
+       switch (type) {
+       case 0x2:       /* ITE8871 (1P) */
+       case 0xa:       /* ITE8875 (1P) */
+               ret = 0;
+               break;
+       case 0xe:       /* ITE8872 (2S1P) */
+               ret = 2;
+               break;
+       case 0x6:       /* ITE8873 (1S) */
+               ret = 1;
+               break;
+       case 0x8:       /* ITE8874 (2S) */
+               ret = 2;
+               break;
+       default:
+               moan_device("Unknown ITE887x", dev);
+               ret = -ENODEV;
+       }
+
+       /* configure all serial ports */
+       for (i = 0; i < ret; i++) {
+               /* read the I/O port from the device */
+               pci_read_config_dword(dev, ITE_887x_PS0BAR + (0x4 * (i + 1)),
+                                                               &ioport);
+               ioport &= 0x0000FF00;   /* the actual base address */
+               pci_write_config_dword(dev, ITE_887x_POSIO0 + (0x4 * (i + 1)),
+                       ITE_887x_POSIO_ENABLE | ITE_887x_POSIO_SPEED |
+                       ITE_887x_POSIO_IOSIZE_8 | ioport);
+
+               /* write the ioport to the UARTBAR */
+               pci_read_config_dword(dev, ITE_887x_UARTBAR, &uartbar);
+               uartbar &= ~(0xffff << (16 * i));       /* clear half the reg */
+               uartbar |= (ioport << (16 * i));        /* set the ioport */
+               pci_write_config_dword(dev, ITE_887x_UARTBAR, uartbar);
+
+               /* get current config */
+               pci_read_config_dword(dev, ITE_887x_MISCR, &miscr);
+               /* disable interrupts (UARTx_Routing[3:0]) */
+               miscr &= ~(0xf << (12 - 4 * i));
+               /* activate the UART (UARTx_En) */
+               miscr |= 1 << (23 - i);
+               /* write new config with activated UART */
+               pci_write_config_dword(dev, ITE_887x_MISCR, miscr);
+       }
+
+       if (ret <= 0) {
+               /* the device has no UARTs if we get here */
+               release_region(iobase->start, ITE_887x_IOSIZE);
+       }
+
+       return ret;
+}
+
+static void __devexit pci_ite887x_exit(struct pci_dev *dev)
+{
+       u32 ioport;
+       /* the ioport is bit 0-15 in POSIO0R */
+       pci_read_config_dword(dev, ITE_887x_POSIO0, &ioport);
+       ioport &= 0xffff;
+       release_region(ioport, ITE_887x_IOSIZE);
+}
+
+/*
+ * Oxford Semiconductor Inc.
+ * Check that device is part of the Tornado range of devices, then determine
+ * the number of ports available on the device.
+ */
+static int pci_oxsemi_tornado_init(struct pci_dev *dev)
+{
+       u8 __iomem *p;
+       unsigned long deviceID;
+       unsigned int  number_uarts = 0;
+
+       /* OxSemi Tornado devices are all 0xCxxx */
+       if (dev->vendor == PCI_VENDOR_ID_OXSEMI &&
+           (dev->device & 0xF000) != 0xC000)
+               return 0;
+
+       p = pci_iomap(dev, 0, 5);
+       if (p == NULL)
+               return -ENOMEM;
+
+       deviceID = ioread32(p);
+       /* Tornado device */
+       if (deviceID == 0x07000200) {
+               number_uarts = ioread8(p + 4);
+               printk(KERN_DEBUG
+                       "%d ports detected on Oxford PCI Express device\n",
+                                                               number_uarts);
+       }
+       pci_iounmap(dev, p);
+       return number_uarts;
+}
+
+static int
+pci_default_setup(struct serial_private *priv,
+                 const struct pciserial_board *board,
+                 struct uart_port *port, int idx)
+{
+       unsigned int bar, offset = board->first_offset, maxnr;
+
+       bar = FL_GET_BASE(board->flags);
+       if (board->flags & FL_BASE_BARS)
+               bar += idx;
+       else
+               offset += idx * board->uart_offset;
+
+       maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >>
+               (board->reg_shift + 3);
+
+       if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr)
+               return 1;
+
+       return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+static int
+ce4100_serial_setup(struct serial_private *priv,
+                 const struct pciserial_board *board,
+                 struct uart_port *port, int idx)
+{
+       int ret;
+
+       ret = setup_port(priv, port, 0, 0, board->reg_shift);
+       port->iotype = UPIO_MEM32;
+       port->type = PORT_XSCALE;
+       port->flags = (port->flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
+       port->regshift = 2;
+
+       return ret;
+}
+
+static int skip_tx_en_setup(struct serial_private *priv,
+                       const struct pciserial_board *board,
+                       struct uart_port *port, int idx)
+{
+       port->flags |= UPF_NO_TXEN_TEST;
+       printk(KERN_DEBUG "serial8250: skipping TxEn test for device "
+                         "[%04x:%04x] subsystem [%04x:%04x]\n",
+                         priv->dev->vendor,
+                         priv->dev->device,
+                         priv->dev->subsystem_vendor,
+                         priv->dev->subsystem_device);
+
+       return pci_default_setup(priv, board, port, idx);
+}
+
+/* This should be in linux/pci_ids.h */
+#define PCI_VENDOR_ID_SBSMODULARIO     0x124B
+#define PCI_SUBVENDOR_ID_SBSMODULARIO  0x124B
+#define PCI_DEVICE_ID_OCTPRO           0x0001
+#define PCI_SUBDEVICE_ID_OCTPRO232     0x0108
+#define PCI_SUBDEVICE_ID_OCTPRO422     0x0208
+#define PCI_SUBDEVICE_ID_POCTAL232     0x0308
+#define PCI_SUBDEVICE_ID_POCTAL422     0x0408
+#define PCI_VENDOR_ID_ADVANTECH                0x13fe
+#define PCI_DEVICE_ID_INTEL_CE4100_UART 0x2e66
+#define PCI_DEVICE_ID_ADVANTECH_PCI3620        0x3620
+#define PCI_DEVICE_ID_TITAN_200I       0x8028
+#define PCI_DEVICE_ID_TITAN_400I       0x8048
+#define PCI_DEVICE_ID_TITAN_800I       0x8088
+#define PCI_DEVICE_ID_TITAN_800EH      0xA007
+#define PCI_DEVICE_ID_TITAN_800EHB     0xA008
+#define PCI_DEVICE_ID_TITAN_400EH      0xA009
+#define PCI_DEVICE_ID_TITAN_100E       0xA010
+#define PCI_DEVICE_ID_TITAN_200E       0xA012
+#define PCI_DEVICE_ID_TITAN_400E       0xA013
+#define PCI_DEVICE_ID_TITAN_800E       0xA014
+#define PCI_DEVICE_ID_TITAN_200EI      0xA016
+#define PCI_DEVICE_ID_TITAN_200EISI    0xA017
+#define PCI_DEVICE_ID_OXSEMI_16PCI958  0x9538
+
+/* Unknown vendors/cards - this should not be in linux/pci_ids.h */
+#define PCI_SUBDEVICE_ID_UNKNOWN_0x1584        0x1584
+
+/*
+ * Master list of serial port init/setup/exit quirks.
+ * This does not describe the general nature of the port.
+ * (ie, baud base, number and location of ports, etc)
+ *
+ * This list is ordered alphabetically by vendor then device.
+ * Specific entries must come before more generic entries.
+ */
+static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
+       /*
+       * ADDI-DATA GmbH communication cards <info@addi-data.com>
+       */
+       {
+               .vendor         = PCI_VENDOR_ID_ADDIDATA_OLD,
+               .device         = PCI_DEVICE_ID_ADDIDATA_APCI7800,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = addidata_apci7800_setup,
+       },
+       /*
+        * AFAVLAB cards - these may be called via parport_serial
+        *  It is not clear whether this applies to all products.
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_AFAVLAB,
+               .device         = PCI_ANY_ID,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = afavlab_setup,
+       },
+       /*
+        * HP Diva
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_HP,
+               .device         = PCI_DEVICE_ID_HP_DIVA,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_hp_diva_init,
+               .setup          = pci_hp_diva_setup,
+       },
+       /*
+        * Intel
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_80960_RP,
+               .subvendor      = 0xe4bf,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_inteli960ni_init,
+               .setup          = pci_default_setup,
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_8257X_SOL,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = skip_tx_en_setup,
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_82573L_SOL,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = skip_tx_en_setup,
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_82573E_SOL,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = skip_tx_en_setup,
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_CE4100_UART,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = ce4100_serial_setup,
+       },
+       /*
+        * ITE
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_ITE,
+               .device         = PCI_DEVICE_ID_ITE_8872,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ite887x_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_ite887x_exit),
+       },
+       /*
+        * National Instruments
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_NI,
+               .device         = PCI_DEVICE_ID_NI_PCI23216,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ni8420_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_ni8420_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_NI,
+               .device         = PCI_DEVICE_ID_NI_PCI2328,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ni8420_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_ni8420_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_NI,
+               .device         = PCI_DEVICE_ID_NI_PCI2324,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ni8420_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_ni8420_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_NI,
+               .device         = PCI_DEVICE_ID_NI_PCI2322,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ni8420_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_ni8420_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_NI,
+               .device         = PCI_DEVICE_ID_NI_PCI2324I,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ni8420_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_ni8420_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_NI,
+               .device         = PCI_DEVICE_ID_NI_PCI2322I,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ni8420_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_ni8420_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_NI,
+               .device         = PCI_DEVICE_ID_NI_PXI8420_23216,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ni8420_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_ni8420_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_NI,
+               .device         = PCI_DEVICE_ID_NI_PXI8420_2328,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ni8420_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_ni8420_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_NI,
+               .device         = PCI_DEVICE_ID_NI_PXI8420_2324,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ni8420_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_ni8420_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_NI,
+               .device         = PCI_DEVICE_ID_NI_PXI8420_2322,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ni8420_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_ni8420_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_NI,
+               .device         = PCI_DEVICE_ID_NI_PXI8422_2324,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ni8420_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_ni8420_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_NI,
+               .device         = PCI_DEVICE_ID_NI_PXI8422_2322,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ni8420_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_ni8420_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_NI,
+               .device         = PCI_ANY_ID,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ni8430_init,
+               .setup          = pci_ni8430_setup,
+               .exit           = __devexit_p(pci_ni8430_exit),
+       },
+       /*
+        * Panacom
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_PANACOM,
+               .device         = PCI_DEVICE_ID_PANACOM_QUADMODEM,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_plx9050_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_plx9050_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_PANACOM,
+               .device         = PCI_DEVICE_ID_PANACOM_DUALMODEM,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_plx9050_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_plx9050_exit),
+       },
+       /*
+        * PLX
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_PLX,
+               .device         = PCI_DEVICE_ID_PLX_9030,
+               .subvendor      = PCI_SUBVENDOR_ID_PERLE,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = pci_default_setup,
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_PLX,
+               .device         = PCI_DEVICE_ID_PLX_9050,
+               .subvendor      = PCI_SUBVENDOR_ID_EXSYS,
+               .subdevice      = PCI_SUBDEVICE_ID_EXSYS_4055,
+               .init           = pci_plx9050_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_plx9050_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_PLX,
+               .device         = PCI_DEVICE_ID_PLX_9050,
+               .subvendor      = PCI_SUBVENDOR_ID_KEYSPAN,
+               .subdevice      = PCI_SUBDEVICE_ID_KEYSPAN_SX2,
+               .init           = pci_plx9050_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_plx9050_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_PLX,
+               .device         = PCI_DEVICE_ID_PLX_9050,
+               .subvendor      = PCI_VENDOR_ID_PLX,
+               .subdevice      = PCI_SUBDEVICE_ID_UNKNOWN_0x1584,
+               .init           = pci_plx9050_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_plx9050_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_PLX,
+               .device         = PCI_DEVICE_ID_PLX_ROMULUS,
+               .subvendor      = PCI_VENDOR_ID_PLX,
+               .subdevice      = PCI_DEVICE_ID_PLX_ROMULUS,
+               .init           = pci_plx9050_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_plx9050_exit),
+       },
+       /*
+        * SBS Technologies, Inc., PMC-OCTALPRO 232
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_SBSMODULARIO,
+               .device         = PCI_DEVICE_ID_OCTPRO,
+               .subvendor      = PCI_SUBVENDOR_ID_SBSMODULARIO,
+               .subdevice      = PCI_SUBDEVICE_ID_OCTPRO232,
+               .init           = sbs_init,
+               .setup          = sbs_setup,
+               .exit           = __devexit_p(sbs_exit),
+       },
+       /*
+        * SBS Technologies, Inc., PMC-OCTALPRO 422
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_SBSMODULARIO,
+               .device         = PCI_DEVICE_ID_OCTPRO,
+               .subvendor      = PCI_SUBVENDOR_ID_SBSMODULARIO,
+               .subdevice      = PCI_SUBDEVICE_ID_OCTPRO422,
+               .init           = sbs_init,
+               .setup          = sbs_setup,
+               .exit           = __devexit_p(sbs_exit),
+       },
+       /*
+        * SBS Technologies, Inc., P-Octal 232
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_SBSMODULARIO,
+               .device         = PCI_DEVICE_ID_OCTPRO,
+               .subvendor      = PCI_SUBVENDOR_ID_SBSMODULARIO,
+               .subdevice      = PCI_SUBDEVICE_ID_POCTAL232,
+               .init           = sbs_init,
+               .setup          = sbs_setup,
+               .exit           = __devexit_p(sbs_exit),
+       },
+       /*
+        * SBS Technologies, Inc., P-Octal 422
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_SBSMODULARIO,
+               .device         = PCI_DEVICE_ID_OCTPRO,
+               .subvendor      = PCI_SUBVENDOR_ID_SBSMODULARIO,
+               .subdevice      = PCI_SUBDEVICE_ID_POCTAL422,
+               .init           = sbs_init,
+               .setup          = sbs_setup,
+               .exit           = __devexit_p(sbs_exit),
+       },
+       /*
+        * SIIG cards - these may be called via parport_serial
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_SIIG,
+               .device         = PCI_ANY_ID,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_siig_init,
+               .setup          = pci_siig_setup,
+       },
+       /*
+        * Titan cards
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_TITAN,
+               .device         = PCI_DEVICE_ID_TITAN_400L,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = titan_400l_800l_setup,
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_TITAN,
+               .device         = PCI_DEVICE_ID_TITAN_800L,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = titan_400l_800l_setup,
+       },
+       /*
+        * Timedia cards
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_TIMEDIA,
+               .device         = PCI_DEVICE_ID_TIMEDIA_1889,
+               .subvendor      = PCI_VENDOR_ID_TIMEDIA,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_timedia_init,
+               .setup          = pci_timedia_setup,
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_TIMEDIA,
+               .device         = PCI_ANY_ID,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = pci_timedia_setup,
+       },
+       /*
+        * Xircom cards
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_XIRCOM,
+               .device         = PCI_DEVICE_ID_XIRCOM_X3201_MDM,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_xircom_init,
+               .setup          = pci_default_setup,
+       },
+       /*
+        * Netmos cards - these may be called via parport_serial
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_NETMOS,
+               .device         = PCI_ANY_ID,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_netmos_init,
+               .setup          = pci_default_setup,
+       },
+       /*
+        * For Oxford Semiconductor and Mainpine
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_OXSEMI,
+               .device         = PCI_ANY_ID,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_oxsemi_tornado_init,
+               .setup          = pci_default_setup,
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_MAINPINE,
+               .device         = PCI_ANY_ID,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_oxsemi_tornado_init,
+               .setup          = pci_default_setup,
+       },
+       /*
+        * Default "match everything" terminator entry
+        */
+       {
+               .vendor         = PCI_ANY_ID,
+               .device         = PCI_ANY_ID,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = pci_default_setup,
+       }
+};
+
+static inline int quirk_id_matches(u32 quirk_id, u32 dev_id)
+{
+       return quirk_id == PCI_ANY_ID || quirk_id == dev_id;
+}
+
+static struct pci_serial_quirk *find_quirk(struct pci_dev *dev)
+{
+       struct pci_serial_quirk *quirk;
+
+       for (quirk = pci_serial_quirks; ; quirk++)
+               if (quirk_id_matches(quirk->vendor, dev->vendor) &&
+                   quirk_id_matches(quirk->device, dev->device) &&
+                   quirk_id_matches(quirk->subvendor, dev->subsystem_vendor) &&
+                   quirk_id_matches(quirk->subdevice, dev->subsystem_device))
+                       break;
+       return quirk;
+}
+
+static inline int get_pci_irq(struct pci_dev *dev,
+                               const struct pciserial_board *board)
+{
+       if (board->flags & FL_NOIRQ)
+               return 0;
+       else
+               return dev->irq;
+}
+
+/*
+ * This is the configuration table for all of the PCI serial boards
+ * which we support.  It is directly indexed by the pci_board_num_t enum
+ * value, which is encoded in the pci_device_id PCI probe table's
+ * driver_data member.
+ *
+ * The makeup of these names are:
+ *  pbn_bn{_bt}_n_baud{_offsetinhex}
+ *
+ *  bn         = PCI BAR number
+ *  bt         = Index using PCI BARs
+ *  n          = number of serial ports
+ *  baud       = baud rate
+ *  offsetinhex        = offset for each sequential port (in hex)
+ *
+ * This table is sorted by (in order): bn, bt, baud, offsetindex, n.
+ *
+ * Please note: in theory if n = 1, _bt infix should make no difference.
+ * ie, pbn_b0_1_115200 is the same as pbn_b0_bt_1_115200
+ */
+enum pci_board_num_t {
+       pbn_default = 0,
+
+       pbn_b0_1_115200,
+       pbn_b0_2_115200,
+       pbn_b0_4_115200,
+       pbn_b0_5_115200,
+       pbn_b0_8_115200,
+
+       pbn_b0_1_921600,
+       pbn_b0_2_921600,
+       pbn_b0_4_921600,
+
+       pbn_b0_2_1130000,
+
+       pbn_b0_4_1152000,
+
+       pbn_b0_2_1843200,
+       pbn_b0_4_1843200,
+
+       pbn_b0_2_1843200_200,
+       pbn_b0_4_1843200_200,
+       pbn_b0_8_1843200_200,
+
+       pbn_b0_1_4000000,
+
+       pbn_b0_bt_1_115200,
+       pbn_b0_bt_2_115200,
+       pbn_b0_bt_4_115200,
+       pbn_b0_bt_8_115200,
+
+       pbn_b0_bt_1_460800,
+       pbn_b0_bt_2_460800,
+       pbn_b0_bt_4_460800,
+
+       pbn_b0_bt_1_921600,
+       pbn_b0_bt_2_921600,
+       pbn_b0_bt_4_921600,
+       pbn_b0_bt_8_921600,
+
+       pbn_b1_1_115200,
+       pbn_b1_2_115200,
+       pbn_b1_4_115200,
+       pbn_b1_8_115200,
+       pbn_b1_16_115200,
+
+       pbn_b1_1_921600,
+       pbn_b1_2_921600,
+       pbn_b1_4_921600,
+       pbn_b1_8_921600,
+
+       pbn_b1_2_1250000,
+
+       pbn_b1_bt_1_115200,
+       pbn_b1_bt_2_115200,
+       pbn_b1_bt_4_115200,
+
+       pbn_b1_bt_2_921600,
+
+       pbn_b1_1_1382400,
+       pbn_b1_2_1382400,
+       pbn_b1_4_1382400,
+       pbn_b1_8_1382400,
+
+       pbn_b2_1_115200,
+       pbn_b2_2_115200,
+       pbn_b2_4_115200,
+       pbn_b2_8_115200,
+
+       pbn_b2_1_460800,
+       pbn_b2_4_460800,
+       pbn_b2_8_460800,
+       pbn_b2_16_460800,
+
+       pbn_b2_1_921600,
+       pbn_b2_4_921600,
+       pbn_b2_8_921600,
+
+       pbn_b2_8_1152000,
+
+       pbn_b2_bt_1_115200,
+       pbn_b2_bt_2_115200,
+       pbn_b2_bt_4_115200,
+
+       pbn_b2_bt_2_921600,
+       pbn_b2_bt_4_921600,
+
+       pbn_b3_2_115200,
+       pbn_b3_4_115200,
+       pbn_b3_8_115200,
+
+       pbn_b4_bt_2_921600,
+       pbn_b4_bt_4_921600,
+       pbn_b4_bt_8_921600,
+
+       /*
+        * Board-specific versions.
+        */
+       pbn_panacom,
+       pbn_panacom2,
+       pbn_panacom4,
+       pbn_exsys_4055,
+       pbn_plx_romulus,
+       pbn_oxsemi,
+       pbn_oxsemi_1_4000000,
+       pbn_oxsemi_2_4000000,
+       pbn_oxsemi_4_4000000,
+       pbn_oxsemi_8_4000000,
+       pbn_intel_i960,
+       pbn_sgi_ioc3,
+       pbn_computone_4,
+       pbn_computone_6,
+       pbn_computone_8,
+       pbn_sbsxrsio,
+       pbn_exar_XR17C152,
+       pbn_exar_XR17C154,
+       pbn_exar_XR17C158,
+       pbn_exar_ibm_saturn,
+       pbn_pasemi_1682M,
+       pbn_ni8430_2,
+       pbn_ni8430_4,
+       pbn_ni8430_8,
+       pbn_ni8430_16,
+       pbn_ADDIDATA_PCIe_1_3906250,
+       pbn_ADDIDATA_PCIe_2_3906250,
+       pbn_ADDIDATA_PCIe_4_3906250,
+       pbn_ADDIDATA_PCIe_8_3906250,
+       pbn_ce4100_1_115200,
+};
+
+/*
+ * uart_offset - the space between channels
+ * reg_shift   - describes how the UART registers are mapped
+ *               to PCI memory by the card.
+ * For example IER register on SBS, Inc. PMC-OctPro is located at
+ * offset 0x10 from the UART base, while UART_IER is defined as 1
+ * in include/linux/serial_reg.h,
+ * see first lines of serial_in() and serial_out() in 8250.c
+*/
+
+static struct pciserial_board pci_boards[] __devinitdata = {
+       [pbn_default] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 1,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_1_115200] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 1,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_2_115200] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 2,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_4_115200] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 4,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_5_115200] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 5,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_8_115200] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 8,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_1_921600] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 1,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_2_921600] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 2,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_4_921600] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 4,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b0_2_1130000] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 2,
+               .base_baud      = 1130000,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b0_4_1152000] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 4,
+               .base_baud      = 1152000,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b0_2_1843200] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 2,
+               .base_baud      = 1843200,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_4_1843200] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 4,
+               .base_baud      = 1843200,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b0_2_1843200_200] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 2,
+               .base_baud      = 1843200,
+               .uart_offset    = 0x200,
+       },
+       [pbn_b0_4_1843200_200] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 4,
+               .base_baud      = 1843200,
+               .uart_offset    = 0x200,
+       },
+       [pbn_b0_8_1843200_200] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 8,
+               .base_baud      = 1843200,
+               .uart_offset    = 0x200,
+       },
+       [pbn_b0_1_4000000] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 1,
+               .base_baud      = 4000000,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b0_bt_1_115200] = {
+               .flags          = FL_BASE0|FL_BASE_BARS,
+               .num_ports      = 1,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_bt_2_115200] = {
+               .flags          = FL_BASE0|FL_BASE_BARS,
+               .num_ports      = 2,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_bt_4_115200] = {
+               .flags          = FL_BASE0|FL_BASE_BARS,
+               .num_ports      = 4,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_bt_8_115200] = {
+               .flags          = FL_BASE0|FL_BASE_BARS,
+               .num_ports      = 8,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b0_bt_1_460800] = {
+               .flags          = FL_BASE0|FL_BASE_BARS,
+               .num_ports      = 1,
+               .base_baud      = 460800,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_bt_2_460800] = {
+               .flags          = FL_BASE0|FL_BASE_BARS,
+               .num_ports      = 2,
+               .base_baud      = 460800,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_bt_4_460800] = {
+               .flags          = FL_BASE0|FL_BASE_BARS,
+               .num_ports      = 4,
+               .base_baud      = 460800,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b0_bt_1_921600] = {
+               .flags          = FL_BASE0|FL_BASE_BARS,
+               .num_ports      = 1,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_bt_2_921600] = {
+               .flags          = FL_BASE0|FL_BASE_BARS,
+               .num_ports      = 2,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_bt_4_921600] = {
+               .flags          = FL_BASE0|FL_BASE_BARS,
+               .num_ports      = 4,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_bt_8_921600] = {
+               .flags          = FL_BASE0|FL_BASE_BARS,
+               .num_ports      = 8,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b1_1_115200] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 1,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b1_2_115200] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 2,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b1_4_115200] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 4,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b1_8_115200] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 8,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b1_16_115200] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 16,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b1_1_921600] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 1,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b1_2_921600] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 2,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b1_4_921600] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 4,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b1_8_921600] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 8,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b1_2_1250000] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 2,
+               .base_baud      = 1250000,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b1_bt_1_115200] = {
+               .flags          = FL_BASE1|FL_BASE_BARS,
+               .num_ports      = 1,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b1_bt_2_115200] = {
+               .flags          = FL_BASE1|FL_BASE_BARS,
+               .num_ports      = 2,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b1_bt_4_115200] = {
+               .flags          = FL_BASE1|FL_BASE_BARS,
+               .num_ports      = 4,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b1_bt_2_921600] = {
+               .flags          = FL_BASE1|FL_BASE_BARS,
+               .num_ports      = 2,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b1_1_1382400] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 1,
+               .base_baud      = 1382400,
+               .uart_offset    = 8,
+       },
+       [pbn_b1_2_1382400] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 2,
+               .base_baud      = 1382400,
+               .uart_offset    = 8,
+       },
+       [pbn_b1_4_1382400] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 4,
+               .base_baud      = 1382400,
+               .uart_offset    = 8,
+       },
+       [pbn_b1_8_1382400] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 8,
+               .base_baud      = 1382400,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b2_1_115200] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 1,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b2_2_115200] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 2,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b2_4_115200] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 4,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b2_8_115200] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 8,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b2_1_460800] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 1,
+               .base_baud      = 460800,
+               .uart_offset    = 8,
+       },
+       [pbn_b2_4_460800] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 4,
+               .base_baud      = 460800,
+               .uart_offset    = 8,
+       },
+       [pbn_b2_8_460800] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 8,
+               .base_baud      = 460800,
+               .uart_offset    = 8,
+       },
+       [pbn_b2_16_460800] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 16,
+               .base_baud      = 460800,
+               .uart_offset    = 8,
+        },
+
+       [pbn_b2_1_921600] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 1,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b2_4_921600] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 4,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b2_8_921600] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 8,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b2_8_1152000] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 8,
+               .base_baud      = 1152000,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b2_bt_1_115200] = {
+               .flags          = FL_BASE2|FL_BASE_BARS,
+               .num_ports      = 1,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b2_bt_2_115200] = {
+               .flags          = FL_BASE2|FL_BASE_BARS,
+               .num_ports      = 2,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b2_bt_4_115200] = {
+               .flags          = FL_BASE2|FL_BASE_BARS,
+               .num_ports      = 4,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b2_bt_2_921600] = {
+               .flags          = FL_BASE2|FL_BASE_BARS,
+               .num_ports      = 2,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b2_bt_4_921600] = {
+               .flags          = FL_BASE2|FL_BASE_BARS,
+               .num_ports      = 4,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b3_2_115200] = {
+               .flags          = FL_BASE3,
+               .num_ports      = 2,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b3_4_115200] = {
+               .flags          = FL_BASE3,
+               .num_ports      = 4,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b3_8_115200] = {
+               .flags          = FL_BASE3,
+               .num_ports      = 8,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b4_bt_2_921600] = {
+               .flags          = FL_BASE4,
+               .num_ports      = 2,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b4_bt_4_921600] = {
+               .flags          = FL_BASE4,
+               .num_ports      = 4,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b4_bt_8_921600] = {
+               .flags          = FL_BASE4,
+               .num_ports      = 8,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+
+       /*
+        * Entries following this are board-specific.
+        */
+
+       /*
+        * Panacom - IOMEM
+        */
+       [pbn_panacom] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 2,
+               .base_baud      = 921600,
+               .uart_offset    = 0x400,
+               .reg_shift      = 7,
+       },
+       [pbn_panacom2] = {
+               .flags          = FL_BASE2|FL_BASE_BARS,
+               .num_ports      = 2,
+               .base_baud      = 921600,
+               .uart_offset    = 0x400,
+               .reg_shift      = 7,
+       },
+       [pbn_panacom4] = {
+               .flags          = FL_BASE2|FL_BASE_BARS,
+               .num_ports      = 4,
+               .base_baud      = 921600,
+               .uart_offset    = 0x400,
+               .reg_shift      = 7,
+       },
+
+       [pbn_exsys_4055] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 4,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+
+       /* I think this entry is broken - the first_offset looks wrong --rmk */
+       [pbn_plx_romulus] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 4,
+               .base_baud      = 921600,
+               .uart_offset    = 8 << 2,
+               .reg_shift      = 2,
+               .first_offset   = 0x03,
+       },
+
+       /*
+        * This board uses the size of PCI Base region 0 to
+        * signal now many ports are available
+        */
+       [pbn_oxsemi] = {
+               .flags          = FL_BASE0|FL_REGION_SZ_CAP,
+               .num_ports      = 32,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_oxsemi_1_4000000] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 1,
+               .base_baud      = 4000000,
+               .uart_offset    = 0x200,
+               .first_offset   = 0x1000,
+       },
+       [pbn_oxsemi_2_4000000] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 2,
+               .base_baud      = 4000000,
+               .uart_offset    = 0x200,
+               .first_offset   = 0x1000,
+       },
+       [pbn_oxsemi_4_4000000] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 4,
+               .base_baud      = 4000000,
+               .uart_offset    = 0x200,
+               .first_offset   = 0x1000,
+       },
+       [pbn_oxsemi_8_4000000] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 8,
+               .base_baud      = 4000000,
+               .uart_offset    = 0x200,
+               .first_offset   = 0x1000,
+       },
+
+
+       /*
+        * EKF addition for i960 Boards form EKF with serial port.
+        * Max 256 ports.
+        */
+       [pbn_intel_i960] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 32,
+               .base_baud      = 921600,
+               .uart_offset    = 8 << 2,
+               .reg_shift      = 2,
+               .first_offset   = 0x10000,
+       },
+       [pbn_sgi_ioc3] = {
+               .flags          = FL_BASE0|FL_NOIRQ,
+               .num_ports      = 1,
+               .base_baud      = 458333,
+               .uart_offset    = 8,
+               .reg_shift      = 0,
+               .first_offset   = 0x20178,
+       },
+
+       /*
+        * Computone - uses IOMEM.
+        */
+       [pbn_computone_4] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 4,
+               .base_baud      = 921600,
+               .uart_offset    = 0x40,
+               .reg_shift      = 2,
+               .first_offset   = 0x200,
+       },
+       [pbn_computone_6] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 6,
+               .base_baud      = 921600,
+               .uart_offset    = 0x40,
+               .reg_shift      = 2,
+               .first_offset   = 0x200,
+       },
+       [pbn_computone_8] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 8,
+               .base_baud      = 921600,
+               .uart_offset    = 0x40,
+               .reg_shift      = 2,
+               .first_offset   = 0x200,
+       },
+       [pbn_sbsxrsio] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 8,
+               .base_baud      = 460800,
+               .uart_offset    = 256,
+               .reg_shift      = 4,
+       },
+       /*
+        * Exar Corp. XR17C15[248] Dual/Quad/Octal UART
+        *  Only basic 16550A support.
+        *  XR17C15[24] are not tested, but they should work.
+        */
+       [pbn_exar_XR17C152] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 2,
+               .base_baud      = 921600,
+               .uart_offset    = 0x200,
+       },
+       [pbn_exar_XR17C154] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 4,
+               .base_baud      = 921600,
+               .uart_offset    = 0x200,
+       },
+       [pbn_exar_XR17C158] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 8,
+               .base_baud      = 921600,
+               .uart_offset    = 0x200,
+       },
+       [pbn_exar_ibm_saturn] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 1,
+               .base_baud      = 921600,
+               .uart_offset    = 0x200,
+       },
+
+       /*
+        * PA Semi PWRficient PA6T-1682M on-chip UART
+        */
+       [pbn_pasemi_1682M] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 1,
+               .base_baud      = 8333333,
+       },
+       /*
+        * National Instruments 843x
+        */
+       [pbn_ni8430_16] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 16,
+               .base_baud      = 3686400,
+               .uart_offset    = 0x10,
+               .first_offset   = 0x800,
+       },
+       [pbn_ni8430_8] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 8,
+               .base_baud      = 3686400,
+               .uart_offset    = 0x10,
+               .first_offset   = 0x800,
+       },
+       [pbn_ni8430_4] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 4,
+               .base_baud      = 3686400,
+               .uart_offset    = 0x10,
+               .first_offset   = 0x800,
+       },
+       [pbn_ni8430_2] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 2,
+               .base_baud      = 3686400,
+               .uart_offset    = 0x10,
+               .first_offset   = 0x800,
+       },
+       /*
+        * ADDI-DATA GmbH PCI-Express communication cards <info@addi-data.com>
+        */
+       [pbn_ADDIDATA_PCIe_1_3906250] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 1,
+               .base_baud      = 3906250,
+               .uart_offset    = 0x200,
+               .first_offset   = 0x1000,
+       },
+       [pbn_ADDIDATA_PCIe_2_3906250] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 2,
+               .base_baud      = 3906250,
+               .uart_offset    = 0x200,
+               .first_offset   = 0x1000,
+       },
+       [pbn_ADDIDATA_PCIe_4_3906250] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 4,
+               .base_baud      = 3906250,
+               .uart_offset    = 0x200,
+               .first_offset   = 0x1000,
+       },
+       [pbn_ADDIDATA_PCIe_8_3906250] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 8,
+               .base_baud      = 3906250,
+               .uart_offset    = 0x200,
+               .first_offset   = 0x1000,
+       },
+       [pbn_ce4100_1_115200] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 1,
+               .base_baud      = 921600,
+               .reg_shift      = 2,
+       },
+};
+
+static const struct pci_device_id softmodem_blacklist[] = {
+       { PCI_VDEVICE(AL, 0x5457), }, /* ALi Corporation M5457 AC'97 Modem */
+       { PCI_VDEVICE(MOTOROLA, 0x3052), }, /* Motorola Si3052-based modem */
+       { PCI_DEVICE(0x1543, 0x3052), }, /* Si3052-based modem, default IDs */
+};
+
+/*
+ * Given a complete unknown PCI device, try to use some heuristics to
+ * guess what the configuration might be, based on the pitiful PCI
+ * serial specs.  Returns 0 on success, 1 on failure.
+ */
+static int __devinit
+serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
+{
+       const struct pci_device_id *blacklist;
+       int num_iomem, num_port, first_port = -1, i;
+
+       /*
+        * If it is not a communications device or the programming
+        * interface is greater than 6, give up.
+        *
+        * (Should we try to make guesses for multiport serial devices
+        * later?)
+        */
+       if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) &&
+            ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) ||
+           (dev->class & 0xff) > 6)
+               return -ENODEV;
+
+       /*
+        * Do not access blacklisted devices that are known not to
+        * feature serial ports.
+        */
+       for (blacklist = softmodem_blacklist;
+            blacklist < softmodem_blacklist + ARRAY_SIZE(softmodem_blacklist);
+            blacklist++) {
+               if (dev->vendor == blacklist->vendor &&
+                   dev->device == blacklist->device)
+                       return -ENODEV;
+       }
+
+       num_iomem = num_port = 0;
+       for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
+               if (pci_resource_flags(dev, i) & IORESOURCE_IO) {
+                       num_port++;
+                       if (first_port == -1)
+                               first_port = i;
+               }
+               if (pci_resource_flags(dev, i) & IORESOURCE_MEM)
+                       num_iomem++;
+       }
+
+       /*
+        * If there is 1 or 0 iomem regions, and exactly one port,
+        * use it.  We guess the number of ports based on the IO
+        * region size.
+        */
+       if (num_iomem <= 1 && num_port == 1) {
+               board->flags = first_port;
+               board->num_ports = pci_resource_len(dev, first_port) / 8;
+               return 0;
+       }
+
+       /*
+        * Now guess if we've got a board which indexes by BARs.
+        * Each IO BAR should be 8 bytes, and they should follow
+        * consecutively.
+        */
+       first_port = -1;
+       num_port = 0;
+       for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
+               if (pci_resource_flags(dev, i) & IORESOURCE_IO &&
+                   pci_resource_len(dev, i) == 8 &&
+                   (first_port == -1 || (first_port + num_port) == i)) {
+                       num_port++;
+                       if (first_port == -1)
+                               first_port = i;
+               }
+       }
+
+       if (num_port > 1) {
+               board->flags = first_port | FL_BASE_BARS;
+               board->num_ports = num_port;
+               return 0;
+       }
+
+       return -ENODEV;
+}
+
+static inline int
+serial_pci_matches(const struct pciserial_board *board,
+                  const struct pciserial_board *guessed)
+{
+       return
+           board->num_ports == guessed->num_ports &&
+           board->base_baud == guessed->base_baud &&
+           board->uart_offset == guessed->uart_offset &&
+           board->reg_shift == guessed->reg_shift &&
+           board->first_offset == guessed->first_offset;
+}
+
+struct serial_private *
+pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
+{
+       struct uart_port serial_port;
+       struct serial_private *priv;
+       struct pci_serial_quirk *quirk;
+       int rc, nr_ports, i;
+
+       nr_ports = board->num_ports;
+
+       /*
+        * Find an init and setup quirks.
+        */
+       quirk = find_quirk(dev);
+
+       /*
+        * Run the new-style initialization function.
+        * The initialization function returns:
+        *  <0  - error
+        *   0  - use board->num_ports
+        *  >0  - number of ports
+        */
+       if (quirk->init) {
+               rc = quirk->init(dev);
+               if (rc < 0) {
+                       priv = ERR_PTR(rc);
+                       goto err_out;
+               }
+               if (rc)
+                       nr_ports = rc;
+       }
+
+       priv = kzalloc(sizeof(struct serial_private) +
+                      sizeof(unsigned int) * nr_ports,
+                      GFP_KERNEL);
+       if (!priv) {
+               priv = ERR_PTR(-ENOMEM);
+               goto err_deinit;
+       }
+
+       priv->dev = dev;
+       priv->quirk = quirk;
+
+       memset(&serial_port, 0, sizeof(struct uart_port));
+       serial_port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+       serial_port.uartclk = board->base_baud * 16;
+       serial_port.irq = get_pci_irq(dev, board);
+       serial_port.dev = &dev->dev;
+
+       for (i = 0; i < nr_ports; i++) {
+               if (quirk->setup(priv, board, &serial_port, i))
+                       break;
+
+#ifdef SERIAL_DEBUG_PCI
+               printk(KERN_DEBUG "Setup PCI port: port %lx, irq %d, type %d\n",
+                      serial_port.iobase, serial_port.irq, serial_port.iotype);
+#endif
+
+               priv->line[i] = serial8250_register_port(&serial_port);
+               if (priv->line[i] < 0) {
+                       printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), priv->line[i]);
+                       break;
+               }
+       }
+       priv->nr = i;
+       return priv;
+
+err_deinit:
+       if (quirk->exit)
+               quirk->exit(dev);
+err_out:
+       return priv;
+}
+EXPORT_SYMBOL_GPL(pciserial_init_ports);
+
+void pciserial_remove_ports(struct serial_private *priv)
+{
+       struct pci_serial_quirk *quirk;
+       int i;
+
+       for (i = 0; i < priv->nr; i++)
+               serial8250_unregister_port(priv->line[i]);
+
+       for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
+               if (priv->remapped_bar[i])
+                       iounmap(priv->remapped_bar[i]);
+               priv->remapped_bar[i] = NULL;
+       }
+
+       /*
+        * Find the exit quirks.
+        */
+       quirk = find_quirk(priv->dev);
+       if (quirk->exit)
+               quirk->exit(priv->dev);
+
+       kfree(priv);
+}
+EXPORT_SYMBOL_GPL(pciserial_remove_ports);
+
+void pciserial_suspend_ports(struct serial_private *priv)
+{
+       int i;
+
+       for (i = 0; i < priv->nr; i++)
+               if (priv->line[i] >= 0)
+                       serial8250_suspend_port(priv->line[i]);
+}
+EXPORT_SYMBOL_GPL(pciserial_suspend_ports);
+
+void pciserial_resume_ports(struct serial_private *priv)
+{
+       int i;
+
+       /*
+        * Ensure that the board is correctly configured.
+        */
+       if (priv->quirk->init)
+               priv->quirk->init(priv->dev);
+
+       for (i = 0; i < priv->nr; i++)
+               if (priv->line[i] >= 0)
+                       serial8250_resume_port(priv->line[i]);
+}
+EXPORT_SYMBOL_GPL(pciserial_resume_ports);
+
+/*
+ * Probe one serial board.  Unfortunately, there is no rhyme nor reason
+ * to the arrangement of serial ports on a PCI card.
+ */
+static int __devinit
+pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
+{
+       struct serial_private *priv;
+       const struct pciserial_board *board;
+       struct pciserial_board tmp;
+       int rc;
+
+       if (ent->driver_data >= ARRAY_SIZE(pci_boards)) {
+               printk(KERN_ERR "pci_init_one: invalid driver_data: %ld\n",
+                       ent->driver_data);
+               return -EINVAL;
+       }
+
+       board = &pci_boards[ent->driver_data];
+
+       rc = pci_enable_device(dev);
+       if (rc)
+               return rc;
+
+       if (ent->driver_data == pbn_default) {
+               /*
+                * Use a copy of the pci_board entry for this;
+                * avoid changing entries in the table.
+                */
+               memcpy(&tmp, board, sizeof(struct pciserial_board));
+               board = &tmp;
+
+               /*
+                * We matched one of our class entries.  Try to
+                * determine the parameters of this board.
+                */
+               rc = serial_pci_guess_board(dev, &tmp);
+               if (rc)
+                       goto disable;
+       } else {
+               /*
+                * We matched an explicit entry.  If we are able to
+                * detect this boards settings with our heuristic,
+                * then we no longer need this entry.
+                */
+               memcpy(&tmp, &pci_boards[pbn_default],
+                      sizeof(struct pciserial_board));
+               rc = serial_pci_guess_board(dev, &tmp);
+               if (rc == 0 && serial_pci_matches(board, &tmp))
+                       moan_device("Redundant entry in serial pci_table.",
+                                   dev);
+       }
+
+       priv = pciserial_init_ports(dev, board);
+       if (!IS_ERR(priv)) {
+               pci_set_drvdata(dev, priv);
+               return 0;
+       }
+
+       rc = PTR_ERR(priv);
+
+ disable:
+       pci_disable_device(dev);
+       return rc;
+}
+
+static void __devexit pciserial_remove_one(struct pci_dev *dev)
+{
+       struct serial_private *priv = pci_get_drvdata(dev);
+
+       pci_set_drvdata(dev, NULL);
+
+       pciserial_remove_ports(priv);
+
+       pci_disable_device(dev);
+}
+
+#ifdef CONFIG_PM
+static int pciserial_suspend_one(struct pci_dev *dev, pm_message_t state)
+{
+       struct serial_private *priv = pci_get_drvdata(dev);
+
+       if (priv)
+               pciserial_suspend_ports(priv);
+
+       pci_save_state(dev);
+       pci_set_power_state(dev, pci_choose_state(dev, state));
+       return 0;
+}
+
+static int pciserial_resume_one(struct pci_dev *dev)
+{
+       int err;
+       struct serial_private *priv = pci_get_drvdata(dev);
+
+       pci_set_power_state(dev, PCI_D0);
+       pci_restore_state(dev);
+
+       if (priv) {
+               /*
+                * The device may have been disabled.  Re-enable it.
+                */
+               err = pci_enable_device(dev);
+               /* FIXME: We cannot simply error out here */
+               if (err)
+                       printk(KERN_ERR "pciserial: Unable to re-enable ports, trying to continue.\n");
+               pciserial_resume_ports(priv);
+       }
+       return 0;
+}
+#endif
+
+static struct pci_device_id serial_pci_tbl[] = {
+       /* Advantech use PCI_DEVICE_ID_ADVANTECH_PCI3620 (0x3620) as 'PCI_SUBVENDOR_ID' */
+       {       PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620,
+               PCI_DEVICE_ID_ADVANTECH_PCI3620, 0x0001, 0, 0,
+               pbn_b2_8_921600 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
+               pbn_b1_8_1382400 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
+               pbn_b1_4_1382400 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
+               pbn_b1_2_1382400 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
+               pbn_b1_8_1382400 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
+               pbn_b1_4_1382400 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
+               pbn_b1_2_1382400 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, 0, 0,
+               pbn_b1_8_921600 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, 0, 0,
+               pbn_b1_8_921600 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, 0, 0,
+               pbn_b1_4_921600 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, 0, 0,
+               pbn_b1_4_921600 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, 0, 0,
+               pbn_b1_2_921600 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6, 0, 0,
+               pbn_b1_8_921600 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1, 0, 0,
+               pbn_b1_8_921600 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1, 0, 0,
+               pbn_b1_4_921600 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_20MHZ, 0, 0,
+               pbn_b1_2_1250000 },
+       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_2, 0, 0,
+               pbn_b0_2_1843200 },
+       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_4, 0, 0,
+               pbn_b0_4_1843200 },
+       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+               PCI_VENDOR_ID_AFAVLAB,
+               PCI_SUBDEVICE_ID_AFAVLAB_P061, 0, 0,
+               pbn_b0_4_1152000 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_232, 0, 0,
+               pbn_b0_2_1843200_200 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_232, 0, 0,
+               pbn_b0_4_1843200_200 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_232, 0, 0,
+               pbn_b0_8_1843200_200 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_1_1, 0, 0,
+               pbn_b0_2_1843200_200 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_2, 0, 0,
+               pbn_b0_4_1843200_200 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4, 0, 0,
+               pbn_b0_8_1843200_200 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2, 0, 0,
+               pbn_b0_2_1843200_200 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4, 0, 0,
+               pbn_b0_4_1843200_200 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8, 0, 0,
+               pbn_b0_8_1843200_200 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_485, 0, 0,
+               pbn_b0_2_1843200_200 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_485, 0, 0,
+               pbn_b0_4_1843200_200 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_485, 0, 0,
+               pbn_b0_8_1843200_200 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
+               PCI_VENDOR_ID_IBM, PCI_SUBDEVICE_ID_IBM_SATURN_SERIAL_ONE_PORT,
+               0, 0, pbn_exar_ibm_saturn },
+
+       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_1_115200 },
+       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_2_115200 },
+       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_4_115200 },
+       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_2_115200 },
+       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_4_115200 },
+       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_8_115200 },
+       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_7803,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_8_460800 },
+       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM8,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_8_115200 },
+
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_2_115200 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_2_921600 },
+       /*
+        * VScom SPCOM800, from sl@s.pl
+        */
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_8_921600 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_4_921600 },
+       /* Unknown card - subdevice 0x1584 */
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_VENDOR_ID_PLX,
+               PCI_SUBDEVICE_ID_UNKNOWN_0x1584, 0, 0,
+               pbn_b0_4_115200 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_KEYSPAN,
+               PCI_SUBDEVICE_ID_KEYSPAN_SX2, 0, 0,
+               pbn_panacom },
+       {       PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_panacom4 },
+       {       PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_panacom2 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+               PCI_VENDOR_ID_ESDGMBH,
+               PCI_DEVICE_ID_ESDGMBH_CPCIASIO4, 0, 0,
+               pbn_b2_4_115200 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+               PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0,
+               pbn_b2_4_460800 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+               PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0,
+               pbn_b2_8_460800 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+               PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0,
+               pbn_b2_16_460800 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+               PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0,
+               pbn_b2_16_460800 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_CHASE_PCIRAS,
+               PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0,
+               pbn_b2_4_460800 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_CHASE_PCIRAS,
+               PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0,
+               pbn_b2_8_460800 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_EXSYS,
+               PCI_SUBDEVICE_ID_EXSYS_4055, 0, 0,
+               pbn_exsys_4055 },
+       /*
+        * Megawolf Romulus PCI Serial Card, from Mike Hudson
+        * (Exoray@isys.ca)
+        */
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS,
+               0x10b5, 0x106a, 0, 0,
+               pbn_plx_romulus },
+       {       PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_4_115200 },
+       {       PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_2_115200 },
+       {       PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_8_115200 },
+       {       PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_8_115200 },
+       {       PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954,
+               PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4,
+               0, 0,
+               pbn_b0_4_921600 },
+       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+               PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL,
+               0, 0,
+               pbn_b0_4_1152000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0x9505,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_921600 },
+
+               /*
+                * The below card is a little controversial since it is the
+                * subject of a PCI vendor/device ID clash.  (See
+                * www.ussg.iu.edu/hypermail/linux/kernel/0303.1/0516.html).
+                * For now just used the hex ID 0x950a.
+                */
+       {       PCI_VENDOR_ID_OXSEMI, 0x950a,
+               PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_SERIAL, 0, 0,
+               pbn_b0_2_115200 },
+       {       PCI_VENDOR_ID_OXSEMI, 0x950a,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_2_1130000 },
+       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_C950,
+               PCI_VENDOR_ID_OXSEMI, PCI_SUBDEVICE_ID_OXSEMI_C950, 0, 0,
+               pbn_b0_1_921600 },
+       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_4_115200 },
+       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_921600 },
+       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI958,
+               PCI_ANY_ID , PCI_ANY_ID, 0, 0,
+               pbn_b2_8_1152000 },
+
+       /*
+        * Oxford Semiconductor Inc. Tornado PCI express device range.
+        */
+       {       PCI_VENDOR_ID_OXSEMI, 0xc101,    /* OXPCIe952 1 Legacy UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc105,    /* OXPCIe952 1 Legacy UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc11b,    /* OXPCIe952 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc11f,    /* OXPCIe952 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc120,    /* OXPCIe952 1 Legacy UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc124,    /* OXPCIe952 1 Legacy UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc138,    /* OXPCIe952 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc13d,    /* OXPCIe952 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc140,    /* OXPCIe952 1 Legacy UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc141,    /* OXPCIe952 1 Legacy UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc144,    /* OXPCIe952 1 Legacy UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc145,    /* OXPCIe952 1 Legacy UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc158,    /* OXPCIe952 2 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_2_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc15d,    /* OXPCIe952 2 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_2_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc208,    /* OXPCIe954 4 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_4_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc20d,    /* OXPCIe954 4 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_4_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc308,    /* OXPCIe958 8 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_8_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc30d,    /* OXPCIe958 8 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_8_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc40b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc40f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc41b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc41f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc42b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc42f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc43b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc43f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc44b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc44f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc45b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc45f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc46b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc46f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc47b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc47f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc48b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc48f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc49b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc49f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc4ab,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc4af,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc4bb,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc4bf,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc4cb,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc4cf,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       /*
+        * Mainpine Inc. IQ Express "Rev3" utilizing OxSemi Tornado
+        */
+       {       PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 1 Port V.34 Super-G3 Fax */
+               PCI_VENDOR_ID_MAINPINE, 0x4001, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 2 Port V.34 Super-G3 Fax */
+               PCI_VENDOR_ID_MAINPINE, 0x4002, 0, 0,
+               pbn_oxsemi_2_4000000 },
+       {       PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 4 Port V.34 Super-G3 Fax */
+               PCI_VENDOR_ID_MAINPINE, 0x4004, 0, 0,
+               pbn_oxsemi_4_4000000 },
+       {       PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 8 Port V.34 Super-G3 Fax */
+               PCI_VENDOR_ID_MAINPINE, 0x4008, 0, 0,
+               pbn_oxsemi_8_4000000 },
+       /*
+        * SBS Technologies, Inc. P-Octal and PMC-OCTPRO cards,
+        * from skokodyn@yahoo.com
+        */
+       {       PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
+               PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_OCTPRO232, 0, 0,
+               pbn_sbsxrsio },
+       {       PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
+               PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_OCTPRO422, 0, 0,
+               pbn_sbsxrsio },
+       {       PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
+               PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_POCTAL232, 0, 0,
+               pbn_sbsxrsio },
+       {       PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
+               PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_POCTAL422, 0, 0,
+               pbn_sbsxrsio },
+
+       /*
+        * Digitan DS560-558, from jimd@esoft.com
+        */
+       {       PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_1_115200 },
+
+       /*
+        * Titan Electronic cards
+        *  The 400L and 800L have a custom setup quirk.
+        */
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_2_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_4_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_4_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100L,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_1_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200L,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_bt_2_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400L,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_4_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800L,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_8_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200I,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b4_bt_2_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400I,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b4_bt_4_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800I,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b4_bt_8_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400EH,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_4_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800EH,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_4_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800EHB,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_4_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100E,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200E,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_2_4000000 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400E,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_4_4000000 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800E,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_8_4000000 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EI,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_2_4000000 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_2_4000000 },
+
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_1_460800 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_1_460800 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_1_460800 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_2_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_2_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_2_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_4_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_4_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_4_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_4_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_4_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_4_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_8_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_8_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_8_921600 },
+
+       /*
+        * Computone devices submitted by Doug McNash dmcnash@computone.com
+        */
+       {       PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+               PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4,
+               0, 0, pbn_computone_4 },
+       {       PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+               PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8,
+               0, 0, pbn_computone_8 },
+       {       PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+               PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6,
+               0, 0, pbn_computone_6 },
+
+       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi },
+       {       PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889,
+               PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_1_921600 },
+
+       /*
+        * AFAVLAB serial card, from Harald Welte <laforge@gnumonks.org>
+        */
+       {       PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P028,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_8_115200 },
+       {       PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P030,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_8_115200 },
+
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_115200 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_115200 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_115200 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATTRO_A,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_115200 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATTRO_B,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_115200 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_A,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_4_460800 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_B,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_4_460800 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_460800 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_460800 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_460800 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_1_115200 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_1_460800 },
+
+       /*
+        * Korenix Jetcard F0/F1 cards (JC1204, JC1208, JC1404, JC1408).
+        * Cards are identified by their subsystem vendor IDs, which
+        * (in hex) match the model number.
+        *
+        * Note that JC140x are RS422/485 cards which require ox950
+        * ACR = 0x10, and as such are not currently fully supported.
+        */
+       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
+               0x1204, 0x0004, 0, 0,
+               pbn_b0_4_921600 },
+       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
+               0x1208, 0x0004, 0, 0,
+               pbn_b0_4_921600 },
+/*     {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
+               0x1402, 0x0002, 0, 0,
+               pbn_b0_2_921600 }, */
+/*     {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
+               0x1404, 0x0004, 0, 0,
+               pbn_b0_4_921600 }, */
+       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF1,
+               0x1208, 0x0004, 0, 0,
+               pbn_b0_4_921600 },
+
+       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF2,
+               0x1204, 0x0004, 0, 0,
+               pbn_b0_4_921600 },
+       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF2,
+               0x1208, 0x0004, 0, 0,
+               pbn_b0_4_921600 },
+       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF3,
+               0x1208, 0x0004, 0, 0,
+               pbn_b0_4_921600 },
+       /*
+        * Dell Remote Access Card 4 - Tim_T_Murphy@Dell.com
+        */
+       {       PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_RAC4,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_1_1382400 },
+
+       /*
+        * Dell Remote Access Card III - Tim_T_Murphy@Dell.com
+        */
+       {       PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_RACIII,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_1_1382400 },
+
+       /*
+        * RAStel 2 port modem, gerg@moreton.com.au
+        */
+       {       PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_2_115200 },
+
+       /*
+        * EKF addition for i960 Boards form EKF with serial port
+        */
+       {       PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80960_RP,
+               0xE4BF, PCI_ANY_ID, 0, 0,
+               pbn_intel_i960 },
+
+       /*
+        * Xircom Cardbus/Ethernet combos
+        */
+       {       PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_X3201_MDM,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_115200 },
+       /*
+        * Xircom RBM56G cardbus modem - Dirk Arnold (temp entry)
+        */
+       {       PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_RBM56G,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_115200 },
+
+       /*
+        * Untested PCI modems, sent in from various folks...
+        */
+
+       /*
+        * Elsa Model 56K PCI Modem, from Andreas Rath <arh@01019freenet.de>
+        */
+       {       PCI_VENDOR_ID_ROCKWELL, 0x1004,
+               0x1048, 0x1500, 0, 0,
+               pbn_b1_1_115200 },
+
+       {       PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
+               0xFF00, 0, 0, 0,
+               pbn_sgi_ioc3 },
+
+       /*
+        * HP Diva card
+        */
+       {       PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA,
+               PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_RMP3, 0, 0,
+               pbn_b1_1_115200 },
+       {       PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_5_115200 },
+       {       PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_AUX,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_1_115200 },
+
+       {       PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM2,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b3_2_115200 },
+       {       PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM4,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b3_4_115200 },
+       {       PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b3_8_115200 },
+
+       /*
+        * Exar Corp. XR17C15[248] Dual/Quad/Octal UART
+        */
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0,
+               0, pbn_exar_XR17C152 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0,
+               0, pbn_exar_XR17C154 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0,
+               0, pbn_exar_XR17C158 },
+
+       /*
+        * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke)
+        */
+       {       PCI_VENDOR_ID_TOPIC, PCI_DEVICE_ID_TOPIC_TP560,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_115200 },
+       /*
+        * ITE
+        */
+       {       PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8872,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b1_bt_1_115200 },
+
+       /*
+        * IntaShield IS-200
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS200,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,   /* 135a.0811 */
+               pbn_b2_2_115200 },
+       /*
+        * IntaShield IS-400
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS400,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,    /* 135a.0dc0 */
+               pbn_b2_4_115200 },
+       /*
+        * Perle PCI-RAS cards
+        */
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+               PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS4,
+               0, 0, pbn_b2_4_921600 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+               PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS8,
+               0, 0, pbn_b2_8_921600 },
+
+       /*
+        * Mainpine series cards: Fairly standard layout but fools
+        * parts of the autodetect in some cases and uses otherwise
+        * unmatched communications subclasses in the PCI Express case
+        */
+
+       {       /* RockForceDUO */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x0200,
+               0, 0, pbn_b0_2_115200 },
+       {       /* RockForceQUATRO */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x0300,
+               0, 0, pbn_b0_4_115200 },
+       {       /* RockForceDUO+ */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x0400,
+               0, 0, pbn_b0_2_115200 },
+       {       /* RockForceQUATRO+ */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x0500,
+               0, 0, pbn_b0_4_115200 },
+       {       /* RockForce+ */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x0600,
+               0, 0, pbn_b0_2_115200 },
+       {       /* RockForce+ */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x0700,
+               0, 0, pbn_b0_4_115200 },
+       {       /* RockForceOCTO+ */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x0800,
+               0, 0, pbn_b0_8_115200 },
+       {       /* RockForceDUO+ */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x0C00,
+               0, 0, pbn_b0_2_115200 },
+       {       /* RockForceQUARTRO+ */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x0D00,
+               0, 0, pbn_b0_4_115200 },
+       {       /* RockForceOCTO+ */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x1D00,
+               0, 0, pbn_b0_8_115200 },
+       {       /* RockForceD1 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x2000,
+               0, 0, pbn_b0_1_115200 },
+       {       /* RockForceF1 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x2100,
+               0, 0, pbn_b0_1_115200 },
+       {       /* RockForceD2 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x2200,
+               0, 0, pbn_b0_2_115200 },
+       {       /* RockForceF2 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x2300,
+               0, 0, pbn_b0_2_115200 },
+       {       /* RockForceD4 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x2400,
+               0, 0, pbn_b0_4_115200 },
+       {       /* RockForceF4 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x2500,
+               0, 0, pbn_b0_4_115200 },
+       {       /* RockForceD8 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x2600,
+               0, 0, pbn_b0_8_115200 },
+       {       /* RockForceF8 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x2700,
+               0, 0, pbn_b0_8_115200 },
+       {       /* IQ Express D1 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x3000,
+               0, 0, pbn_b0_1_115200 },
+       {       /* IQ Express F1 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x3100,
+               0, 0, pbn_b0_1_115200 },
+       {       /* IQ Express D2 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x3200,
+               0, 0, pbn_b0_2_115200 },
+       {       /* IQ Express F2 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x3300,
+               0, 0, pbn_b0_2_115200 },
+       {       /* IQ Express D4 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x3400,
+               0, 0, pbn_b0_4_115200 },
+       {       /* IQ Express F4 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x3500,
+               0, 0, pbn_b0_4_115200 },
+       {       /* IQ Express D8 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x3C00,
+               0, 0, pbn_b0_8_115200 },
+       {       /* IQ Express F8 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x3D00,
+               0, 0, pbn_b0_8_115200 },
+
+
+       /*
+        * PA Semi PA6T-1682M on-chip UART
+        */
+       {       PCI_VENDOR_ID_PASEMI, 0xa004,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pasemi_1682M },
+
+       /*
+        * National Instruments
+        */
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI23216,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_16_115200 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2328,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_8_115200 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2324,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_bt_4_115200 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2322,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_bt_2_115200 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2324I,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_bt_4_115200 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2322I,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_bt_2_115200 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_23216,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_16_115200 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2328,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_8_115200 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2324,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_bt_4_115200 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2322,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_bt_2_115200 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8422_2324,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_bt_4_115200 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8422_2322,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_bt_2_115200 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2322,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_ni8430_2 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2322,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_ni8430_2 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2324,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_ni8430_4 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2324,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_ni8430_4 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2328,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_ni8430_8 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2328,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_ni8430_8 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_23216,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_ni8430_16 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_23216,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_ni8430_16 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8432_2322,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_ni8430_2 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8432_2322,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_ni8430_2 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8432_2324,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_ni8430_4 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8432_2324,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_ni8430_4 },
+
+       /*
+       * ADDI-DATA GmbH communication cards <info@addi-data.com>
+       */
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7500,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_4_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7420,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_2_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7300,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_1_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA_OLD,
+               PCI_DEVICE_ID_ADDIDATA_APCI7800,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b1_8_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7500_2,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_4_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7420_2,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_2_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7300_2,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_1_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7500_3,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_4_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7420_3,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_2_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7300_3,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_1_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7800_3,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_8_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCIe7500,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_ADDIDATA_PCIe_4_3906250 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCIe7420,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_ADDIDATA_PCIe_2_3906250 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCIe7300,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_ADDIDATA_PCIe_1_3906250 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCIe7800,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_ADDIDATA_PCIe_8_3906250 },
+
+       {       PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835,
+               PCI_VENDOR_ID_IBM, 0x0299,
+               0, 0, pbn_b0_bt_2_115200 },
+
+       {       PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901,
+               0xA000, 0x1000,
+               0, 0, pbn_b0_1_115200 },
+
+       /*
+        * Best Connectivity PCI Multi I/O cards
+        */
+
+       {       PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
+               0xA000, 0x1000,
+               0, 0, pbn_b0_1_115200 },
+
+       {       PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
+               0xA000, 0x3004,
+               0, 0, pbn_b0_bt_4_115200 },
+       /* Intel CE4100 */
+       {       PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CE4100_UART,
+               PCI_ANY_ID,  PCI_ANY_ID, 0, 0,
+               pbn_ce4100_1_115200 },
+
+
+       /*
+        * These entries match devices with class COMMUNICATION_SERIAL,
+        * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
+        */
+       {       PCI_ANY_ID, PCI_ANY_ID,
+               PCI_ANY_ID, PCI_ANY_ID,
+               PCI_CLASS_COMMUNICATION_SERIAL << 8,
+               0xffff00, pbn_default },
+       {       PCI_ANY_ID, PCI_ANY_ID,
+               PCI_ANY_ID, PCI_ANY_ID,
+               PCI_CLASS_COMMUNICATION_MODEM << 8,
+               0xffff00, pbn_default },
+       {       PCI_ANY_ID, PCI_ANY_ID,
+               PCI_ANY_ID, PCI_ANY_ID,
+               PCI_CLASS_COMMUNICATION_MULTISERIAL << 8,
+               0xffff00, pbn_default },
+       { 0, }
+};
+
+static struct pci_driver serial_pci_driver = {
+       .name           = "serial",
+       .probe          = pciserial_init_one,
+       .remove         = __devexit_p(pciserial_remove_one),
+#ifdef CONFIG_PM
+       .suspend        = pciserial_suspend_one,
+       .resume         = pciserial_resume_one,
+#endif
+       .id_table       = serial_pci_tbl,
+};
+
+static int __init serial8250_pci_init(void)
+{
+       return pci_register_driver(&serial_pci_driver);
+}
+
+static void __exit serial8250_pci_exit(void)
+{
+       pci_unregister_driver(&serial_pci_driver);
+}
+
+module_init(serial8250_pci_init);
+module_exit(serial8250_pci_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic 8250/16x50 PCI serial probe module");
+MODULE_DEVICE_TABLE(pci, serial_pci_tbl);
diff --git a/drivers/tty/serial/8250_pnp.c b/drivers/tty/serial/8250_pnp.c
new file mode 100644 (file)
index 0000000..4822cb5
--- /dev/null
@@ -0,0 +1,523 @@
+/*
+ *  linux/drivers/char/8250_pnp.c
+ *
+ *  Probe module for 8250/16550-type ISAPNP serial ports.
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ *  Copyright (C) 2001 Russell King, All Rights Reserved.
+ *
+ *  Ported to the Linux PnP Layer - (C) Adam Belay.
+ *
+ * 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.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pnp.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/serial_core.h>
+#include <linux/bitops.h>
+
+#include <asm/byteorder.h>
+
+#include "8250.h"
+
+#define UNKNOWN_DEV 0x3000
+
+
+static const struct pnp_device_id pnp_dev_table[] = {
+       /* Archtek America Corp. */
+       /* Archtek SmartLink Modem 3334BT Plug & Play */
+       {       "AAC000F",              0       },
+       /* Anchor Datacomm BV */
+       /* SXPro 144 External Data Fax Modem Plug & Play */
+       {       "ADC0001",              0       },
+       /* SXPro 288 External Data Fax Modem Plug & Play */
+       {       "ADC0002",              0       },
+       /* PROLiNK 1456VH ISA PnP K56flex Fax Modem */
+       {       "AEI0250",              0       },
+       /* Actiontec ISA PNP 56K X2 Fax Modem */
+       {       "AEI1240",              0       },
+       /* Rockwell 56K ACF II Fax+Data+Voice Modem */
+       {       "AKY1021",              0 /*SPCI_FL_NO_SHIRQ*/  },
+       /* AZT3005 PnP SOUND DEVICE */
+       {       "AZT4001",              0       },
+       /* Best Data Products Inc. Smart One 336F PnP Modem */
+       {       "BDP3336",              0       },
+       /*  Boca Research */
+       /* Boca Complete Ofc Communicator 14.4 Data-FAX */
+       {       "BRI0A49",              0       },
+       /* Boca Research 33,600 ACF Modem */
+       {       "BRI1400",              0       },
+       /* Boca 33.6 Kbps Internal FD34FSVD */
+       {       "BRI3400",              0       },
+       /* Boca 33.6 Kbps Internal FD34FSVD */
+       {       "BRI0A49",              0       },
+       /* Best Data Products Inc. Smart One 336F PnP Modem */
+       {       "BDP3336",              0       },
+       /* Computer Peripherals Inc */
+       /* EuroViVa CommCenter-33.6 SP PnP */
+       {       "CPI4050",              0       },
+       /* Creative Labs */
+       /* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */
+       {       "CTL3001",              0       },
+       /* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */
+       {       "CTL3011",              0       },
+       /* Davicom ISA 33.6K Modem */
+       {       "DAV0336",              0       },
+       /* Creative */
+       /* Creative Modem Blaster Flash56 DI5601-1 */
+       {       "DMB1032",              0       },
+       /* Creative Modem Blaster V.90 DI5660 */
+       {       "DMB2001",              0       },
+       /* E-Tech */
+       /* E-Tech CyberBULLET PC56RVP */
+       {       "ETT0002",              0       },
+       /* FUJITSU */
+       /* Fujitsu 33600 PnP-I2 R Plug & Play */
+       {       "FUJ0202",              0       },
+       /* Fujitsu FMV-FX431 Plug & Play */
+       {       "FUJ0205",              0       },
+       /* Fujitsu 33600 PnP-I4 R Plug & Play */
+       {       "FUJ0206",              0       },
+       /* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */
+       {       "FUJ0209",              0       },
+       /* Archtek America Corp. */
+       /* Archtek SmartLink Modem 3334BT Plug & Play */
+       {       "GVC000F",              0       },
+       /* Archtek SmartLink Modem 3334BRV 33.6K Data Fax Voice */
+       {       "GVC0303",              0       },
+       /* Hayes */
+       /* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */
+       {       "HAY0001",              0       },
+       /* Hayes Optima 336 V.34 + FAX + Voice PnP */
+       {       "HAY000C",              0       },
+       /* Hayes Optima 336B V.34 + FAX + Voice PnP */
+       {       "HAY000D",              0       },
+       /* Hayes Accura 56K Ext Fax Modem PnP */
+       {       "HAY5670",              0       },
+       /* Hayes Accura 56K Ext Fax Modem PnP */
+       {       "HAY5674",              0       },
+       /* Hayes Accura 56K Fax Modem PnP */
+       {       "HAY5675",              0       },
+       /* Hayes 288, V.34 + FAX */
+       {       "HAYF000",              0       },
+       /* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */
+       {       "HAYF001",              0       },
+       /* IBM */
+       /* IBM Thinkpad 701 Internal Modem Voice */
+       {       "IBM0033",              0       },
+       /* Intertex */
+       /* Intertex 28k8 33k6 Voice EXT PnP */
+       {       "IXDC801",              0       },
+       /* Intertex 33k6 56k Voice EXT PnP */
+       {       "IXDC901",              0       },
+       /* Intertex 28k8 33k6 Voice SP EXT PnP */
+       {       "IXDD801",              0       },
+       /* Intertex 33k6 56k Voice SP EXT PnP */
+       {       "IXDD901",              0       },
+       /* Intertex 28k8 33k6 Voice SP INT PnP */
+       {       "IXDF401",              0       },
+       /* Intertex 28k8 33k6 Voice SP EXT PnP */
+       {       "IXDF801",              0       },
+       /* Intertex 33k6 56k Voice SP EXT PnP */
+       {       "IXDF901",              0       },
+       /* Kortex International */
+       /* KORTEX 28800 Externe PnP */
+       {       "KOR4522",              0       },
+       /* KXPro 33.6 Vocal ASVD PnP */
+       {       "KORF661",              0       },
+       /* Lasat */
+       /* LASAT Internet 33600 PnP */
+       {       "LAS4040",              0       },
+       /* Lasat Safire 560 PnP */
+       {       "LAS4540",              0       },
+       /* Lasat Safire 336  PnP */
+       {       "LAS5440",              0       },
+       /* Microcom, Inc. */
+       /* Microcom TravelPorte FAST V.34 Plug & Play */
+       {       "MNP0281",              0       },
+       /* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */
+       {       "MNP0336",              0       },
+       /* Microcom DeskPorte FAST EP 28.8 Plug & Play */
+       {       "MNP0339",              0       },
+       /* Microcom DeskPorte 28.8P Plug & Play */
+       {       "MNP0342",              0       },
+       /* Microcom DeskPorte FAST ES 28.8 Plug & Play */
+       {       "MNP0500",              0       },
+       /* Microcom DeskPorte FAST ES 28.8 Plug & Play */
+       {       "MNP0501",              0       },
+       /* Microcom DeskPorte 28.8S Internal Plug & Play */
+       {       "MNP0502",              0       },
+       /* Motorola */
+       /* Motorola BitSURFR Plug & Play */
+       {       "MOT1105",              0       },
+       /* Motorola TA210 Plug & Play */
+       {       "MOT1111",              0       },
+       /* Motorola HMTA 200 (ISDN) Plug & Play */
+       {       "MOT1114",              0       },
+       /* Motorola BitSURFR Plug & Play */
+       {       "MOT1115",              0       },
+       /* Motorola Lifestyle 28.8 Internal */
+       {       "MOT1190",              0       },
+       /* Motorola V.3400 Plug & Play */
+       {       "MOT1501",              0       },
+       /* Motorola Lifestyle 28.8 V.34 Plug & Play */
+       {       "MOT1502",              0       },
+       /* Motorola Power 28.8 V.34 Plug & Play */
+       {       "MOT1505",              0       },
+       /* Motorola ModemSURFR External 28.8 Plug & Play */
+       {       "MOT1509",              0       },
+       /* Motorola Premier 33.6 Desktop Plug & Play */
+       {       "MOT150A",              0       },
+       /* Motorola VoiceSURFR 56K External PnP */
+       {       "MOT150F",              0       },
+       /* Motorola ModemSURFR 56K External PnP */
+       {       "MOT1510",              0       },
+       /* Motorola ModemSURFR 56K Internal PnP */
+       {       "MOT1550",              0       },
+       /* Motorola ModemSURFR Internal 28.8 Plug & Play */
+       {       "MOT1560",              0       },
+       /* Motorola Premier 33.6 Internal Plug & Play */
+       {       "MOT1580",              0       },
+       /* Motorola OnlineSURFR 28.8 Internal Plug & Play */
+       {       "MOT15B0",              0       },
+       /* Motorola VoiceSURFR 56K Internal PnP */
+       {       "MOT15F0",              0       },
+       /* Com 1 */
+       /*  Deskline K56 Phone System PnP */
+       {       "MVX00A1",              0       },
+       /* PC Rider K56 Phone System PnP */
+       {       "MVX00F2",              0       },
+       /* NEC 98NOTE SPEAKER PHONE FAX MODEM(33600bps) */
+       {       "nEC8241",              0       },
+       /* Pace 56 Voice Internal Plug & Play Modem */
+       {       "PMC2430",              0       },
+       /* Generic */
+       /* Generic standard PC COM port  */
+       {       "PNP0500",              0       },
+       /* Generic 16550A-compatible COM port */
+       {       "PNP0501",              0       },
+       /* Compaq 14400 Modem */
+       {       "PNPC000",              0       },
+       /* Compaq 2400/9600 Modem */
+       {       "PNPC001",              0       },
+       /* Dial-Up Networking Serial Cable between 2 PCs */
+       {       "PNPC031",              0       },
+       /* Dial-Up Networking Parallel Cable between 2 PCs */
+       {       "PNPC032",              0       },
+       /* Standard 9600 bps Modem */
+       {       "PNPC100",              0       },
+       /* Standard 14400 bps Modem */
+       {       "PNPC101",              0       },
+       /*  Standard 28800 bps Modem*/
+       {       "PNPC102",              0       },
+       /*  Standard Modem*/
+       {       "PNPC103",              0       },
+       /*  Standard 9600 bps Modem*/
+       {       "PNPC104",              0       },
+       /*  Standard 14400 bps Modem*/
+       {       "PNPC105",              0       },
+       /*  Standard 28800 bps Modem*/
+       {       "PNPC106",              0       },
+       /*  Standard Modem */
+       {       "PNPC107",              0       },
+       /* Standard 9600 bps Modem */
+       {       "PNPC108",              0       },
+       /* Standard 14400 bps Modem */
+       {       "PNPC109",              0       },
+       /* Standard 28800 bps Modem */
+       {       "PNPC10A",              0       },
+       /* Standard Modem */
+       {       "PNPC10B",              0       },
+       /* Standard 9600 bps Modem */
+       {       "PNPC10C",              0       },
+       /* Standard 14400 bps Modem */
+       {       "PNPC10D",              0       },
+       /* Standard 28800 bps Modem */
+       {       "PNPC10E",              0       },
+       /* Standard Modem */
+       {       "PNPC10F",              0       },
+       /* Standard PCMCIA Card Modem */
+       {       "PNP2000",              0       },
+       /* Rockwell */
+       /* Modular Technology */
+       /* Rockwell 33.6 DPF Internal PnP */
+       /* Modular Technology 33.6 Internal PnP */
+       {       "ROK0030",              0       },
+       /* Kortex International */
+       /* KORTEX 14400 Externe PnP */
+       {       "ROK0100",              0       },
+       /* Rockwell 28.8 */
+       {       "ROK4120",              0       },
+       /* Viking Components, Inc */
+       /* Viking 28.8 INTERNAL Fax+Data+Voice PnP */
+       {       "ROK4920",              0       },
+       /* Rockwell */
+       /* British Telecom */
+       /* Modular Technology */
+       /* Rockwell 33.6 DPF External PnP */
+       /* BT Prologue 33.6 External PnP */
+       /* Modular Technology 33.6 External PnP */
+       {       "RSS00A0",              0       },
+       /* Viking 56K FAX INT */
+       {       "RSS0262",              0       },
+       /* K56 par,VV,Voice,Speakphone,AudioSpan,PnP */
+       {       "RSS0250",              0       },
+       /* SupraExpress 28.8 Data/Fax PnP modem */
+       {       "SUP1310",              0       },
+       /* SupraExpress 336i PnP Voice Modem */
+       {       "SUP1381",              0       },
+       /* SupraExpress 33.6 Data/Fax PnP modem */
+       {       "SUP1421",              0       },
+       /* SupraExpress 33.6 Data/Fax PnP modem */
+       {       "SUP1590",              0       },
+       /* SupraExpress 336i Sp ASVD */
+       {       "SUP1620",              0       },
+       /* SupraExpress 33.6 Data/Fax PnP modem */
+       {       "SUP1760",              0       },
+       /* SupraExpress 56i Sp Intl */
+       {       "SUP2171",              0       },
+       /* Phoebe Micro */
+       /* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */
+       {       "TEX0011",              0       },
+       /* Archtek America Corp. */
+       /* Archtek SmartLink Modem 3334BT Plug & Play */
+       {       "UAC000F",              0       },
+       /* 3Com Corp. */
+       /* Gateway Telepath IIvi 33.6 */
+       {       "USR0000",              0       },
+       /* U.S. Robotics Sporster 33.6K Fax INT PnP */
+       {       "USR0002",              0       },
+       /*  Sportster Vi 14.4 PnP FAX Voicemail */
+       {       "USR0004",              0       },
+       /* U.S. Robotics 33.6K Voice INT PnP */
+       {       "USR0006",              0       },
+       /* U.S. Robotics 33.6K Voice EXT PnP */
+       {       "USR0007",              0       },
+       /* U.S. Robotics Courier V.Everything INT PnP */
+       {       "USR0009",              0       },
+       /* U.S. Robotics 33.6K Voice INT PnP */
+       {       "USR2002",              0       },
+       /* U.S. Robotics 56K Voice INT PnP */
+       {       "USR2070",              0       },
+       /* U.S. Robotics 56K Voice EXT PnP */
+       {       "USR2080",              0       },
+       /* U.S. Robotics 56K FAX INT */
+       {       "USR3031",              0       },
+       /* U.S. Robotics 56K FAX INT */
+       {       "USR3050",              0       },
+       /* U.S. Robotics 56K Voice INT PnP */
+       {       "USR3070",              0       },
+       /* U.S. Robotics 56K Voice EXT PnP */
+       {       "USR3080",              0       },
+       /* U.S. Robotics 56K Voice INT PnP */
+       {       "USR3090",              0       },
+       /* U.S. Robotics 56K Message  */
+       {       "USR9100",              0       },
+       /* U.S. Robotics 56K FAX EXT PnP*/
+       {       "USR9160",              0       },
+       /* U.S. Robotics 56K FAX INT PnP*/
+       {       "USR9170",              0       },
+       /* U.S. Robotics 56K Voice EXT PnP*/
+       {       "USR9180",              0       },
+       /* U.S. Robotics 56K Voice INT PnP*/
+       {       "USR9190",              0       },
+       /* Wacom tablets */
+       {       "WACFXXX",              0       },
+       /* Compaq touchscreen */
+       {       "FPI2002",              0 },
+       /* Fujitsu Stylistic touchscreens */
+       {       "FUJ02B2",              0 },
+       {       "FUJ02B3",              0 },
+       /* Fujitsu Stylistic LT touchscreens */
+       {       "FUJ02B4",              0 },
+       /* Passive Fujitsu Stylistic touchscreens */
+       {       "FUJ02B6",              0 },
+       {       "FUJ02B7",              0 },
+       {       "FUJ02B8",              0 },
+       {       "FUJ02B9",              0 },
+       {       "FUJ02BC",              0 },
+       /* Fujitsu Wacom Tablet PC device */
+       {       "FUJ02E5",              0       },
+       /* Fujitsu P-series tablet PC device */
+       {       "FUJ02E6",              0       },
+       /* Fujitsu Wacom 2FGT Tablet PC device */
+       {       "FUJ02E7",              0       },
+       /* Fujitsu Wacom 1FGT Tablet PC device */
+       {       "FUJ02E9",              0       },
+       /*
+        * LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6 in
+        * disguise)
+        */
+       {       "LTS0001",              0       },
+       /* Rockwell's (PORALiNK) 33600 INT PNP */
+       {       "WCI0003",              0       },
+       /* Unknown PnP modems */
+       {       "PNPCXXX",              UNKNOWN_DEV     },
+       /* More unknown PnP modems */
+       {       "PNPDXXX",              UNKNOWN_DEV     },
+       {       "",                     0       }
+};
+
+MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
+
+static char *modem_names[] __devinitdata = {
+       "MODEM", "Modem", "modem", "FAX", "Fax", "fax",
+       "56K", "56k", "K56", "33.6", "28.8", "14.4",
+       "33,600", "28,800", "14,400", "33.600", "28.800", "14.400",
+       "33600", "28800", "14400", "V.90", "V.34", "V.32", NULL
+};
+
+static int __devinit check_name(char *name)
+{
+       char **tmp;
+
+       for (tmp = modem_names; *tmp; tmp++)
+               if (strstr(name, *tmp))
+                       return 1;
+
+       return 0;
+}
+
+static int __devinit check_resources(struct pnp_dev *dev)
+{
+       resource_size_t base[] = {0x2f8, 0x3f8, 0x2e8, 0x3e8};
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(base); i++) {
+               if (pnp_possible_config(dev, IORESOURCE_IO, base[i], 8))
+                       return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * Given a complete unknown PnP device, try to use some heuristics to
+ * detect modems. Currently use such heuristic set:
+ *     - dev->name or dev->bus->name must contain "modem" substring;
+ *     - device must have only one IO region (8 byte long) with base address
+ *       0x2e8, 0x3e8, 0x2f8 or 0x3f8.
+ *
+ * Such detection looks very ugly, but can detect at least some of numerous
+ * PnP modems, alternatively we must hardcode all modems in pnp_devices[]
+ * table.
+ */
+static int __devinit serial_pnp_guess_board(struct pnp_dev *dev, int *flags)
+{
+       if (!(check_name(pnp_dev_name(dev)) ||
+               (dev->card && check_name(dev->card->name))))
+                       return -ENODEV;
+
+       if (check_resources(dev))
+               return 0;
+
+       return -ENODEV;
+}
+
+static int __devinit
+serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
+{
+       struct uart_port port;
+       int ret, line, flags = dev_id->driver_data;
+
+       if (flags & UNKNOWN_DEV) {
+               ret = serial_pnp_guess_board(dev, &flags);
+               if (ret < 0)
+                       return ret;
+       }
+
+       memset(&port, 0, sizeof(struct uart_port));
+       if (pnp_irq_valid(dev, 0))
+               port.irq = pnp_irq(dev, 0);
+       if (pnp_port_valid(dev, 0)) {
+               port.iobase = pnp_port_start(dev, 0);
+               port.iotype = UPIO_PORT;
+       } else if (pnp_mem_valid(dev, 0)) {
+               port.mapbase = pnp_mem_start(dev, 0);
+               port.iotype = UPIO_MEM;
+               port.flags = UPF_IOREMAP;
+       } else
+               return -ENODEV;
+
+#ifdef SERIAL_DEBUG_PNP
+       printk(KERN_DEBUG
+               "Setup PNP port: port %x, mem 0x%lx, irq %d, type %d\n",
+                      port.iobase, port.mapbase, port.irq, port.iotype);
+#endif
+
+       port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
+       if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE)
+               port.flags |= UPF_SHARE_IRQ;
+       port.uartclk = 1843200;
+       port.dev = &dev->dev;
+
+       line = serial8250_register_port(&port);
+       if (line < 0)
+               return -ENODEV;
+
+       pnp_set_drvdata(dev, (void *)((long)line + 1));
+       return 0;
+}
+
+static void __devexit serial_pnp_remove(struct pnp_dev *dev)
+{
+       long line = (long)pnp_get_drvdata(dev);
+       if (line)
+               serial8250_unregister_port(line - 1);
+}
+
+#ifdef CONFIG_PM
+static int serial_pnp_suspend(struct pnp_dev *dev, pm_message_t state)
+{
+       long line = (long)pnp_get_drvdata(dev);
+
+       if (!line)
+               return -ENODEV;
+       serial8250_suspend_port(line - 1);
+       return 0;
+}
+
+static int serial_pnp_resume(struct pnp_dev *dev)
+{
+       long line = (long)pnp_get_drvdata(dev);
+
+       if (!line)
+               return -ENODEV;
+       serial8250_resume_port(line - 1);
+       return 0;
+}
+#else
+#define serial_pnp_suspend NULL
+#define serial_pnp_resume NULL
+#endif /* CONFIG_PM */
+
+static struct pnp_driver serial_pnp_driver = {
+       .name           = "serial",
+       .probe          = serial_pnp_probe,
+       .remove         = __devexit_p(serial_pnp_remove),
+       .suspend        = serial_pnp_suspend,
+       .resume         = serial_pnp_resume,
+       .id_table       = pnp_dev_table,
+};
+
+static int __init serial8250_pnp_init(void)
+{
+       return pnp_register_driver(&serial_pnp_driver);
+}
+
+static void __exit serial8250_pnp_exit(void)
+{
+       pnp_unregister_driver(&serial_pnp_driver);
+}
+
+module_init(serial8250_pnp_init);
+module_exit(serial8250_pnp_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic 8250/16x50 PnP serial driver");
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
new file mode 100644 (file)
index 0000000..c1df767
--- /dev/null
@@ -0,0 +1,1598 @@
+#
+# Serial device configuration
+#
+
+menu "Serial drivers"
+       depends on HAS_IOMEM
+
+#
+# The new 8250/16550 serial drivers
+config SERIAL_8250
+       tristate "8250/16550 and compatible serial support"
+       select SERIAL_CORE
+       ---help---
+         This selects whether you want to include the driver for the standard
+         serial ports.  The standard answer is Y.  People who might say N
+         here are those that are setting up dedicated Ethernet WWW/FTP
+         servers, or users that have one of the various bus mice instead of a
+         serial mouse and don't intend to use their machine's standard serial
+         port for anything.  (Note that the Cyclades and Stallion multi
+         serial port drivers do not need this driver built in for them to
+         work.)
+
+         To compile this driver as a module, choose M here: the
+         module will be called 8250.
+         [WARNING: Do not compile this driver as a module if you are using
+         non-standard serial ports, since the configuration information will
+         be lost when the driver is unloaded.  This limitation may be lifted
+         in the future.]
+
+         BTW1: If you have a mouseman serial mouse which is not recognized by
+         the X window system, try running gpm first.
+
+         BTW2: If you intend to use a software modem (also called Winmodem)
+         under Linux, forget it.  These modems are crippled and require
+         proprietary drivers which are only available under Windows.
+
+         Most people will say Y or M here, so that they can use serial mice,
+         modems and similar devices connecting to the standard serial ports.
+
+config SERIAL_8250_CONSOLE
+       bool "Console on 8250/16550 and compatible serial port"
+       depends on SERIAL_8250=y
+       select SERIAL_CORE_CONSOLE
+       ---help---
+         If you say Y here, it will be possible to use a serial port as the
+         system console (the system console is the device which receives all
+         kernel messages and warnings and which allows logins in single user
+         mode). This could be useful if some terminal or printer is connected
+         to that serial port.
+
+         Even if you say Y here, the currently visible virtual console
+         (/dev/tty0) will still be used as the system console by default, but
+         you can alter that using a kernel command line option such as
+         "console=ttyS1". (Try "man bootparam" or see the documentation of
+         your boot loader (grub or lilo or loadlin) about how to pass options
+         to the kernel at boot time.)
+
+         If you don't have a VGA card installed and you say Y here, the
+         kernel will automatically use the first serial line, /dev/ttyS0, as
+         system console.
+
+         You can set that using a kernel command line option such as
+         "console=uart8250,io,0x3f8,9600n8"
+         "console=uart8250,mmio,0xff5e0000,115200n8".
+         and it will switch to normal serial console when the corresponding 
+         port is ready.
+         "earlycon=uart8250,io,0x3f8,9600n8"
+         "earlycon=uart8250,mmio,0xff5e0000,115200n8".
+         it will not only setup early console.
+
+         If unsure, say N.
+
+config FIX_EARLYCON_MEM
+       bool
+       depends on X86
+       default y
+
+config SERIAL_8250_GSC
+       tristate
+       depends on SERIAL_8250 && GSC
+       default SERIAL_8250
+
+config SERIAL_8250_PCI
+       tristate "8250/16550 PCI device support" if EMBEDDED
+       depends on SERIAL_8250 && PCI
+       default SERIAL_8250
+       help
+         This builds standard PCI serial support. You may be able to
+         disable this feature if you only need legacy serial support.
+         Saves about 9K.
+
+config SERIAL_8250_PNP
+       tristate "8250/16550 PNP device support" if EMBEDDED
+       depends on SERIAL_8250 && PNP
+       default SERIAL_8250
+       help
+         This builds standard PNP serial support. You may be able to
+         disable this feature if you only need legacy serial support.
+
+config SERIAL_8250_HP300
+       tristate
+       depends on SERIAL_8250 && HP300
+       default SERIAL_8250
+
+config SERIAL_8250_CS
+       tristate "8250/16550 PCMCIA device support"
+       depends on PCMCIA && SERIAL_8250
+       ---help---
+         Say Y here to enable support for 16-bit PCMCIA serial devices,
+         including serial port cards, modems, and the modem functions of
+         multi-function Ethernet/modem cards. (PCMCIA- or PC-cards are
+         credit-card size devices often used with laptops.)
+
+         To compile this driver as a module, choose M here: the
+         module will be called serial_cs.
+
+         If unsure, say N.
+
+config SERIAL_8250_NR_UARTS
+       int "Maximum number of 8250/16550 serial ports"
+       depends on SERIAL_8250
+       default "4"
+       help
+         Set this to the number of serial ports you want the driver
+         to support.  This includes any ports discovered via ACPI or
+         PCI enumeration and any ports that may be added at run-time
+         via hot-plug, or any ISA multi-port serial cards.
+
+config SERIAL_8250_RUNTIME_UARTS
+       int "Number of 8250/16550 serial ports to register at runtime"
+       depends on SERIAL_8250
+       range 0 SERIAL_8250_NR_UARTS
+       default "4"
+       help
+         Set this to the maximum number of serial ports you want
+         the kernel to register at boot time.  This can be overridden
+         with the module parameter "nr_uarts", or boot-time parameter
+         8250.nr_uarts
+
+config SERIAL_8250_EXTENDED
+       bool "Extended 8250/16550 serial driver options"
+       depends on SERIAL_8250
+       help
+         If you wish to use any non-standard features of the standard "dumb"
+         driver, say Y here. This includes HUB6 support, shared serial
+         interrupts, special multiport support, support for more than the
+         four COM 1/2/3/4 boards, etc.
+
+         Note that the answer to this question won't directly affect the
+         kernel: saying N will just cause the configurator to skip all
+         the questions about serial driver options. If unsure, say N.
+
+config SERIAL_8250_MANY_PORTS
+       bool "Support more than 4 legacy serial ports"
+       depends on SERIAL_8250_EXTENDED && !IA64
+       help
+         Say Y here if you have dumb serial boards other than the four
+         standard COM 1/2/3/4 ports. This may happen if you have an AST
+         FourPort, Accent Async, Boca (read the Boca mini-HOWTO, available
+         from <http://www.tldp.org/docs.html#howto>), or other custom
+         serial port hardware which acts similar to standard serial port
+         hardware. If you only use the standard COM 1/2/3/4 ports, you can
+         say N here to save some memory. You can also say Y if you have an
+         "intelligent" multiport card such as Cyclades, Digiboards, etc.
+
+#
+# Multi-port serial cards
+#
+
+config SERIAL_8250_FOURPORT
+       tristate "Support Fourport cards"
+       depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
+       help
+         Say Y here if you have an AST FourPort serial board.
+
+         To compile this driver as a module, choose M here: the module
+         will be called 8250_fourport.
+
+config SERIAL_8250_ACCENT
+       tristate "Support Accent cards"
+       depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
+       help
+         Say Y here if you have an Accent Async serial board.
+
+         To compile this driver as a module, choose M here: the module
+         will be called 8250_accent.
+
+config SERIAL_8250_BOCA
+       tristate "Support Boca cards"
+       depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
+       help
+         Say Y here if you have a Boca serial board.  Please read the Boca
+         mini-HOWTO, available from <http://www.tldp.org/docs.html#howto>
+
+         To compile this driver as a module, choose M here: the module
+         will be called 8250_boca.
+
+config SERIAL_8250_EXAR_ST16C554
+       tristate "Support Exar ST16C554/554D Quad UART"
+       depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
+       help
+         The Uplogix Envoy TU301 uses this Exar Quad UART.  If you are
+         tinkering with your Envoy TU301, or have a machine with this UART,
+         say Y here.
+
+         To compile this driver as a module, choose M here: the module
+         will be called 8250_exar_st16c554.
+
+config SERIAL_8250_HUB6
+       tristate "Support Hub6 cards"
+       depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
+       help
+         Say Y here if you have a HUB6 serial board.
+
+         To compile this driver as a module, choose M here: the module
+         will be called 8250_hub6.
+
+config SERIAL_8250_SHARE_IRQ
+       bool "Support for sharing serial interrupts"
+       depends on SERIAL_8250_EXTENDED
+       help
+         Some serial boards have hardware support which allows multiple dumb
+         serial ports on the same board to share a single IRQ. To enable
+         support for this in the serial driver, say Y here.
+
+config SERIAL_8250_DETECT_IRQ
+       bool "Autodetect IRQ on standard ports (unsafe)"
+       depends on SERIAL_8250_EXTENDED
+       help
+         Say Y here if you want the kernel to try to guess which IRQ
+         to use for your serial port.
+
+         This is considered unsafe; it is far better to configure the IRQ in
+         a boot script using the setserial command.
+
+         If unsure, say N.
+
+config SERIAL_8250_RSA
+       bool "Support RSA serial ports"
+       depends on SERIAL_8250_EXTENDED
+       help
+         ::: To be written :::
+
+config SERIAL_8250_MCA
+       tristate "Support 8250-type ports on MCA buses"
+       depends on SERIAL_8250 != n && MCA
+       help
+         Say Y here if you have a MCA serial ports.
+
+         To compile this driver as a module, choose M here: the module
+         will be called 8250_mca.
+
+config SERIAL_8250_ACORN
+       tristate "Acorn expansion card serial port support"
+       depends on ARCH_ACORN && SERIAL_8250
+       help
+         If you have an Atomwide Serial card or Serial Port card for an Acorn
+         system, say Y to this option.  The driver can handle 1, 2, or 3 port
+         cards.  If unsure, say N.
+
+config SERIAL_8250_RM9K
+       bool "Support for MIPS RM9xxx integrated serial port"
+       depends on SERIAL_8250 != n && SERIAL_RM9000
+       select SERIAL_8250_SHARE_IRQ
+       help
+         Selecting this option will add support for the integrated serial
+         port hardware found on MIPS RM9122 and similar processors.
+         If unsure, say N.
+
+comment "Non-8250 serial port support"
+
+config SERIAL_AMBA_PL010
+       tristate "ARM AMBA PL010 serial port support"
+       depends on ARM_AMBA && (BROKEN || !ARCH_VERSATILE)
+       select SERIAL_CORE
+       help
+         This selects the ARM(R) AMBA(R) PrimeCell PL010 UART.  If you have
+         an Integrator/AP or Integrator/PP2 platform, or if you have a
+         Cirrus Logic EP93xx CPU, say Y or M here.
+
+         If unsure, say N.
+
+config SERIAL_AMBA_PL010_CONSOLE
+       bool "Support for console on AMBA serial port"
+       depends on SERIAL_AMBA_PL010=y
+       select SERIAL_CORE_CONSOLE
+       ---help---
+         Say Y here if you wish to use an AMBA PrimeCell UART as the system
+         console (the system console is the device which receives all kernel
+         messages and warnings and which allows logins in single user mode).
+
+         Even if you say Y here, the currently visible framebuffer console
+         (/dev/tty0) will still be used as the system console by default, but
+         you can alter that using a kernel command line option such as
+         "console=ttyAM0". (Try "man bootparam" or see the documentation of
+         your boot loader (lilo or loadlin) about how to pass options to the
+         kernel at boot time.)
+
+config SERIAL_AMBA_PL011
+       tristate "ARM AMBA PL011 serial port support"
+       depends on ARM_AMBA
+       select SERIAL_CORE
+       help
+         This selects the ARM(R) AMBA(R) PrimeCell PL011 UART.  If you have
+         an Integrator/PP2, Integrator/CP or Versatile platform, say Y or M
+         here.
+
+         If unsure, say N.
+
+config SERIAL_AMBA_PL011_CONSOLE
+       bool "Support for console on AMBA serial port"
+       depends on SERIAL_AMBA_PL011=y
+       select SERIAL_CORE_CONSOLE
+       ---help---
+         Say Y here if you wish to use an AMBA PrimeCell UART as the system
+         console (the system console is the device which receives all kernel
+         messages and warnings and which allows logins in single user mode).
+
+         Even if you say Y here, the currently visible framebuffer console
+         (/dev/tty0) will still be used as the system console by default, but
+         you can alter that using a kernel command line option such as
+         "console=ttyAMA0". (Try "man bootparam" or see the documentation of
+         your boot loader (lilo or loadlin) about how to pass options to the
+         kernel at boot time.)
+
+config SERIAL_SB1250_DUART
+       tristate "BCM1xxx on-chip DUART serial support"
+       depends on SIBYTE_SB1xxx_SOC=y
+       select SERIAL_CORE
+       default y
+       ---help---
+         Support for the asynchronous serial interface (DUART) included in
+         the BCM1250 and derived System-On-a-Chip (SOC) devices.  Note that
+         the letter D in DUART stands for "dual", which is how the device
+         is implemented.  Depending on the SOC configuration there may be
+         one or more DUARTs available of which all are handled.
+
+         If unsure, say Y.  To compile this driver as a module, choose M here:
+         the module will be called sb1250-duart.
+
+config SERIAL_SB1250_DUART_CONSOLE
+       bool "Support for console on a BCM1xxx DUART serial port"
+       depends on SERIAL_SB1250_DUART=y
+       select SERIAL_CORE_CONSOLE
+       default y
+       ---help---
+         If you say Y here, it will be possible to use a serial port as the
+         system console (the system console is the device which receives all
+         kernel messages and warnings and which allows logins in single user
+         mode).
+
+         If unsure, say Y.
+
+config SERIAL_ATMEL
+       bool "AT91 / AT32 on-chip serial port support"
+       depends on (ARM && ARCH_AT91) || AVR32
+       select SERIAL_CORE
+       help
+         This enables the driver for the on-chip UARTs of the Atmel
+         AT91 and AT32 processors.
+
+config SERIAL_ATMEL_CONSOLE
+       bool "Support for console on AT91 / AT32 serial port"
+       depends on SERIAL_ATMEL=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Say Y here if you wish to use an on-chip UART on a Atmel
+         AT91 or AT32 processor as the system console (the system
+         console is the device which receives all kernel messages and
+         warnings and which allows logins in single user mode).
+
+config SERIAL_ATMEL_PDC
+       bool "Support DMA transfers on AT91 / AT32 serial port"
+       depends on SERIAL_ATMEL
+       default y
+       help
+         Say Y here if you wish to use the PDC to do DMA transfers to
+         and from the Atmel AT91 / AT32 serial port. In order to
+         actually use DMA transfers, make sure that the use_dma_tx
+         and use_dma_rx members in the atmel_uart_data struct is set
+         appropriately for each port.
+
+         Note that break and error handling currently doesn't work
+         properly when DMA is enabled. Make sure that ports where
+         this matters don't use DMA.
+
+config SERIAL_ATMEL_TTYAT
+       bool "Install as device ttyATn instead of ttySn"
+       depends on SERIAL_ATMEL=y
+       help
+         Say Y here if you wish to have the internal AT91 / AT32 UARTs
+         appear as /dev/ttyATn (major 204, minor starting at 154)
+         instead of the normal /dev/ttySn (major 4, minor starting at
+         64). This is necessary if you also want other UARTs, such as
+         external 8250/16C550 compatible UARTs.
+         The ttySn nodes are legally reserved for the 8250 serial driver
+         but are often misused by other serial drivers.
+
+         To use this, you should create suitable ttyATn device nodes in
+         /dev/, and pass "console=ttyATn" to the kernel.
+
+         Say Y if you have an external 8250/16C550 UART.  If unsure, say N.
+
+config SERIAL_KS8695
+       bool "Micrel KS8695 (Centaur) serial port support"
+       depends on ARCH_KS8695
+       select SERIAL_CORE
+       help
+         This selects the Micrel Centaur KS8695 UART.  Say Y here.
+
+config SERIAL_KS8695_CONSOLE
+       bool "Support for console on KS8695 (Centaur) serial port"
+       depends on SERIAL_KS8695=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Say Y here if you wish to use a KS8695 (Centaur) UART as the
+         system console (the system console is the device which
+         receives all kernel messages and warnings and which allows
+         logins in single user mode).
+
+config SERIAL_CLPS711X
+       tristate "CLPS711X serial port support"
+       depends on ARM && ARCH_CLPS711X
+       select SERIAL_CORE
+       help
+         ::: To be written :::
+
+config SERIAL_CLPS711X_CONSOLE
+       bool "Support for console on CLPS711X serial port"
+       depends on SERIAL_CLPS711X=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Even if you say Y here, the currently visible virtual console
+         (/dev/tty0) will still be used as the system console by default, but
+         you can alter that using a kernel command line option such as
+         "console=ttyCL1". (Try "man bootparam" or see the documentation of
+         your boot loader (lilo or loadlin) about how to pass options to the
+         kernel at boot time.)
+
+config SERIAL_SAMSUNG
+       tristate "Samsung SoC serial support"
+       depends on ARM && PLAT_SAMSUNG
+       select SERIAL_CORE
+       help
+         Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,
+         providing /dev/ttySAC0, 1 and 2 (note, some machines may not
+         provide all of these ports, depending on how the serial port
+         pins are configured.
+
+config SERIAL_SAMSUNG_UARTS_4
+       bool
+       depends on ARM && PLAT_SAMSUNG
+       default y if CPU_S3C2443
+       help
+         Internal node for the common case of 4 Samsung compatible UARTs
+
+config SERIAL_SAMSUNG_UARTS
+       int
+       depends on ARM && PLAT_SAMSUNG
+       default 2 if ARCH_S3C2400
+       default 6 if ARCH_S5P6450
+       default 4 if SERIAL_SAMSUNG_UARTS_4
+       default 3
+       help
+         Select the number of available UART ports for the Samsung S3C
+         serial driver
+       
+config SERIAL_SAMSUNG_DEBUG
+       bool "Samsung SoC serial debug"
+       depends on SERIAL_SAMSUNG && DEBUG_LL
+       help
+         Add support for debugging the serial driver. Since this is
+         generally being used as a console, we use our own output
+         routines that go via the low-level debug printascii()
+         function.
+
+config SERIAL_SAMSUNG_CONSOLE
+       bool "Support for console on Samsung SoC serial port"
+       depends on SERIAL_SAMSUNG=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Allow selection of the S3C24XX on-board serial ports for use as
+         an virtual console.
+
+         Even if you say Y here, the currently visible virtual console
+         (/dev/tty0) will still be used as the system console by default, but
+         you can alter that using a kernel command line option such as
+         "console=ttySACx". (Try "man bootparam" or see the documentation of
+         your boot loader about how to pass options to the kernel at
+         boot time.)
+
+config SERIAL_S3C2400
+       tristate "Samsung S3C2410 Serial port support"
+       depends on ARM && SERIAL_SAMSUNG && CPU_S3C2400
+       default y if CPU_S3C2400
+       help
+         Serial port support for the Samsung S3C2400 SoC
+
+config SERIAL_S3C2410
+       tristate "Samsung S3C2410 Serial port support"
+       depends on SERIAL_SAMSUNG && CPU_S3C2410
+       default y if CPU_S3C2410
+       help
+         Serial port support for the Samsung S3C2410 SoC
+
+config SERIAL_S3C2412
+       tristate "Samsung S3C2412/S3C2413 Serial port support"
+       depends on SERIAL_SAMSUNG && CPU_S3C2412
+       default y if CPU_S3C2412
+       help
+         Serial port support for the Samsung S3C2412 and S3C2413 SoC
+
+config SERIAL_S3C2440
+       tristate "Samsung S3C2440/S3C2442/S3C2416 Serial port support"
+       depends on SERIAL_SAMSUNG && (CPU_S3C2440 || CPU_S3C2442 || CPU_S3C2416)
+       default y if CPU_S3C2440
+       default y if CPU_S3C2442
+       select SERIAL_SAMSUNG_UARTS_4 if CPU_S3C2416
+       help
+         Serial port support for the Samsung S3C2440, S3C2416 and S3C2442 SoC
+
+config SERIAL_S3C24A0
+       tristate "Samsung S3C24A0 Serial port support"
+       depends on SERIAL_SAMSUNG && CPU_S3C24A0
+       default y if CPU_S3C24A0
+       help
+         Serial port support for the Samsung S3C24A0 SoC
+
+config SERIAL_S3C6400
+       tristate "Samsung S3C6400/S3C6410/S5P6440/S5P6450/S5PC100 Serial port support"
+       depends on SERIAL_SAMSUNG && (CPU_S3C6400 || CPU_S3C6410 || CPU_S5P6440 || CPU_S5P6450 || CPU_S5PC100)
+       select SERIAL_SAMSUNG_UARTS_4
+       default y
+       help
+         Serial port support for the Samsung S3C6400, S3C6410, S5P6440, S5P6450
+         and S5PC100 SoCs
+
+config SERIAL_S5PV210
+       tristate "Samsung S5PV210 Serial port support"
+       depends on SERIAL_SAMSUNG && (CPU_S5PV210 || CPU_S5P6442 || CPU_S5PV310)
+       select SERIAL_SAMSUNG_UARTS_4 if (CPU_S5PV210 || CPU_S5PV310)
+       default y
+       help
+         Serial port support for Samsung's S5P Family of SoC's
+
+
+config SERIAL_MAX3100
+       tristate "MAX3100 support"
+       depends on SPI
+       select SERIAL_CORE
+       help
+         MAX3100 chip support
+
+config SERIAL_MAX3107
+       tristate "MAX3107 support"
+       depends on SPI
+       select SERIAL_CORE
+       help
+         MAX3107 chip support
+
+config SERIAL_MAX3107_AAVA
+       tristate "MAX3107 AAVA platform support"
+       depends on X86_MRST && SERIAL_MAX3107 && GPIOLIB
+       select SERIAL_CORE
+       help
+         Support for the MAX3107 chip configuration found on the AAVA
+         platform. Includes the extra initialisation and GPIO support
+         neded for this device.
+
+config SERIAL_DZ
+       bool "DECstation DZ serial driver"
+       depends on MACH_DECSTATION && 32BIT
+       select SERIAL_CORE
+       default y
+       ---help---
+         DZ11-family serial controllers for DECstations and VAXstations,
+         including the DC7085, M7814, and M7819.
+
+config SERIAL_DZ_CONSOLE
+       bool "Support console on DECstation DZ serial driver"
+       depends on SERIAL_DZ=y
+       select SERIAL_CORE_CONSOLE
+       default y
+       ---help---
+         If you say Y here, it will be possible to use a serial port as the
+         system console (the system console is the device which receives all
+         kernel messages and warnings and which allows logins in single user
+         mode).
+
+         Note that the firmware uses ttyS3 as the serial console on
+         DECstations that use this driver.
+
+         If unsure, say Y.
+
+config SERIAL_ZS
+       tristate "DECstation Z85C30 serial support"
+       depends on MACH_DECSTATION
+       select SERIAL_CORE
+       default y
+       ---help---
+         Support for the Zilog 85C350 serial communications controller used
+         for serial ports in newer DECstation systems.  These include the
+         DECsystem 5900 and all models of the DECstation and DECsystem 5000
+         systems except from model 200.
+
+         If unsure, say Y.  To compile this driver as a module, choose M here:
+         the module will be called zs.
+
+config SERIAL_ZS_CONSOLE
+       bool "Support for console on a DECstation Z85C30 serial port"
+       depends on SERIAL_ZS=y
+       select SERIAL_CORE_CONSOLE
+       default y
+       ---help---
+         If you say Y here, it will be possible to use a serial port as the
+         system console (the system console is the device which receives all
+         kernel messages and warnings and which allows logins in single user
+         mode).
+
+         Note that the firmware uses ttyS1 as the serial console on the
+         Maxine and ttyS3 on the others using this driver.
+
+         If unsure, say Y.
+
+config SERIAL_21285
+       tristate "DC21285 serial port support"
+       depends on ARM && FOOTBRIDGE
+       select SERIAL_CORE
+       help
+         If you have a machine based on a 21285 (Footbridge) StrongARM(R)/
+         PCI bridge you can enable its onboard serial port by enabling this
+         option.
+
+config SERIAL_21285_CONSOLE
+       bool "Console on DC21285 serial port"
+       depends on SERIAL_21285=y
+       select SERIAL_CORE_CONSOLE
+       help
+         If you have enabled the serial port on the 21285 footbridge you can
+         make it the console by answering Y to this option.
+
+         Even if you say Y here, the currently visible virtual console
+         (/dev/tty0) will still be used as the system console by default, but
+         you can alter that using a kernel command line option such as
+         "console=ttyFB". (Try "man bootparam" or see the documentation of
+         your boot loader (lilo or loadlin) about how to pass options to the
+         kernel at boot time.)
+
+config SERIAL_MPSC
+       bool "Marvell MPSC serial port support"
+       depends on PPC32 && MV64X60
+       select SERIAL_CORE
+       help
+         Say Y here if you want to use the Marvell MPSC serial controller.
+
+config SERIAL_MPSC_CONSOLE
+       bool "Support for console on Marvell MPSC serial port"
+       depends on SERIAL_MPSC
+       select SERIAL_CORE_CONSOLE
+       help
+         Say Y here if you want to support a serial console on a Marvell MPSC.
+
+config SERIAL_PXA
+       bool "PXA serial port support"
+       depends on ARCH_PXA || ARCH_MMP
+       select SERIAL_CORE
+       help
+         If you have a machine based on an Intel XScale PXA2xx CPU you
+         can enable its onboard serial ports by enabling this option.
+
+config SERIAL_PXA_CONSOLE
+       bool "Console on PXA serial port"
+       depends on SERIAL_PXA
+       select SERIAL_CORE_CONSOLE
+       help
+         If you have enabled the serial port on the Intel XScale PXA
+         CPU you can make it the console by answering Y to this option.
+
+         Even if you say Y here, the currently visible virtual console
+         (/dev/tty0) will still be used as the system console by default, but
+         you can alter that using a kernel command line option such as
+         "console=ttySA0". (Try "man bootparam" or see the documentation of
+         your boot loader (lilo or loadlin) about how to pass options to the
+         kernel at boot time.)
+
+config SERIAL_SA1100
+       bool "SA1100 serial port support"
+       depends on ARM && ARCH_SA1100
+       select SERIAL_CORE
+       help
+         If you have a machine based on a SA1100/SA1110 StrongARM(R) CPU you
+         can enable its onboard serial port by enabling this option.
+         Please read <file:Documentation/arm/SA1100/serial_UART> for further
+         info.
+
+config SERIAL_SA1100_CONSOLE
+       bool "Console on SA1100 serial port"
+       depends on SERIAL_SA1100
+       select SERIAL_CORE_CONSOLE
+       help
+         If you have enabled the serial port on the SA1100/SA1110 StrongARM
+         CPU you can make it the console by answering Y to this option.
+
+         Even if you say Y here, the currently visible virtual console
+         (/dev/tty0) will still be used as the system console by default, but
+         you can alter that using a kernel command line option such as
+         "console=ttySA0". (Try "man bootparam" or see the documentation of
+         your boot loader (lilo or loadlin) about how to pass options to the
+         kernel at boot time.)
+
+config SERIAL_MRST_MAX3110
+       tristate "SPI UART driver for Max3110"
+       depends on SPI_DW_PCI
+       select SERIAL_CORE
+       select SERIAL_CORE_CONSOLE
+       help
+         This is the UART protocol driver for the MAX3110 device on
+         the Intel Moorestown platform. On other systems use the max3100
+         driver.
+
+config SERIAL_MFD_HSU
+       tristate "Medfield High Speed UART support"
+       depends on PCI
+       select SERIAL_CORE
+
+config SERIAL_MFD_HSU_CONSOLE
+       boolean "Medfile HSU serial console support"
+       depends on SERIAL_MFD_HSU=y
+       select SERIAL_CORE_CONSOLE
+
+config SERIAL_BFIN
+       tristate "Blackfin serial port support"
+       depends on BLACKFIN
+       select SERIAL_CORE
+       select SERIAL_BFIN_UART0 if (BF531 || BF532 || BF533 || BF561)
+       help
+         Add support for the built-in UARTs on the Blackfin.
+
+         To compile this driver as a module, choose M here: the
+         module will be called bfin_5xx.
+
+config SERIAL_BFIN_CONSOLE
+       bool "Console on Blackfin serial port"
+       depends on SERIAL_BFIN=y
+       select SERIAL_CORE_CONSOLE
+
+choice
+       prompt "UART Mode"
+       depends on SERIAL_BFIN
+       default SERIAL_BFIN_DMA
+       help
+         This driver supports the built-in serial ports of the Blackfin family
+         of CPUs
+
+config SERIAL_BFIN_DMA
+       bool "DMA mode"
+       depends on !DMA_UNCACHED_NONE && KGDB_SERIAL_CONSOLE=n
+       help
+         This driver works under DMA mode. If this option is selected, the
+         blackfin simple dma driver is also enabled.
+
+config SERIAL_BFIN_PIO
+       bool "PIO mode"
+       help
+         This driver works under PIO mode.
+
+endchoice
+
+config SERIAL_BFIN_UART0
+       bool "Enable UART0"
+       depends on SERIAL_BFIN
+       help
+         Enable UART0
+
+config BFIN_UART0_CTSRTS
+       bool "Enable UART0 hardware flow control"
+       depends on SERIAL_BFIN_UART0
+       help
+         Enable hardware flow control in the driver.
+
+config SERIAL_BFIN_UART1
+       bool "Enable UART1"
+       depends on SERIAL_BFIN && (!BF531 && !BF532 && !BF533 && !BF561)
+       help
+         Enable UART1
+
+config BFIN_UART1_CTSRTS
+       bool "Enable UART1 hardware flow control"
+       depends on SERIAL_BFIN_UART1
+       help
+         Enable hardware flow control in the driver.
+
+config SERIAL_BFIN_UART2
+       bool "Enable UART2"
+       depends on SERIAL_BFIN && (BF54x || BF538 || BF539)
+       help
+         Enable UART2
+
+config BFIN_UART2_CTSRTS
+       bool "Enable UART2 hardware flow control"
+       depends on SERIAL_BFIN_UART2
+       help
+         Enable hardware flow control in the driver.
+
+config SERIAL_BFIN_UART3
+       bool "Enable UART3"
+       depends on SERIAL_BFIN && (BF54x)
+       help
+         Enable UART3
+
+config BFIN_UART3_CTSRTS
+       bool "Enable UART3 hardware flow control"
+       depends on SERIAL_BFIN_UART3
+       help
+         Enable hardware flow control in the driver.
+
+config SERIAL_IMX
+       bool "IMX serial port support"
+       depends on ARM && (ARCH_IMX || ARCH_MXC)
+       select SERIAL_CORE
+       select RATIONAL
+       help
+         If you have a machine based on a Motorola IMX CPU you
+         can enable its onboard serial port by enabling this option.
+
+config SERIAL_IMX_CONSOLE
+       bool "Console on IMX serial port"
+       depends on SERIAL_IMX
+       select SERIAL_CORE_CONSOLE
+       help
+         If you have enabled the serial port on the Motorola IMX
+         CPU you can make it the console by answering Y to this option.
+
+         Even if you say Y here, the currently visible virtual console
+         (/dev/tty0) will still be used as the system console by default, but
+         you can alter that using a kernel command line option such as
+         "console=ttySA0". (Try "man bootparam" or see the documentation of
+         your boot loader (lilo or loadlin) about how to pass options to the
+         kernel at boot time.)
+
+config SERIAL_UARTLITE
+       tristate "Xilinx uartlite serial port support"
+       depends on PPC32 || MICROBLAZE || MFD_TIMBERDALE
+       select SERIAL_CORE
+       help
+         Say Y here if you want to use the Xilinx uartlite serial controller.
+
+         To compile this driver as a module, choose M here: the
+         module will be called uartlite.
+
+config SERIAL_UARTLITE_CONSOLE
+       bool "Support for console on Xilinx uartlite serial port"
+       depends on SERIAL_UARTLITE=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Say Y here if you wish to use a Xilinx uartlite as the system
+         console (the system console is the device which receives all kernel
+         messages and warnings and which allows logins in single user mode).
+
+config SERIAL_SUNCORE
+       bool
+       depends on SPARC
+       select SERIAL_CORE
+       select SERIAL_CORE_CONSOLE
+       default y
+
+config SERIAL_SUNZILOG
+       tristate "Sun Zilog8530 serial support"
+       depends on SPARC
+       help
+         This driver supports the Zilog8530 serial ports found on many Sparc
+         systems.  Say Y or M if you want to be able to these serial ports.
+
+config SERIAL_SUNZILOG_CONSOLE
+       bool "Console on Sun Zilog8530 serial port"
+       depends on SERIAL_SUNZILOG=y
+       help
+         If you would like to be able to use the Zilog8530 serial port
+         on your Sparc system as the console, you can do so by answering
+         Y to this option.
+
+config SERIAL_SUNSU
+       tristate "Sun SU serial support"
+       depends on SPARC && PCI
+       help
+         This driver supports the 8250 serial ports that run the keyboard and
+         mouse on (PCI) UltraSPARC systems.  Say Y or M if you want to be able
+         to these serial ports.
+
+config SERIAL_SUNSU_CONSOLE
+       bool "Console on Sun SU serial port"
+       depends on SERIAL_SUNSU=y
+       help
+         If you would like to be able to use the SU serial port
+         on your Sparc system as the console, you can do so by answering
+         Y to this option.
+
+config SERIAL_MUX
+       tristate "Serial MUX support"
+       depends on GSC
+       select SERIAL_CORE
+       default y
+       ---help---
+         Saying Y here will enable the hardware MUX serial driver for
+         the Nova, K class systems and D class with a 'remote control card'.
+         The hardware MUX is not 8250/16550 compatible therefore the
+         /dev/ttyB0 device is shared between the Serial MUX and the PDC
+         software console. The following steps need to be completed to use
+         the Serial MUX:
+
+           1. create the device entry (mknod /dev/ttyB0 c 11 0)
+           2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0
+           3. Add device ttyB0 to /etc/securetty (if you want to log on as
+                root on this console.)
+           4. Change the kernel command console parameter to: console=ttyB0
+
+config SERIAL_MUX_CONSOLE
+       bool "Support for console on serial MUX"
+       depends on SERIAL_MUX=y
+       select SERIAL_CORE_CONSOLE
+       default y
+
+config PDC_CONSOLE
+       bool "PDC software console support"
+       depends on PARISC && !SERIAL_MUX && VT
+       default n
+       help
+         Saying Y here will enable the software based PDC console to be 
+         used as the system console.  This is useful for machines in 
+         which the hardware based console has not been written yet.  The
+         following steps must be competed to use the PDC console:
+
+           1. create the device entry (mknod /dev/ttyB0 c 11 0)
+           2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0
+           3. Add device ttyB0 to /etc/securetty (if you want to log on as
+                root on this console.)
+           4. Change the kernel command console parameter to: console=ttyB0
+
+config SERIAL_SUNSAB
+       tristate "Sun Siemens SAB82532 serial support"
+       depends on SPARC && PCI
+       help
+         This driver supports the Siemens SAB82532 DUSCC serial ports on newer
+         (PCI) UltraSPARC systems.  Say Y or M if you want to be able to these
+         serial ports.
+
+config SERIAL_SUNSAB_CONSOLE
+       bool "Console on Sun Siemens SAB82532 serial port"
+       depends on SERIAL_SUNSAB=y
+       help
+         If you would like to be able to use the SAB82532 serial port
+         on your Sparc system as the console, you can do so by answering
+         Y to this option.
+
+config SERIAL_SUNHV
+       bool "Sun4v Hypervisor Console support"
+       depends on SPARC64
+       help
+         This driver supports the console device found on SUN4V Sparc
+         systems.  Say Y if you want to be able to use this device.
+
+config SERIAL_IP22_ZILOG
+       tristate "SGI Zilog8530 serial support"
+       depends on SGI_HAS_ZILOG
+       select SERIAL_CORE
+       help
+         This driver supports the Zilog8530 serial ports found on SGI
+         systems.  Say Y or M if you want to be able to these serial ports.
+
+config SERIAL_IP22_ZILOG_CONSOLE
+       bool "Console on SGI Zilog8530 serial port"
+       depends on SERIAL_IP22_ZILOG=y
+       select SERIAL_CORE_CONSOLE
+
+config SERIAL_SH_SCI
+       tristate "SuperH SCI(F) serial port support"
+       depends on HAVE_CLK && (SUPERH || H8300 || ARCH_SHMOBILE)
+       select SERIAL_CORE
+
+config SERIAL_SH_SCI_NR_UARTS
+       int "Maximum number of SCI(F) serial ports"
+       depends on SERIAL_SH_SCI
+       default "2"
+
+config SERIAL_SH_SCI_CONSOLE
+       bool "Support for console on SuperH SCI(F)"
+       depends on SERIAL_SH_SCI=y
+       select SERIAL_CORE_CONSOLE
+
+config SERIAL_SH_SCI_DMA
+       bool "DMA support"
+       depends on SERIAL_SH_SCI && SH_DMAE && EXPERIMENTAL
+
+config SERIAL_PNX8XXX
+       bool "Enable PNX8XXX SoCs' UART Support"
+       depends on MIPS && (SOC_PNX8550 || SOC_PNX833X)
+       select SERIAL_CORE
+       help
+         If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330
+         and you want to use serial ports, say Y.  Otherwise, say N.
+
+config SERIAL_PNX8XXX_CONSOLE
+       bool "Enable PNX8XX0 serial console"
+       depends on SERIAL_PNX8XXX
+       select SERIAL_CORE_CONSOLE
+       help
+         If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330
+         and you want to use serial console, say Y. Otherwise, say N.
+
+config SERIAL_CORE
+       tristate
+
+config SERIAL_CORE_CONSOLE
+       bool
+
+config CONSOLE_POLL
+       bool
+
+config SERIAL_68328
+       bool "68328 serial support"
+       depends on M68328 || M68EZ328 || M68VZ328
+       help
+         This driver supports the built-in serial port of the Motorola 68328
+         (standard, EZ and VZ varieties).
+
+config SERIAL_68328_RTS_CTS
+       bool "Support RTS/CTS on 68328 serial port"
+       depends on SERIAL_68328
+
+config SERIAL_MCF
+       bool "Coldfire serial support"
+       depends on COLDFIRE
+       select SERIAL_CORE
+       help
+         This serial driver supports the Freescale Coldfire serial ports.
+
+config SERIAL_MCF_BAUDRATE
+       int "Default baudrate for Coldfire serial ports"
+       depends on SERIAL_MCF
+       default 19200
+       help
+         This setting lets you define what the default baudrate is for the
+         ColdFire serial ports. The usual default varies from board to board,
+         and this setting is a way of catering for that.
+
+config SERIAL_MCF_CONSOLE
+       bool "Coldfire serial console support"
+       depends on SERIAL_MCF
+       select SERIAL_CORE_CONSOLE
+       help
+         Enable a ColdFire internal serial port to be the system console.
+
+config SERIAL_68360_SMC
+       bool "68360 SMC uart support"
+       depends on M68360
+       help
+         This driver supports the SMC serial ports of the Motorola 68360 CPU.
+
+config SERIAL_68360_SCC
+       bool "68360 SCC uart support"
+       depends on M68360
+       help
+         This driver supports the SCC serial ports of the Motorola 68360 CPU.
+
+config SERIAL_68360
+       bool
+       depends on SERIAL_68360_SMC || SERIAL_68360_SCC
+       default y
+
+config SERIAL_PMACZILOG
+       tristate "Mac or PowerMac z85c30 ESCC support"
+       depends on (M68K && MAC) || (PPC_OF && PPC_PMAC)
+       select SERIAL_CORE
+       help
+         This driver supports the Zilog z85C30 serial ports found on
+         (Power)Mac machines.
+         Say Y or M if you want to be able to these serial ports.
+
+config SERIAL_PMACZILOG_TTYS
+       bool "Use ttySn device nodes for Zilog z85c30"
+       depends on SERIAL_PMACZILOG
+       help
+         The pmac_zilog driver for the z85C30 chip on many powermacs
+         historically used the device numbers for /dev/ttySn.  The
+         8250 serial port driver also uses these numbers, which means
+         the two drivers being unable to coexist; you could not use
+         both z85C30 and 8250 type ports at the same time.
+
+         If this option is not selected, the pmac_zilog driver will
+         use the device numbers allocated for /dev/ttyPZn.  This allows
+         the pmac_zilog and 8250 drivers to co-exist, but may cause
+         existing userspace setups to break.  Programs that need to
+         access the built-in serial ports on powermacs will need to
+         be reconfigured to use /dev/ttyPZn instead of /dev/ttySn.
+
+         If you enable this option, any z85c30 ports in the system will
+         be registered as ttyS0 onwards as in the past, and you will be
+         unable to use the 8250 module for PCMCIA or other 16C550-style
+         UARTs.
+
+         Say N unless you need the z85c30 ports on your (Power)Mac
+         to appear as /dev/ttySn.
+
+config SERIAL_PMACZILOG_CONSOLE
+       bool "Console on Mac or PowerMac z85c30 serial port"
+       depends on SERIAL_PMACZILOG=y
+       select SERIAL_CORE_CONSOLE
+       help
+         If you would like to be able to use the z85c30 serial port
+         on your (Power)Mac as the console, you can do so by answering
+         Y to this option.
+
+config SERIAL_LH7A40X
+       tristate "Sharp LH7A40X embedded UART support"
+       depends on ARM && ARCH_LH7A40X
+       select SERIAL_CORE
+       help
+         This enables support for the three on-board UARTs of the
+         Sharp LH7A40X series CPUs.  Choose Y or M.
+
+config SERIAL_LH7A40X_CONSOLE
+       bool "Support for console on Sharp LH7A40X serial port"
+       depends on SERIAL_LH7A40X=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Say Y here if you wish to use one of the serial ports as the
+         system console--the system console is the device which
+         receives all kernel messages and warnings and which allows
+         logins in single user mode.
+
+         Even if you say Y here, the currently visible framebuffer console
+         (/dev/tty0) will still be used as the default system console, but
+         you can alter that using a kernel command line, for example
+         "console=ttyAM1".
+
+config SERIAL_CPM
+       tristate "CPM SCC/SMC serial port support"
+       depends on CPM2 || 8xx
+       select SERIAL_CORE
+       help
+         This driver supports the SCC and SMC serial ports on Motorola 
+         embedded PowerPC that contain a CPM1 (8xx) or CPM2 (8xxx)
+
+config SERIAL_CPM_CONSOLE
+       bool "Support for console on CPM SCC/SMC serial port"
+       depends on SERIAL_CPM=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Say Y here if you wish to use a SCC or SMC CPM UART as the system
+         console (the system console is the device which receives all kernel
+         messages and warnings and which allows logins in single user mode).
+
+         Even if you say Y here, the currently visible framebuffer console
+         (/dev/tty0) will still be used as the system console by default, but
+         you can alter that using a kernel command line option such as
+         "console=ttyCPM0". (Try "man bootparam" or see the documentation of
+         your boot loader (lilo or loadlin) about how to pass options to the
+         kernel at boot time.)
+
+config SERIAL_SGI_L1_CONSOLE
+       bool "SGI Altix L1 serial console support"
+       depends on IA64_GENERIC || IA64_SGI_SN2
+       select SERIAL_CORE
+       select SERIAL_CORE_CONSOLE
+       help
+               If you have an SGI Altix and you would like to use the system
+               controller serial port as your console (you want this!),
+               say Y.  Otherwise, say N.
+
+config SERIAL_MPC52xx
+       tristate "Freescale MPC52xx/MPC512x family PSC serial support"
+       depends on PPC_MPC52xx || PPC_MPC512x
+       select SERIAL_CORE
+       help
+         This driver supports MPC52xx and MPC512x PSC serial ports. If you would
+         like to use them, you must answer Y or M to this option. Note that
+         for use as console, it must be included in kernel and not as a
+         module.
+
+config SERIAL_MPC52xx_CONSOLE
+       bool "Console on a Freescale MPC52xx/MPC512x family PSC serial port"
+       depends on SERIAL_MPC52xx=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Select this options if you'd like to use one of the PSC serial port
+         of the Freescale MPC52xx family as a console.
+
+config SERIAL_MPC52xx_CONSOLE_BAUD
+       int "Freescale MPC52xx/MPC512x family PSC serial port baud"
+       depends on SERIAL_MPC52xx_CONSOLE=y
+       default "9600"
+       help
+         Select the MPC52xx console baud rate.
+         This value is only used if the bootloader doesn't pass in the
+         console baudrate
+
+config SERIAL_ICOM
+       tristate "IBM Multiport Serial Adapter"
+       depends on PCI && (PPC_ISERIES || PPC_PSERIES)
+       select SERIAL_CORE
+       select FW_LOADER
+       help
+         This driver is for a family of multiport serial adapters
+         including 2 port RVX, 2 port internal modem, 4 port internal
+         modem and a split 1 port RVX and 1 port internal modem.
+
+         This driver can also be built as a module.  If so, the module
+         will be called icom.
+
+config SERIAL_M32R_SIO
+       bool "M32R SIO I/F"
+       depends on M32R
+       default y
+       select SERIAL_CORE
+       help
+         Say Y here if you want to use the M32R serial controller.
+
+config SERIAL_M32R_SIO_CONSOLE
+       bool "use SIO console"
+       depends on SERIAL_M32R_SIO=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Say Y here if you want to support a serial console.
+
+         If you use an M3T-M32700UT or an OPSPUT platform,
+         please say also y for SERIAL_M32R_PLDSIO.
+
+config SERIAL_M32R_PLDSIO
+       bool "M32R SIO I/F on a PLD"
+       depends on SERIAL_M32R_SIO=y && (PLAT_OPSPUT || PLAT_USRV || PLAT_M32700UT)
+       default n
+       help
+         Say Y here if you want to use the M32R serial controller
+         on a PLD (Programmable Logic Device).
+
+         If you use an M3T-M32700UT or an OPSPUT platform,
+         please say Y.
+
+config SERIAL_TXX9
+       bool "TMPTX39XX/49XX SIO support"
+       depends on HAS_TXX9_SERIAL
+       select SERIAL_CORE
+       default y
+
+config HAS_TXX9_SERIAL
+       bool
+
+config SERIAL_TXX9_NR_UARTS
+       int "Maximum number of TMPTX39XX/49XX SIO ports"
+       depends on SERIAL_TXX9
+       default "6"
+
+config SERIAL_TXX9_CONSOLE
+       bool "TMPTX39XX/49XX SIO Console support"
+       depends on SERIAL_TXX9=y
+       select SERIAL_CORE_CONSOLE
+
+config SERIAL_TXX9_STDSERIAL
+       bool "TX39XX/49XX SIO act as standard serial"
+       depends on !SERIAL_8250 && SERIAL_TXX9
+
+config SERIAL_VR41XX
+       tristate "NEC VR4100 series Serial Interface Unit support"
+       depends on CPU_VR41XX
+       select SERIAL_CORE
+       help
+         If you have a NEC VR4100 series processor and you want to use
+         Serial Interface Unit(SIU) or Debug Serial Interface Unit(DSIU)
+         (not include VR4111/VR4121 DSIU), say Y.  Otherwise, say N.
+
+config SERIAL_VR41XX_CONSOLE
+       bool "Enable NEC VR4100 series Serial Interface Unit console"
+       depends on SERIAL_VR41XX=y
+       select SERIAL_CORE_CONSOLE
+       help
+         If you have a NEC VR4100 series processor and you want to use
+         a console on a serial port, say Y.  Otherwise, say N.
+
+config SERIAL_JSM
+       tristate "Digi International NEO PCI Support"
+       depends on PCI
+       select SERIAL_CORE
+       help
+         This is a driver for Digi International's Neo series
+         of cards which provide multiple serial ports. You would need
+         something like this to connect more than two modems to your Linux
+         box, for instance in order to become a dial-in server. This driver
+         supports PCI boards only.
+
+         If you have a card like this, say Y here, otherwise say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called jsm.
+
+config SERIAL_SGI_IOC4
+       tristate "SGI IOC4 controller serial support"
+       depends on (IA64_GENERIC || IA64_SGI_SN2) && SGI_IOC4
+       select SERIAL_CORE
+       help
+               If you have an SGI Altix with an IOC4 based Base IO card
+               and wish to use the serial ports on this card, say Y.
+               Otherwise, say N.
+
+config SERIAL_SGI_IOC3
+       tristate "SGI Altix IOC3 serial support"
+       depends on (IA64_GENERIC || IA64_SGI_SN2) && SGI_IOC3
+       select SERIAL_CORE
+       help
+         If you have an SGI Altix with an IOC3 serial card,
+         say Y or M.  Otherwise, say N.
+
+config SERIAL_MSM
+       bool "MSM on-chip serial port support"
+       depends on ARM && ARCH_MSM
+       select SERIAL_CORE
+
+config SERIAL_MSM_CONSOLE
+       bool "MSM serial console support"
+       depends on SERIAL_MSM=y
+       select SERIAL_CORE_CONSOLE
+
+config SERIAL_VT8500
+       bool "VIA VT8500 on-chip serial port support"
+       depends on ARM && ARCH_VT8500
+       select SERIAL_CORE
+
+config SERIAL_VT8500_CONSOLE
+       bool "VIA VT8500 serial console support"
+       depends on SERIAL_VT8500=y
+       select SERIAL_CORE_CONSOLE
+
+config SERIAL_NETX
+       tristate "NetX serial port support"
+       depends on ARM && ARCH_NETX
+       select SERIAL_CORE
+       help
+         If you have a machine based on a Hilscher NetX SoC you
+         can enable its onboard serial port by enabling this option.
+
+          To compile this driver as a module, choose M here: the
+          module will be called netx-serial.
+
+config SERIAL_NETX_CONSOLE
+       bool "Console on NetX serial port"
+       depends on SERIAL_NETX=y
+       select SERIAL_CORE_CONSOLE
+       help
+         If you have enabled the serial port on the Hilscher NetX SoC
+         you can make it the console by answering Y to this option.
+
+config SERIAL_OF_PLATFORM
+       tristate "Serial port on Open Firmware platform bus"
+       depends on OF
+       depends on SERIAL_8250 || SERIAL_OF_PLATFORM_NWPSERIAL
+       help
+         If you have a PowerPC based system that has serial ports
+         on a platform specific bus, you should enable this option.
+         Currently, only 8250 compatible ports are supported, but
+         others can easily be added.
+
+config SERIAL_OMAP
+       tristate "OMAP serial port support"
+       depends on ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4
+       select SERIAL_CORE
+       help
+         If you have a machine based on an Texas Instruments OMAP CPU you
+         can enable its onboard serial ports by enabling this option.
+
+         By enabling this option you take advantage of dma feature available
+         with the omap-serial driver. DMA support can be enabled from platform
+         data.
+
+config SERIAL_OMAP_CONSOLE
+       bool "Console on OMAP serial port"
+       depends on SERIAL_OMAP
+       select SERIAL_CORE_CONSOLE
+       help
+         Select this option if you would like to use omap serial port as
+         console.
+
+         Even if you say Y here, the currently visible virtual console
+         (/dev/tty0) will still be used as the system console by default, but
+         you can alter that using a kernel command line option such as
+         "console=ttyOx". (Try "man bootparam" or see the documentation of
+         your boot loader about how to pass options to the kernel at
+         boot time.)
+
+config SERIAL_OF_PLATFORM_NWPSERIAL
+       tristate "NWP serial port driver"
+       depends on PPC_OF && PPC_DCR
+       select SERIAL_OF_PLATFORM
+       select SERIAL_CORE_CONSOLE
+       select SERIAL_CORE
+       help
+         This driver supports the cell network processor nwp serial
+         device.
+
+config SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE
+       bool "Console on NWP serial port"
+       depends on SERIAL_OF_PLATFORM_NWPSERIAL=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Support for Console on the NWP serial ports.
+
+config SERIAL_QE
+       tristate "Freescale QUICC Engine serial port support"
+       depends on QUICC_ENGINE
+       select SERIAL_CORE
+       select FW_LOADER
+       default n
+       help
+         This driver supports the QE serial ports on Freescale embedded
+         PowerPC that contain a QUICC Engine.
+
+config SERIAL_SC26XX
+       tristate "SC2681/SC2692 serial port support"
+       depends on SNI_RM
+       select SERIAL_CORE
+       help
+         This is a driver for the onboard serial ports of
+         older RM400 machines.
+
+config SERIAL_SC26XX_CONSOLE
+       bool "Console on SC2681/SC2692 serial port"
+       depends on SERIAL_SC26XX
+       select SERIAL_CORE_CONSOLE
+       help
+         Support for Console on SC2681/SC2692 serial ports.
+
+config SERIAL_BFIN_SPORT
+       tristate "Blackfin SPORT emulate UART"
+       depends on BLACKFIN
+       select SERIAL_CORE
+       help
+         Enable SPORT emulate UART on Blackfin series.
+
+         To compile this driver as a module, choose M here: the
+         module will be called bfin_sport_uart.
+
+config SERIAL_BFIN_SPORT_CONSOLE
+       bool "Console on Blackfin sport emulated uart"
+       depends on SERIAL_BFIN_SPORT=y
+       select SERIAL_CORE_CONSOLE
+
+config SERIAL_BFIN_SPORT0_UART
+       bool "Enable UART over SPORT0"
+       depends on SERIAL_BFIN_SPORT && !(BF542 || BF544)
+       help
+         Enable UART over SPORT0
+
+config SERIAL_BFIN_SPORT0_UART_CTSRTS
+       bool "Enable UART over SPORT0 hardware flow control"
+       depends on SERIAL_BFIN_SPORT0_UART
+       help
+         Enable hardware flow control in the driver.
+
+config SERIAL_BFIN_SPORT1_UART
+       bool "Enable UART over SPORT1"
+       depends on SERIAL_BFIN_SPORT
+       help
+         Enable UART over SPORT1
+
+config SERIAL_BFIN_SPORT1_UART_CTSRTS
+       bool "Enable UART over SPORT1 hardware flow control"
+       depends on SERIAL_BFIN_SPORT1_UART
+       help
+         Enable hardware flow control in the driver.
+
+config SERIAL_BFIN_SPORT2_UART
+       bool "Enable UART over SPORT2"
+       depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539)
+       help
+         Enable UART over SPORT2
+
+config SERIAL_BFIN_SPORT2_UART_CTSRTS
+       bool "Enable UART over SPORT2 hardware flow control"
+       depends on SERIAL_BFIN_SPORT2_UART
+       help
+         Enable hardware flow control in the driver.
+
+config SERIAL_BFIN_SPORT3_UART
+       bool "Enable UART over SPORT3"
+       depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539)
+       help
+         Enable UART over SPORT3
+
+config SERIAL_BFIN_SPORT3_UART_CTSRTS
+       bool "Enable UART over SPORT3 hardware flow control"
+       depends on SERIAL_BFIN_SPORT3_UART
+       help
+         Enable hardware flow control in the driver.
+
+config SERIAL_TIMBERDALE
+       tristate "Support for timberdale UART"
+       select SERIAL_CORE
+       ---help---
+       Add support for UART controller on timberdale.
+
+config SERIAL_BCM63XX
+       tristate "bcm63xx serial port support"
+       select SERIAL_CORE
+       depends on BCM63XX
+       help
+         If you have a bcm63xx CPU, you can enable its onboard
+         serial port by enabling this options.
+
+          To compile this driver as a module, choose M here: the
+          module will be called bcm963xx_uart.
+
+config SERIAL_BCM63XX_CONSOLE
+       bool "Console on bcm63xx serial port"
+       depends on SERIAL_BCM63XX=y
+       select SERIAL_CORE_CONSOLE
+       help
+         If you have enabled the serial port on the bcm63xx CPU
+         you can make it the console by answering Y to this option.
+
+config SERIAL_GRLIB_GAISLER_APBUART
+       tristate "GRLIB APBUART serial support"
+       depends on OF
+       ---help---
+       Add support for the GRLIB APBUART serial port.
+
+config SERIAL_GRLIB_GAISLER_APBUART_CONSOLE
+       bool "Console on GRLIB APBUART serial port"
+       depends on SERIAL_GRLIB_GAISLER_APBUART=y
+       select SERIAL_CORE_CONSOLE
+       help
+       Support for running a console on the GRLIB APBUART
+
+config SERIAL_ALTERA_JTAGUART
+       tristate "Altera JTAG UART support"
+       select SERIAL_CORE
+       help
+         This driver supports the Altera JTAG UART port.
+
+config SERIAL_ALTERA_JTAGUART_CONSOLE
+       bool "Altera JTAG UART console support"
+       depends on SERIAL_ALTERA_JTAGUART=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Enable a Altera JTAG UART port to be the system console.
+
+config SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS
+       bool "Bypass output when no connection"
+       depends on SERIAL_ALTERA_JTAGUART_CONSOLE
+       select SERIAL_CORE_CONSOLE
+       help
+         Bypass console output and keep going even if there is no
+         JTAG terminal connection with the host.
+
+config SERIAL_ALTERA_UART
+       tristate "Altera UART support"
+       select SERIAL_CORE
+       help
+         This driver supports the Altera softcore UART port.
+
+config SERIAL_ALTERA_UART_MAXPORTS
+       int "Maximum number of Altera UART ports"
+       depends on SERIAL_ALTERA_UART
+       default 4
+       help
+         This setting lets you define the maximum number of the Altera
+         UART ports. The usual default varies from board to board, and
+         this setting is a way of catering for that.
+
+config SERIAL_ALTERA_UART_BAUDRATE
+       int "Default baudrate for Altera UART ports"
+       depends on SERIAL_ALTERA_UART
+       default 115200
+       help
+         This setting lets you define what the default baudrate is for the
+         Altera UART ports. The usual default varies from board to board,
+         and this setting is a way of catering for that.
+
+config SERIAL_ALTERA_UART_CONSOLE
+       bool "Altera UART console support"
+       depends on SERIAL_ALTERA_UART=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Enable a Altera UART port to be the system console.
+
+config SERIAL_IFX6X60
+        tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)"
+       depends on GPIOLIB && SPI && EXPERIMENTAL
+       help
+         Support for the IFX6x60 modem devices on Intel MID platforms.
+
+config SERIAL_PCH_UART
+       tristate "Intel EG20T PCH UART"
+       depends on PCI && DMADEVICES
+       select SERIAL_CORE
+       select PCH_DMA
+       help
+         This driver is for PCH(Platform controller Hub) UART of Intel EG20T
+         which is an IOH(Input/Output Hub) for x86 embedded processor.
+         Enabling PCH_DMA, this PCH UART works as DMA mode.
+endmenu
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
new file mode 100644 (file)
index 0000000..8ea92e9
--- /dev/null
@@ -0,0 +1,94 @@
+#
+# Makefile for the kernel serial device drivers.
+#
+
+obj-$(CONFIG_SERIAL_CORE) += serial_core.o
+obj-$(CONFIG_SERIAL_21285) += 21285.o
+
+# These Sparc drivers have to appear before others such as 8250
+# which share ttySx minor node space.  Otherwise console device
+# names change and other unplesantries.
+obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
+obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o
+obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o
+obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o
+obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o
+
+obj-$(CONFIG_SERIAL_8250) += 8250.o
+obj-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
+obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o
+obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o
+obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
+obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o
+obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o
+obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o
+obj-$(CONFIG_SERIAL_8250_FOURPORT) += 8250_fourport.o
+obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o
+obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o
+obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o
+obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
+obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o
+obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o
+obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
+obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
+obj-$(CONFIG_SERIAL_PXA) += pxa.o
+obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o
+obj-$(CONFIG_SERIAL_SA1100) += sa1100.o
+obj-$(CONFIG_SERIAL_BCM63XX) += bcm63xx_uart.o
+obj-$(CONFIG_SERIAL_BFIN) += bfin_5xx.o
+obj-$(CONFIG_SERIAL_BFIN_SPORT) += bfin_sport_uart.o
+obj-$(CONFIG_SERIAL_SAMSUNG) += samsung.o
+obj-$(CONFIG_SERIAL_S3C2400) += s3c2400.o
+obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o
+obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o
+obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o
+obj-$(CONFIG_SERIAL_S3C24A0) += s3c24a0.o
+obj-$(CONFIG_SERIAL_S3C6400) += s3c6400.o
+obj-$(CONFIG_SERIAL_S5PV210) += s5pv210.o
+obj-$(CONFIG_SERIAL_MAX3100) += max3100.o
+obj-$(CONFIG_SERIAL_MAX3107) += max3107.o
+obj-$(CONFIG_SERIAL_MAX3107_AAVA) += max3107-aava.o
+obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
+obj-$(CONFIG_SERIAL_MUX) += mux.o
+obj-$(CONFIG_SERIAL_68328) += 68328serial.o
+obj-$(CONFIG_SERIAL_68360) += 68360serial.o
+obj-$(CONFIG_SERIAL_MCF) += mcf.o
+obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
+obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o
+obj-$(CONFIG_SERIAL_DZ) += dz.o
+obj-$(CONFIG_SERIAL_ZS) += zs.o
+obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
+obj-$(CONFIG_SERIAL_SGI_L1_CONSOLE) += sn_console.o
+obj-$(CONFIG_SERIAL_CPM) += cpm_uart/
+obj-$(CONFIG_SERIAL_IMX) += imx.o
+obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o
+obj-$(CONFIG_SERIAL_ICOM) += icom.o
+obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o
+obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
+obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
+obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
+obj-$(CONFIG_SERIAL_SC26XX) += sc26xx.o
+obj-$(CONFIG_SERIAL_JSM) += jsm/
+obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
+obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
+obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
+obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
+obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
+obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
+obj-$(CONFIG_SERIAL_MSM) += msm_serial.o
+obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
+obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
+obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
+obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
+obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
+obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
+obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
+obj-$(CONFIG_SERIAL_TIMBERDALE)        += timbuart.o
+obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
+obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
+obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
+obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o
+obj-$(CONFIG_SERIAL_MRST_MAX3110)      += mrst_max3110.o
+obj-$(CONFIG_SERIAL_MFD_HSU)   += mfd.o
+obj-$(CONFIG_SERIAL_IFX6X60)   += ifx6x60.o
+obj-$(CONFIG_SERIAL_PCH_UART)  += pch_uart.o
diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c
new file mode 100644 (file)
index 0000000..f9b49b5
--- /dev/null
@@ -0,0 +1,504 @@
+/*
+ * altera_jtaguart.c -- Altera JTAG UART driver
+ *
+ * Based on mcf.c -- Freescale ColdFire UART driver
+ *
+ * (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
+ * (C) Copyright 2008, Thomas Chou <thomas@wytron.com.tw>
+ * (C) Copyright 2010, Tobias Klauser <tklauser@distanz.ch>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/altera_jtaguart.h>
+
+#define DRV_NAME "altera_jtaguart"
+
+/*
+ * Altera JTAG UART register definitions according to the Altera JTAG UART
+ * datasheet: http://www.altera.com/literature/hb/nios2/n2cpu_nii51009.pdf
+ */
+
+#define ALTERA_JTAGUART_SIZE                   8
+
+#define ALTERA_JTAGUART_DATA_REG               0
+
+#define ALTERA_JTAGUART_DATA_DATA_MSK          0x000000FF
+#define ALTERA_JTAGUART_DATA_RVALID_MSK                0x00008000
+#define ALTERA_JTAGUART_DATA_RAVAIL_MSK                0xFFFF0000
+#define ALTERA_JTAGUART_DATA_RAVAIL_OFF                16
+
+#define ALTERA_JTAGUART_CONTROL_REG            4
+
+#define ALTERA_JTAGUART_CONTROL_RE_MSK         0x00000001
+#define ALTERA_JTAGUART_CONTROL_WE_MSK         0x00000002
+#define ALTERA_JTAGUART_CONTROL_RI_MSK         0x00000100
+#define ALTERA_JTAGUART_CONTROL_RI_OFF         8
+#define ALTERA_JTAGUART_CONTROL_WI_MSK         0x00000200
+#define ALTERA_JTAGUART_CONTROL_AC_MSK         0x00000400
+#define ALTERA_JTAGUART_CONTROL_WSPACE_MSK     0xFFFF0000
+#define ALTERA_JTAGUART_CONTROL_WSPACE_OFF     16
+
+/*
+ * Local per-uart structure.
+ */
+struct altera_jtaguart {
+       struct uart_port port;
+       unsigned int sigs;      /* Local copy of line sigs */
+       unsigned long imr;      /* Local IMR mirror */
+};
+
+static unsigned int altera_jtaguart_tx_empty(struct uart_port *port)
+{
+       return (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
+               ALTERA_JTAGUART_CONTROL_WSPACE_MSK) ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int altera_jtaguart_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+static void altera_jtaguart_set_mctrl(struct uart_port *port, unsigned int sigs)
+{
+}
+
+static void altera_jtaguart_start_tx(struct uart_port *port)
+{
+       struct altera_jtaguart *pp =
+           container_of(port, struct altera_jtaguart, port);
+
+       pp->imr |= ALTERA_JTAGUART_CONTROL_WE_MSK;
+       writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
+}
+
+static void altera_jtaguart_stop_tx(struct uart_port *port)
+{
+       struct altera_jtaguart *pp =
+           container_of(port, struct altera_jtaguart, port);
+
+       pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK;
+       writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
+}
+
+static void altera_jtaguart_stop_rx(struct uart_port *port)
+{
+       struct altera_jtaguart *pp =
+           container_of(port, struct altera_jtaguart, port);
+
+       pp->imr &= ~ALTERA_JTAGUART_CONTROL_RE_MSK;
+       writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
+}
+
+static void altera_jtaguart_break_ctl(struct uart_port *port, int break_state)
+{
+}
+
+static void altera_jtaguart_enable_ms(struct uart_port *port)
+{
+}
+
+static void altera_jtaguart_set_termios(struct uart_port *port,
+                                       struct ktermios *termios,
+                                       struct ktermios *old)
+{
+       /* Just copy the old termios settings back */
+       if (old)
+               tty_termios_copy_hw(termios, old);
+}
+
+static void altera_jtaguart_rx_chars(struct altera_jtaguart *pp)
+{
+       struct uart_port *port = &pp->port;
+       unsigned char ch, flag;
+       unsigned long status;
+
+       while ((status = readl(port->membase + ALTERA_JTAGUART_DATA_REG)) &
+              ALTERA_JTAGUART_DATA_RVALID_MSK) {
+               ch = status & ALTERA_JTAGUART_DATA_DATA_MSK;
+               flag = TTY_NORMAL;
+               port->icount.rx++;
+
+               if (uart_handle_sysrq_char(port, ch))
+                       continue;
+               uart_insert_char(port, 0, 0, ch, flag);
+       }
+
+       tty_flip_buffer_push(port->state->port.tty);
+}
+
+static void altera_jtaguart_tx_chars(struct altera_jtaguart *pp)
+{
+       struct uart_port *port = &pp->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       unsigned int pending, count;
+
+       if (port->x_char) {
+               /* Send special char - probably flow control */
+               writel(port->x_char, port->membase + ALTERA_JTAGUART_DATA_REG);
+               port->x_char = 0;
+               port->icount.tx++;
+               return;
+       }
+
+       pending = uart_circ_chars_pending(xmit);
+       if (pending > 0) {
+               count = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
+                               ALTERA_JTAGUART_CONTROL_WSPACE_MSK) >>
+                       ALTERA_JTAGUART_CONTROL_WSPACE_OFF;
+               if (count > pending)
+                       count = pending;
+               if (count > 0) {
+                       pending -= count;
+                       while (count--) {
+                               writel(xmit->buf[xmit->tail],
+                                      port->membase + ALTERA_JTAGUART_DATA_REG);
+                               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+                               port->icount.tx++;
+                       }
+                       if (pending < WAKEUP_CHARS)
+                               uart_write_wakeup(port);
+               }
+       }
+
+       if (pending == 0) {
+               pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK;
+               writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
+       }
+}
+
+static irqreturn_t altera_jtaguart_interrupt(int irq, void *data)
+{
+       struct uart_port *port = data;
+       struct altera_jtaguart *pp =
+           container_of(port, struct altera_jtaguart, port);
+       unsigned int isr;
+
+       isr = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) >>
+              ALTERA_JTAGUART_CONTROL_RI_OFF) & pp->imr;
+
+       spin_lock(&port->lock);
+
+       if (isr & ALTERA_JTAGUART_CONTROL_RE_MSK)
+               altera_jtaguart_rx_chars(pp);
+       if (isr & ALTERA_JTAGUART_CONTROL_WE_MSK)
+               altera_jtaguart_tx_chars(pp);
+
+       spin_unlock(&port->lock);
+
+       return IRQ_RETVAL(isr);
+}
+
+static void altera_jtaguart_config_port(struct uart_port *port, int flags)
+{
+       port->type = PORT_ALTERA_JTAGUART;
+
+       /* Clear mask, so no surprise interrupts. */
+       writel(0, port->membase + ALTERA_JTAGUART_CONTROL_REG);
+}
+
+static int altera_jtaguart_startup(struct uart_port *port)
+{
+       struct altera_jtaguart *pp =
+           container_of(port, struct altera_jtaguart, port);
+       unsigned long flags;
+       int ret;
+
+       ret = request_irq(port->irq, altera_jtaguart_interrupt, IRQF_DISABLED,
+                       DRV_NAME, port);
+       if (ret) {
+               pr_err(DRV_NAME ": unable to attach Altera JTAG UART %d "
+                      "interrupt vector=%d\n", port->line, port->irq);
+               return ret;
+       }
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Enable RX interrupts now */
+       pp->imr = ALTERA_JTAGUART_CONTROL_RE_MSK;
+       writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       return 0;
+}
+
+static void altera_jtaguart_shutdown(struct uart_port *port)
+{
+       struct altera_jtaguart *pp =
+           container_of(port, struct altera_jtaguart, port);
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Disable all interrupts now */
+       pp->imr = 0;
+       writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       free_irq(port->irq, port);
+}
+
+static const char *altera_jtaguart_type(struct uart_port *port)
+{
+       return (port->type == PORT_ALTERA_JTAGUART) ? "Altera JTAG UART" : NULL;
+}
+
+static int altera_jtaguart_request_port(struct uart_port *port)
+{
+       /* UARTs always present */
+       return 0;
+}
+
+static void altera_jtaguart_release_port(struct uart_port *port)
+{
+       /* Nothing to release... */
+}
+
+static int altera_jtaguart_verify_port(struct uart_port *port,
+                                      struct serial_struct *ser)
+{
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_ALTERA_JTAGUART)
+               return -EINVAL;
+       return 0;
+}
+
+/*
+ *     Define the basic serial functions we support.
+ */
+static struct uart_ops altera_jtaguart_ops = {
+       .tx_empty       = altera_jtaguart_tx_empty,
+       .get_mctrl      = altera_jtaguart_get_mctrl,
+       .set_mctrl      = altera_jtaguart_set_mctrl,
+       .start_tx       = altera_jtaguart_start_tx,
+       .stop_tx        = altera_jtaguart_stop_tx,
+       .stop_rx        = altera_jtaguart_stop_rx,
+       .enable_ms      = altera_jtaguart_enable_ms,
+       .break_ctl      = altera_jtaguart_break_ctl,
+       .startup        = altera_jtaguart_startup,
+       .shutdown       = altera_jtaguart_shutdown,
+       .set_termios    = altera_jtaguart_set_termios,
+       .type           = altera_jtaguart_type,
+       .request_port   = altera_jtaguart_request_port,
+       .release_port   = altera_jtaguart_release_port,
+       .config_port    = altera_jtaguart_config_port,
+       .verify_port    = altera_jtaguart_verify_port,
+};
+
+#define ALTERA_JTAGUART_MAXPORTS 1
+static struct altera_jtaguart altera_jtaguart_ports[ALTERA_JTAGUART_MAXPORTS];
+
+#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE)
+
+int __init early_altera_jtaguart_setup(struct altera_jtaguart_platform_uart
+                                      *platp)
+{
+       struct uart_port *port;
+       int i;
+
+       for (i = 0; i < ALTERA_JTAGUART_MAXPORTS && platp[i].mapbase; i++) {
+               port = &altera_jtaguart_ports[i].port;
+
+               port->line = i;
+               port->type = PORT_ALTERA_JTAGUART;
+               port->mapbase = platp[i].mapbase;
+               port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE);
+               port->iotype = SERIAL_IO_MEM;
+               port->irq = platp[i].irq;
+               port->flags = ASYNC_BOOT_AUTOCONF;
+               port->ops = &altera_jtaguart_ops;
+       }
+
+       return 0;
+}
+
+#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS)
+static void altera_jtaguart_console_putc(struct console *co, const char c)
+{
+       struct uart_port *port = &(altera_jtaguart_ports + co->index)->port;
+       unsigned long status;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       while (((status = readl(port->membase + ALTERA_JTAGUART_CONTROL_REG)) &
+               ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) {
+               if ((status & ALTERA_JTAGUART_CONTROL_AC_MSK) == 0) {
+                       spin_unlock_irqrestore(&port->lock, flags);
+                       return; /* no connection activity */
+               }
+               spin_unlock_irqrestore(&port->lock, flags);
+               cpu_relax();
+               spin_lock_irqsave(&port->lock, flags);
+       }
+       writel(c, port->membase + ALTERA_JTAGUART_DATA_REG);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+#else
+static void altera_jtaguart_console_putc(struct console *co, const char c)
+{
+       struct uart_port *port = &(altera_jtaguart_ports + co->index)->port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       while ((readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
+               ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               cpu_relax();
+               spin_lock_irqsave(&port->lock, flags);
+       }
+       writel(c, port->membase + ALTERA_JTAGUART_DATA_REG);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+#endif
+
+static void altera_jtaguart_console_write(struct console *co, const char *s,
+                                         unsigned int count)
+{
+       for (; count; count--, s++) {
+               altera_jtaguart_console_putc(co, *s);
+               if (*s == '\n')
+                       altera_jtaguart_console_putc(co, '\r');
+       }
+}
+
+static int __init altera_jtaguart_console_setup(struct console *co,
+                                               char *options)
+{
+       struct uart_port *port;
+
+       if (co->index < 0 || co->index >= ALTERA_JTAGUART_MAXPORTS)
+               return -EINVAL;
+       port = &altera_jtaguart_ports[co->index].port;
+       if (port->membase == 0)
+               return -ENODEV;
+       return 0;
+}
+
+static struct uart_driver altera_jtaguart_driver;
+
+static struct console altera_jtaguart_console = {
+       .name   = "ttyJ",
+       .write  = altera_jtaguart_console_write,
+       .device = uart_console_device,
+       .setup  = altera_jtaguart_console_setup,
+       .flags  = CON_PRINTBUFFER,
+       .index  = -1,
+       .data   = &altera_jtaguart_driver,
+};
+
+static int __init altera_jtaguart_console_init(void)
+{
+       register_console(&altera_jtaguart_console);
+       return 0;
+}
+
+console_initcall(altera_jtaguart_console_init);
+
+#define        ALTERA_JTAGUART_CONSOLE (&altera_jtaguart_console)
+
+#else
+
+#define        ALTERA_JTAGUART_CONSOLE NULL
+
+#endif /* CONFIG_ALTERA_JTAGUART_CONSOLE */
+
+static struct uart_driver altera_jtaguart_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "altera_jtaguart",
+       .dev_name       = "ttyJ",
+       .major          = ALTERA_JTAGUART_MAJOR,
+       .minor          = ALTERA_JTAGUART_MINOR,
+       .nr             = ALTERA_JTAGUART_MAXPORTS,
+       .cons           = ALTERA_JTAGUART_CONSOLE,
+};
+
+static int __devinit altera_jtaguart_probe(struct platform_device *pdev)
+{
+       struct altera_jtaguart_platform_uart *platp = pdev->dev.platform_data;
+       struct uart_port *port;
+       int i;
+
+       for (i = 0; i < ALTERA_JTAGUART_MAXPORTS && platp[i].mapbase; i++) {
+               port = &altera_jtaguart_ports[i].port;
+
+               port->line = i;
+               port->type = PORT_ALTERA_JTAGUART;
+               port->mapbase = platp[i].mapbase;
+               port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE);
+               port->iotype = SERIAL_IO_MEM;
+               port->irq = platp[i].irq;
+               port->ops = &altera_jtaguart_ops;
+               port->flags = ASYNC_BOOT_AUTOCONF;
+
+               uart_add_one_port(&altera_jtaguart_driver, port);
+       }
+
+       return 0;
+}
+
+static int __devexit altera_jtaguart_remove(struct platform_device *pdev)
+{
+       struct uart_port *port;
+       int i;
+
+       for (i = 0; i < ALTERA_JTAGUART_MAXPORTS; i++) {
+               port = &altera_jtaguart_ports[i].port;
+               if (port)
+                       uart_remove_one_port(&altera_jtaguart_driver, port);
+       }
+
+       return 0;
+}
+
+static struct platform_driver altera_jtaguart_platform_driver = {
+       .probe  = altera_jtaguart_probe,
+       .remove = __devexit_p(altera_jtaguart_remove),
+       .driver = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init altera_jtaguart_init(void)
+{
+       int rc;
+
+       rc = uart_register_driver(&altera_jtaguart_driver);
+       if (rc)
+               return rc;
+       rc = platform_driver_register(&altera_jtaguart_platform_driver);
+       if (rc) {
+               uart_unregister_driver(&altera_jtaguart_driver);
+               return rc;
+       }
+       return 0;
+}
+
+static void __exit altera_jtaguart_exit(void)
+{
+       platform_driver_unregister(&altera_jtaguart_platform_driver);
+       uart_unregister_driver(&altera_jtaguart_driver);
+}
+
+module_init(altera_jtaguart_init);
+module_exit(altera_jtaguart_exit);
+
+MODULE_DESCRIPTION("Altera JTAG UART driver");
+MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c
new file mode 100644 (file)
index 0000000..7212162
--- /dev/null
@@ -0,0 +1,608 @@
+/*
+ * altera_uart.c -- Altera UART driver
+ *
+ * Based on mcf.c -- Freescale ColdFire UART driver
+ *
+ * (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
+ * (C) Copyright 2008, Thomas Chou <thomas@wytron.com.tw>
+ * (C) Copyright 2010, Tobias Klauser <tklauser@distanz.ch>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/altera_uart.h>
+
+#define DRV_NAME "altera_uart"
+#define SERIAL_ALTERA_MAJOR 204
+#define SERIAL_ALTERA_MINOR 213
+
+/*
+ * Altera UART register definitions according to the Nios UART datasheet:
+ * http://www.altera.com/literature/ds/ds_nios_uart.pdf
+ */
+
+#define ALTERA_UART_SIZE               32
+
+#define ALTERA_UART_RXDATA_REG         0
+#define ALTERA_UART_TXDATA_REG         4
+#define ALTERA_UART_STATUS_REG         8
+#define ALTERA_UART_CONTROL_REG                12
+#define ALTERA_UART_DIVISOR_REG                16
+#define ALTERA_UART_EOP_REG            20
+
+#define ALTERA_UART_STATUS_PE_MSK      0x0001  /* parity error */
+#define ALTERA_UART_STATUS_FE_MSK      0x0002  /* framing error */
+#define ALTERA_UART_STATUS_BRK_MSK     0x0004  /* break */
+#define ALTERA_UART_STATUS_ROE_MSK     0x0008  /* RX overrun error */
+#define ALTERA_UART_STATUS_TOE_MSK     0x0010  /* TX overrun error */
+#define ALTERA_UART_STATUS_TMT_MSK     0x0020  /* TX shift register state */
+#define ALTERA_UART_STATUS_TRDY_MSK    0x0040  /* TX ready */
+#define ALTERA_UART_STATUS_RRDY_MSK    0x0080  /* RX ready */
+#define ALTERA_UART_STATUS_E_MSK       0x0100  /* exception condition */
+#define ALTERA_UART_STATUS_DCTS_MSK    0x0400  /* CTS logic-level change */
+#define ALTERA_UART_STATUS_CTS_MSK     0x0800  /* CTS logic state */
+#define ALTERA_UART_STATUS_EOP_MSK     0x1000  /* EOP written/read */
+
+                                               /* Enable interrupt on... */
+#define ALTERA_UART_CONTROL_PE_MSK     0x0001  /* ...parity error */
+#define ALTERA_UART_CONTROL_FE_MSK     0x0002  /* ...framing error */
+#define ALTERA_UART_CONTROL_BRK_MSK    0x0004  /* ...break */
+#define ALTERA_UART_CONTROL_ROE_MSK    0x0008  /* ...RX overrun */
+#define ALTERA_UART_CONTROL_TOE_MSK    0x0010  /* ...TX overrun */
+#define ALTERA_UART_CONTROL_TMT_MSK    0x0020  /* ...TX shift register empty */
+#define ALTERA_UART_CONTROL_TRDY_MSK   0x0040  /* ...TX ready */
+#define ALTERA_UART_CONTROL_RRDY_MSK   0x0080  /* ...RX ready */
+#define ALTERA_UART_CONTROL_E_MSK      0x0100  /* ...exception*/
+
+#define ALTERA_UART_CONTROL_TRBK_MSK   0x0200  /* TX break */
+#define ALTERA_UART_CONTROL_DCTS_MSK   0x0400  /* Interrupt on CTS change */
+#define ALTERA_UART_CONTROL_RTS_MSK    0x0800  /* RTS signal */
+#define ALTERA_UART_CONTROL_EOP_MSK    0x1000  /* Interrupt on EOP */
+
+/*
+ * Local per-uart structure.
+ */
+struct altera_uart {
+       struct uart_port port;
+       struct timer_list tmr;
+       unsigned int sigs;      /* Local copy of line sigs */
+       unsigned short imr;     /* Local IMR mirror */
+};
+
+static u32 altera_uart_readl(struct uart_port *port, int reg)
+{
+       struct altera_uart_platform_uart *platp = port->private_data;
+
+       return readl(port->membase + (reg << platp->bus_shift));
+}
+
+static void altera_uart_writel(struct uart_port *port, u32 dat, int reg)
+{
+       struct altera_uart_platform_uart *platp = port->private_data;
+
+       writel(dat, port->membase + (reg << platp->bus_shift));
+}
+
+static unsigned int altera_uart_tx_empty(struct uart_port *port)
+{
+       return (altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
+               ALTERA_UART_STATUS_TMT_MSK) ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int altera_uart_get_mctrl(struct uart_port *port)
+{
+       struct altera_uart *pp = container_of(port, struct altera_uart, port);
+       unsigned int sigs;
+
+       sigs = (altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
+            ALTERA_UART_STATUS_CTS_MSK) ? TIOCM_CTS : 0;
+       sigs |= (pp->sigs & TIOCM_RTS);
+
+       return sigs;
+}
+
+static void altera_uart_set_mctrl(struct uart_port *port, unsigned int sigs)
+{
+       struct altera_uart *pp = container_of(port, struct altera_uart, port);
+
+       pp->sigs = sigs;
+       if (sigs & TIOCM_RTS)
+               pp->imr |= ALTERA_UART_CONTROL_RTS_MSK;
+       else
+               pp->imr &= ~ALTERA_UART_CONTROL_RTS_MSK;
+       altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
+}
+
+static void altera_uart_start_tx(struct uart_port *port)
+{
+       struct altera_uart *pp = container_of(port, struct altera_uart, port);
+
+       pp->imr |= ALTERA_UART_CONTROL_TRDY_MSK;
+       altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
+}
+
+static void altera_uart_stop_tx(struct uart_port *port)
+{
+       struct altera_uart *pp = container_of(port, struct altera_uart, port);
+
+       pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK;
+       altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
+}
+
+static void altera_uart_stop_rx(struct uart_port *port)
+{
+       struct altera_uart *pp = container_of(port, struct altera_uart, port);
+
+       pp->imr &= ~ALTERA_UART_CONTROL_RRDY_MSK;
+       altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
+}
+
+static void altera_uart_break_ctl(struct uart_port *port, int break_state)
+{
+       struct altera_uart *pp = container_of(port, struct altera_uart, port);
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       if (break_state == -1)
+               pp->imr |= ALTERA_UART_CONTROL_TRBK_MSK;
+       else
+               pp->imr &= ~ALTERA_UART_CONTROL_TRBK_MSK;
+       altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void altera_uart_enable_ms(struct uart_port *port)
+{
+}
+
+static void altera_uart_set_termios(struct uart_port *port,
+                                   struct ktermios *termios,
+                                   struct ktermios *old)
+{
+       unsigned long flags;
+       unsigned int baud, baudclk;
+
+       baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
+       baudclk = port->uartclk / baud;
+
+       if (old)
+               tty_termios_copy_hw(termios, old);
+       tty_termios_encode_baud_rate(termios, baud, baud);
+
+       spin_lock_irqsave(&port->lock, flags);
+       uart_update_timeout(port, termios->c_cflag, baud);
+       altera_uart_writel(port, baudclk, ALTERA_UART_DIVISOR_REG);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void altera_uart_rx_chars(struct altera_uart *pp)
+{
+       struct uart_port *port = &pp->port;
+       unsigned char ch, flag;
+       unsigned short status;
+
+       while ((status = altera_uart_readl(port, ALTERA_UART_STATUS_REG)) &
+              ALTERA_UART_STATUS_RRDY_MSK) {
+               ch = altera_uart_readl(port, ALTERA_UART_RXDATA_REG);
+               flag = TTY_NORMAL;
+               port->icount.rx++;
+
+               if (status & ALTERA_UART_STATUS_E_MSK) {
+                       altera_uart_writel(port, status,
+                                          ALTERA_UART_STATUS_REG);
+
+                       if (status & ALTERA_UART_STATUS_BRK_MSK) {
+                               port->icount.brk++;
+                               if (uart_handle_break(port))
+                                       continue;
+                       } else if (status & ALTERA_UART_STATUS_PE_MSK) {
+                               port->icount.parity++;
+                       } else if (status & ALTERA_UART_STATUS_ROE_MSK) {
+                               port->icount.overrun++;
+                       } else if (status & ALTERA_UART_STATUS_FE_MSK) {
+                               port->icount.frame++;
+                       }
+
+                       status &= port->read_status_mask;
+
+                       if (status & ALTERA_UART_STATUS_BRK_MSK)
+                               flag = TTY_BREAK;
+                       else if (status & ALTERA_UART_STATUS_PE_MSK)
+                               flag = TTY_PARITY;
+                       else if (status & ALTERA_UART_STATUS_FE_MSK)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(port, ch))
+                       continue;
+               uart_insert_char(port, status, ALTERA_UART_STATUS_ROE_MSK, ch,
+                                flag);
+       }
+
+       tty_flip_buffer_push(port->state->port.tty);
+}
+
+static void altera_uart_tx_chars(struct altera_uart *pp)
+{
+       struct uart_port *port = &pp->port;
+       struct circ_buf *xmit = &port->state->xmit;
+
+       if (port->x_char) {
+               /* Send special char - probably flow control */
+               altera_uart_writel(port, port->x_char, ALTERA_UART_TXDATA_REG);
+               port->x_char = 0;
+               port->icount.tx++;
+               return;
+       }
+
+       while (altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
+              ALTERA_UART_STATUS_TRDY_MSK) {
+               if (xmit->head == xmit->tail)
+                       break;
+               altera_uart_writel(port, xmit->buf[xmit->tail],
+                      ALTERA_UART_TXDATA_REG);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (xmit->head == xmit->tail) {
+               pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK;
+               altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
+       }
+}
+
+static irqreturn_t altera_uart_interrupt(int irq, void *data)
+{
+       struct uart_port *port = data;
+       struct altera_uart *pp = container_of(port, struct altera_uart, port);
+       unsigned int isr;
+
+       isr = altera_uart_readl(port, ALTERA_UART_STATUS_REG) & pp->imr;
+
+       spin_lock(&port->lock);
+       if (isr & ALTERA_UART_STATUS_RRDY_MSK)
+               altera_uart_rx_chars(pp);
+       if (isr & ALTERA_UART_STATUS_TRDY_MSK)
+               altera_uart_tx_chars(pp);
+       spin_unlock(&port->lock);
+
+       return IRQ_RETVAL(isr);
+}
+
+static void altera_uart_timer(unsigned long data)
+{
+       struct uart_port *port = (void *)data;
+       struct altera_uart *pp = container_of(port, struct altera_uart, port);
+
+       altera_uart_interrupt(0, port);
+       mod_timer(&pp->tmr, jiffies + uart_poll_timeout(port));
+}
+
+static void altera_uart_config_port(struct uart_port *port, int flags)
+{
+       port->type = PORT_ALTERA_UART;
+
+       /* Clear mask, so no surprise interrupts. */
+       altera_uart_writel(port, 0, ALTERA_UART_CONTROL_REG);
+       /* Clear status register */
+       altera_uart_writel(port, 0, ALTERA_UART_STATUS_REG);
+}
+
+static int altera_uart_startup(struct uart_port *port)
+{
+       struct altera_uart *pp = container_of(port, struct altera_uart, port);
+       unsigned long flags;
+       int ret;
+
+       if (!port->irq) {
+               setup_timer(&pp->tmr, altera_uart_timer, (unsigned long)port);
+               mod_timer(&pp->tmr, jiffies + uart_poll_timeout(port));
+               return 0;
+       }
+
+       ret = request_irq(port->irq, altera_uart_interrupt, IRQF_DISABLED,
+                       DRV_NAME, port);
+       if (ret) {
+               pr_err(DRV_NAME ": unable to attach Altera UART %d "
+                      "interrupt vector=%d\n", port->line, port->irq);
+               return ret;
+       }
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Enable RX interrupts now */
+       pp->imr = ALTERA_UART_CONTROL_RRDY_MSK;
+       writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       return 0;
+}
+
+static void altera_uart_shutdown(struct uart_port *port)
+{
+       struct altera_uart *pp = container_of(port, struct altera_uart, port);
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Disable all interrupts now */
+       pp->imr = 0;
+       writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       if (port->irq)
+               free_irq(port->irq, port);
+       else
+               del_timer_sync(&pp->tmr);
+}
+
+static const char *altera_uart_type(struct uart_port *port)
+{
+       return (port->type == PORT_ALTERA_UART) ? "Altera UART" : NULL;
+}
+
+static int altera_uart_request_port(struct uart_port *port)
+{
+       /* UARTs always present */
+       return 0;
+}
+
+static void altera_uart_release_port(struct uart_port *port)
+{
+       /* Nothing to release... */
+}
+
+static int altera_uart_verify_port(struct uart_port *port,
+                                  struct serial_struct *ser)
+{
+       if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_ALTERA_UART))
+               return -EINVAL;
+       return 0;
+}
+
+/*
+ *     Define the basic serial functions we support.
+ */
+static struct uart_ops altera_uart_ops = {
+       .tx_empty       = altera_uart_tx_empty,
+       .get_mctrl      = altera_uart_get_mctrl,
+       .set_mctrl      = altera_uart_set_mctrl,
+       .start_tx       = altera_uart_start_tx,
+       .stop_tx        = altera_uart_stop_tx,
+       .stop_rx        = altera_uart_stop_rx,
+       .enable_ms      = altera_uart_enable_ms,
+       .break_ctl      = altera_uart_break_ctl,
+       .startup        = altera_uart_startup,
+       .shutdown       = altera_uart_shutdown,
+       .set_termios    = altera_uart_set_termios,
+       .type           = altera_uart_type,
+       .request_port   = altera_uart_request_port,
+       .release_port   = altera_uart_release_port,
+       .config_port    = altera_uart_config_port,
+       .verify_port    = altera_uart_verify_port,
+};
+
+static struct altera_uart altera_uart_ports[CONFIG_SERIAL_ALTERA_UART_MAXPORTS];
+
+#if defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE)
+
+int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp)
+{
+       struct uart_port *port;
+       int i;
+
+       for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS && platp[i].mapbase; i++) {
+               port = &altera_uart_ports[i].port;
+
+               port->line = i;
+               port->type = PORT_ALTERA_UART;
+               port->mapbase = platp[i].mapbase;
+               port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE);
+               port->iotype = SERIAL_IO_MEM;
+               port->irq = platp[i].irq;
+               port->uartclk = platp[i].uartclk;
+               port->flags = UPF_BOOT_AUTOCONF;
+               port->ops = &altera_uart_ops;
+               port->private_data = platp;
+       }
+
+       return 0;
+}
+
+static void altera_uart_console_putc(struct uart_port *port, const char c)
+{
+       while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
+                ALTERA_UART_STATUS_TRDY_MSK))
+               cpu_relax();
+
+       writel(c, port->membase + ALTERA_UART_TXDATA_REG);
+}
+
+static void altera_uart_console_write(struct console *co, const char *s,
+                                     unsigned int count)
+{
+       struct uart_port *port = &(altera_uart_ports + co->index)->port;
+
+       for (; count; count--, s++) {
+               altera_uart_console_putc(port, *s);
+               if (*s == '\n')
+                       altera_uart_console_putc(port, '\r');
+       }
+}
+
+static int __init altera_uart_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       int baud = CONFIG_SERIAL_ALTERA_UART_BAUDRATE;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (co->index < 0 || co->index >= CONFIG_SERIAL_ALTERA_UART_MAXPORTS)
+               return -EINVAL;
+       port = &altera_uart_ports[co->index].port;
+       if (!port->membase)
+               return -ENODEV;
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver altera_uart_driver;
+
+static struct console altera_uart_console = {
+       .name   = "ttyAL",
+       .write  = altera_uart_console_write,
+       .device = uart_console_device,
+       .setup  = altera_uart_console_setup,
+       .flags  = CON_PRINTBUFFER,
+       .index  = -1,
+       .data   = &altera_uart_driver,
+};
+
+static int __init altera_uart_console_init(void)
+{
+       register_console(&altera_uart_console);
+       return 0;
+}
+
+console_initcall(altera_uart_console_init);
+
+#define        ALTERA_UART_CONSOLE     (&altera_uart_console)
+
+#else
+
+#define        ALTERA_UART_CONSOLE     NULL
+
+#endif /* CONFIG_ALTERA_UART_CONSOLE */
+
+/*
+ *     Define the altera_uart UART driver structure.
+ */
+static struct uart_driver altera_uart_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = DRV_NAME,
+       .dev_name       = "ttyAL",
+       .major          = SERIAL_ALTERA_MAJOR,
+       .minor          = SERIAL_ALTERA_MINOR,
+       .nr             = CONFIG_SERIAL_ALTERA_UART_MAXPORTS,
+       .cons           = ALTERA_UART_CONSOLE,
+};
+
+static int __devinit altera_uart_probe(struct platform_device *pdev)
+{
+       struct altera_uart_platform_uart *platp = pdev->dev.platform_data;
+       struct uart_port *port;
+       struct resource *res_mem;
+       struct resource *res_irq;
+       int i = pdev->id;
+
+       /* -1 emphasizes that the platform must have one port, no .N suffix */
+       if (i == -1)
+               i = 0;
+
+       if (i >= CONFIG_SERIAL_ALTERA_UART_MAXPORTS)
+               return -EINVAL;
+
+       port = &altera_uart_ports[i].port;
+
+       res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res_mem)
+               port->mapbase = res_mem->start;
+       else if (platp->mapbase)
+               port->mapbase = platp->mapbase;
+       else
+               return -EINVAL;
+
+       res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (res_irq)
+               port->irq = res_irq->start;
+       else if (platp->irq)
+               port->irq = platp->irq;
+
+       port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE);
+       if (!port->membase)
+               return -ENOMEM;
+
+       port->line = i;
+       port->type = PORT_ALTERA_UART;
+       port->iotype = SERIAL_IO_MEM;
+       port->uartclk = platp->uartclk;
+       port->ops = &altera_uart_ops;
+       port->flags = UPF_BOOT_AUTOCONF;
+       port->private_data = platp;
+
+       uart_add_one_port(&altera_uart_driver, port);
+
+       return 0;
+}
+
+static int __devexit altera_uart_remove(struct platform_device *pdev)
+{
+       struct uart_port *port = &altera_uart_ports[pdev->id].port;
+
+       uart_remove_one_port(&altera_uart_driver, port);
+       return 0;
+}
+
+static struct platform_driver altera_uart_platform_driver = {
+       .probe  = altera_uart_probe,
+       .remove = __devexit_p(altera_uart_remove),
+       .driver = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+               .pm     = NULL,
+       },
+};
+
+static int __init altera_uart_init(void)
+{
+       int rc;
+
+       rc = uart_register_driver(&altera_uart_driver);
+       if (rc)
+               return rc;
+       rc = platform_driver_register(&altera_uart_platform_driver);
+       if (rc) {
+               uart_unregister_driver(&altera_uart_driver);
+               return rc;
+       }
+       return 0;
+}
+
+static void __exit altera_uart_exit(void)
+{
+       platform_driver_unregister(&altera_uart_platform_driver);
+       uart_unregister_driver(&altera_uart_driver);
+}
+
+module_init(altera_uart_init);
+module_exit(altera_uart_exit);
+
+MODULE_DESCRIPTION("Altera UART driver");
+MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_ALTERA_MAJOR);
diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c
new file mode 100644 (file)
index 0000000..2904aa0
--- /dev/null
@@ -0,0 +1,825 @@
+/*
+ *  linux/drivers/char/amba.c
+ *
+ *  Driver for AMBA serial ports
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ *  Copyright 1999 ARM Limited
+ *  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
+ *
+ * This is a generic driver for ARM AMBA-type serial ports.  They
+ * have a lot of 16550-like features, but are not register compatible.
+ * Note that although they do have CTS, DCD and DSR inputs, they do
+ * not have an RI input, nor do they have DTR or RTS outputs.  If
+ * required, these have to be supplied via some other means (eg, GPIO)
+ * and hooked into this driver.
+ */
+
+#if defined(CONFIG_SERIAL_AMBA_PL010_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/serial.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+
+#include <asm/io.h>
+
+#define UART_NR                8
+
+#define SERIAL_AMBA_MAJOR      204
+#define SERIAL_AMBA_MINOR      16
+#define SERIAL_AMBA_NR         UART_NR
+
+#define AMBA_ISR_PASS_LIMIT    256
+
+#define UART_RX_DATA(s)                (((s) & UART01x_FR_RXFE) == 0)
+#define UART_TX_READY(s)       (((s) & UART01x_FR_TXFF) == 0)
+
+#define UART_DUMMY_RSR_RX      256
+#define UART_PORT_SIZE         64
+
+/*
+ * We wrap our port structure around the generic uart_port.
+ */
+struct uart_amba_port {
+       struct uart_port        port;
+       struct clk              *clk;
+       struct amba_device      *dev;
+       struct amba_pl010_data  *data;
+       unsigned int            old_status;
+};
+
+static void pl010_stop_tx(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int cr;
+
+       cr = readb(uap->port.membase + UART010_CR);
+       cr &= ~UART010_CR_TIE;
+       writel(cr, uap->port.membase + UART010_CR);
+}
+
+static void pl010_start_tx(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int cr;
+
+       cr = readb(uap->port.membase + UART010_CR);
+       cr |= UART010_CR_TIE;
+       writel(cr, uap->port.membase + UART010_CR);
+}
+
+static void pl010_stop_rx(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int cr;
+
+       cr = readb(uap->port.membase + UART010_CR);
+       cr &= ~(UART010_CR_RIE | UART010_CR_RTIE);
+       writel(cr, uap->port.membase + UART010_CR);
+}
+
+static void pl010_enable_ms(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int cr;
+
+       cr = readb(uap->port.membase + UART010_CR);
+       cr |= UART010_CR_MSIE;
+       writel(cr, uap->port.membase + UART010_CR);
+}
+
+static void pl010_rx_chars(struct uart_amba_port *uap)
+{
+       struct tty_struct *tty = uap->port.state->port.tty;
+       unsigned int status, ch, flag, rsr, max_count = 256;
+
+       status = readb(uap->port.membase + UART01x_FR);
+       while (UART_RX_DATA(status) && max_count--) {
+               ch = readb(uap->port.membase + UART01x_DR);
+               flag = TTY_NORMAL;
+
+               uap->port.icount.rx++;
+
+               /*
+                * Note that the error handling code is
+                * out of the main execution path
+                */
+               rsr = readb(uap->port.membase + UART01x_RSR) | UART_DUMMY_RSR_RX;
+               if (unlikely(rsr & UART01x_RSR_ANY)) {
+                       writel(0, uap->port.membase + UART01x_ECR);
+
+                       if (rsr & UART01x_RSR_BE) {
+                               rsr &= ~(UART01x_RSR_FE | UART01x_RSR_PE);
+                               uap->port.icount.brk++;
+                               if (uart_handle_break(&uap->port))
+                                       goto ignore_char;
+                       } else if (rsr & UART01x_RSR_PE)
+                               uap->port.icount.parity++;
+                       else if (rsr & UART01x_RSR_FE)
+                               uap->port.icount.frame++;
+                       if (rsr & UART01x_RSR_OE)
+                               uap->port.icount.overrun++;
+
+                       rsr &= uap->port.read_status_mask;
+
+                       if (rsr & UART01x_RSR_BE)
+                               flag = TTY_BREAK;
+                       else if (rsr & UART01x_RSR_PE)
+                               flag = TTY_PARITY;
+                       else if (rsr & UART01x_RSR_FE)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(&uap->port, ch))
+                       goto ignore_char;
+
+               uart_insert_char(&uap->port, rsr, UART01x_RSR_OE, ch, flag);
+
+       ignore_char:
+               status = readb(uap->port.membase + UART01x_FR);
+       }
+       spin_unlock(&uap->port.lock);
+       tty_flip_buffer_push(tty);
+       spin_lock(&uap->port.lock);
+}
+
+static void pl010_tx_chars(struct uart_amba_port *uap)
+{
+       struct circ_buf *xmit = &uap->port.state->xmit;
+       int count;
+
+       if (uap->port.x_char) {
+               writel(uap->port.x_char, uap->port.membase + UART01x_DR);
+               uap->port.icount.tx++;
+               uap->port.x_char = 0;
+               return;
+       }
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) {
+               pl010_stop_tx(&uap->port);
+               return;
+       }
+
+       count = uap->port.fifosize >> 1;
+       do {
+               writel(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               uap->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (--count > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&uap->port);
+
+       if (uart_circ_empty(xmit))
+               pl010_stop_tx(&uap->port);
+}
+
+static void pl010_modem_status(struct uart_amba_port *uap)
+{
+       unsigned int status, delta;
+
+       writel(0, uap->port.membase + UART010_ICR);
+
+       status = readb(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
+
+       delta = status ^ uap->old_status;
+       uap->old_status = status;
+
+       if (!delta)
+               return;
+
+       if (delta & UART01x_FR_DCD)
+               uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD);
+
+       if (delta & UART01x_FR_DSR)
+               uap->port.icount.dsr++;
+
+       if (delta & UART01x_FR_CTS)
+               uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS);
+
+       wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
+}
+
+static irqreturn_t pl010_int(int irq, void *dev_id)
+{
+       struct uart_amba_port *uap = dev_id;
+       unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
+       int handled = 0;
+
+       spin_lock(&uap->port.lock);
+
+       status = readb(uap->port.membase + UART010_IIR);
+       if (status) {
+               do {
+                       if (status & (UART010_IIR_RTIS | UART010_IIR_RIS))
+                               pl010_rx_chars(uap);
+                       if (status & UART010_IIR_MIS)
+                               pl010_modem_status(uap);
+                       if (status & UART010_IIR_TIS)
+                               pl010_tx_chars(uap);
+
+                       if (pass_counter-- == 0)
+                               break;
+
+                       status = readb(uap->port.membase + UART010_IIR);
+               } while (status & (UART010_IIR_RTIS | UART010_IIR_RIS |
+                                  UART010_IIR_TIS));
+               handled = 1;
+       }
+
+       spin_unlock(&uap->port.lock);
+
+       return IRQ_RETVAL(handled);
+}
+
+static unsigned int pl010_tx_empty(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int status = readb(uap->port.membase + UART01x_FR);
+       return status & UART01x_FR_BUSY ? 0 : TIOCSER_TEMT;
+}
+
+static unsigned int pl010_get_mctrl(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int result = 0;
+       unsigned int status;
+
+       status = readb(uap->port.membase + UART01x_FR);
+       if (status & UART01x_FR_DCD)
+               result |= TIOCM_CAR;
+       if (status & UART01x_FR_DSR)
+               result |= TIOCM_DSR;
+       if (status & UART01x_FR_CTS)
+               result |= TIOCM_CTS;
+
+       return result;
+}
+
+static void pl010_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+
+       if (uap->data)
+               uap->data->set_mctrl(uap->dev, uap->port.membase, mctrl);
+}
+
+static void pl010_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned long flags;
+       unsigned int lcr_h;
+
+       spin_lock_irqsave(&uap->port.lock, flags);
+       lcr_h = readb(uap->port.membase + UART010_LCRH);
+       if (break_state == -1)
+               lcr_h |= UART01x_LCRH_BRK;
+       else
+               lcr_h &= ~UART01x_LCRH_BRK;
+       writel(lcr_h, uap->port.membase + UART010_LCRH);
+       spin_unlock_irqrestore(&uap->port.lock, flags);
+}
+
+static int pl010_startup(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       int retval;
+
+       /*
+        * Try to enable the clock producer.
+        */
+       retval = clk_enable(uap->clk);
+       if (retval)
+               goto out;
+
+       uap->port.uartclk = clk_get_rate(uap->clk);
+
+       /*
+        * Allocate the IRQ
+        */
+       retval = request_irq(uap->port.irq, pl010_int, 0, "uart-pl010", uap);
+       if (retval)
+               goto clk_dis;
+
+       /*
+        * initialise the old status of the modem signals
+        */
+       uap->old_status = readb(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
+
+       /*
+        * Finally, enable interrupts
+        */
+       writel(UART01x_CR_UARTEN | UART010_CR_RIE | UART010_CR_RTIE,
+              uap->port.membase + UART010_CR);
+
+       return 0;
+
+ clk_dis:
+       clk_disable(uap->clk);
+ out:
+       return retval;
+}
+
+static void pl010_shutdown(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+
+       /*
+        * Free the interrupt
+        */
+       free_irq(uap->port.irq, uap);
+
+       /*
+        * disable all interrupts, disable the port
+        */
+       writel(0, uap->port.membase + UART010_CR);
+
+       /* disable break condition and fifos */
+       writel(readb(uap->port.membase + UART010_LCRH) &
+               ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN),
+              uap->port.membase + UART010_LCRH);
+
+       /*
+        * Shut down the clock producer
+        */
+       clk_disable(uap->clk);
+}
+
+static void
+pl010_set_termios(struct uart_port *port, struct ktermios *termios,
+                    struct ktermios *old)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int lcr_h, old_cr;
+       unsigned long flags;
+       unsigned int baud, quot;
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old, 0, uap->port.uartclk/16); 
+       quot = uart_get_divisor(port, baud);
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               lcr_h = UART01x_LCRH_WLEN_5;
+               break;
+       case CS6:
+               lcr_h = UART01x_LCRH_WLEN_6;
+               break;
+       case CS7:
+               lcr_h = UART01x_LCRH_WLEN_7;
+               break;
+       default: // CS8
+               lcr_h = UART01x_LCRH_WLEN_8;
+               break;
+       }
+       if (termios->c_cflag & CSTOPB)
+               lcr_h |= UART01x_LCRH_STP2;
+       if (termios->c_cflag & PARENB) {
+               lcr_h |= UART01x_LCRH_PEN;
+               if (!(termios->c_cflag & PARODD))
+                       lcr_h |= UART01x_LCRH_EPS;
+       }
+       if (uap->port.fifosize > 1)
+               lcr_h |= UART01x_LCRH_FEN;
+
+       spin_lock_irqsave(&uap->port.lock, flags);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       uap->port.read_status_mask = UART01x_RSR_OE;
+       if (termios->c_iflag & INPCK)
+               uap->port.read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               uap->port.read_status_mask |= UART01x_RSR_BE;
+
+       /*
+        * Characters to ignore
+        */
+       uap->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               uap->port.ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
+       if (termios->c_iflag & IGNBRK) {
+               uap->port.ignore_status_mask |= UART01x_RSR_BE;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       uap->port.ignore_status_mask |= UART01x_RSR_OE;
+       }
+
+       /*
+        * Ignore all characters if CREAD is not set.
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               uap->port.ignore_status_mask |= UART_DUMMY_RSR_RX;
+
+       /* first, disable everything */
+       old_cr = readb(uap->port.membase + UART010_CR) & ~UART010_CR_MSIE;
+
+       if (UART_ENABLE_MS(port, termios->c_cflag))
+               old_cr |= UART010_CR_MSIE;
+
+       writel(0, uap->port.membase + UART010_CR);
+
+       /* Set baud rate */
+       quot -= 1;
+       writel((quot & 0xf00) >> 8, uap->port.membase + UART010_LCRM);
+       writel(quot & 0xff, uap->port.membase + UART010_LCRL);
+
+       /*
+        * ----------v----------v----------v----------v-----
+        * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
+        * ----------^----------^----------^----------^-----
+        */
+       writel(lcr_h, uap->port.membase + UART010_LCRH);
+       writel(old_cr, uap->port.membase + UART010_CR);
+
+       spin_unlock_irqrestore(&uap->port.lock, flags);
+}
+
+static void pl010_set_ldisc(struct uart_port *port, int new)
+{
+       if (new == N_PPS) {
+               port->flags |= UPF_HARDPPS_CD;
+               pl010_enable_ms(port);
+       } else
+               port->flags &= ~UPF_HARDPPS_CD;
+}
+
+static const char *pl010_type(struct uart_port *port)
+{
+       return port->type == PORT_AMBA ? "AMBA" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'
+ */
+static void pl010_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 pl010_request_port(struct uart_port *port)
+{
+       return request_mem_region(port->mapbase, UART_PORT_SIZE, "uart-pl010")
+                       != NULL ? 0 : -EBUSY;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void pl010_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = PORT_AMBA;
+               pl010_request_port(port);
+       }
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       int ret = 0;
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
+               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 amba_pl010_pops = {
+       .tx_empty       = pl010_tx_empty,
+       .set_mctrl      = pl010_set_mctrl,
+       .get_mctrl      = pl010_get_mctrl,
+       .stop_tx        = pl010_stop_tx,
+       .start_tx       = pl010_start_tx,
+       .stop_rx        = pl010_stop_rx,
+       .enable_ms      = pl010_enable_ms,
+       .break_ctl      = pl010_break_ctl,
+       .startup        = pl010_startup,
+       .shutdown       = pl010_shutdown,
+       .set_termios    = pl010_set_termios,
+       .set_ldisc      = pl010_set_ldisc,
+       .type           = pl010_type,
+       .release_port   = pl010_release_port,
+       .request_port   = pl010_request_port,
+       .config_port    = pl010_config_port,
+       .verify_port    = pl010_verify_port,
+};
+
+static struct uart_amba_port *amba_ports[UART_NR];
+
+#ifdef CONFIG_SERIAL_AMBA_PL010_CONSOLE
+
+static void pl010_console_putchar(struct uart_port *port, int ch)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int status;
+
+       do {
+               status = readb(uap->port.membase + UART01x_FR);
+               barrier();
+       } while (!UART_TX_READY(status));
+       writel(ch, uap->port.membase + UART01x_DR);
+}
+
+static void
+pl010_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct uart_amba_port *uap = amba_ports[co->index];
+       unsigned int status, old_cr;
+
+       clk_enable(uap->clk);
+
+       /*
+        *      First save the CR then disable the interrupts
+        */
+       old_cr = readb(uap->port.membase + UART010_CR);
+       writel(UART01x_CR_UARTEN, uap->port.membase + UART010_CR);
+
+       uart_console_write(&uap->port, s, count, pl010_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the TCR
+        */
+       do {
+               status = readb(uap->port.membase + UART01x_FR);
+               barrier();
+       } while (status & UART01x_FR_BUSY);
+       writel(old_cr, uap->port.membase + UART010_CR);
+
+       clk_disable(uap->clk);
+}
+
+static void __init
+pl010_console_get_options(struct uart_amba_port *uap, int *baud,
+                            int *parity, int *bits)
+{
+       if (readb(uap->port.membase + UART010_CR) & UART01x_CR_UARTEN) {
+               unsigned int lcr_h, quot;
+               lcr_h = readb(uap->port.membase + UART010_LCRH);
+
+               *parity = 'n';
+               if (lcr_h & UART01x_LCRH_PEN) {
+                       if (lcr_h & UART01x_LCRH_EPS)
+                               *parity = 'e';
+                       else
+                               *parity = 'o';
+               }
+
+               if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7)
+                       *bits = 7;
+               else
+                       *bits = 8;
+
+               quot = readb(uap->port.membase + UART010_LCRL) |
+                      readb(uap->port.membase + UART010_LCRM) << 8;
+               *baud = uap->port.uartclk / (16 * (quot + 1));
+       }
+}
+
+static int __init pl010_console_setup(struct console *co, char *options)
+{
+       struct uart_amba_port *uap;
+       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.
+        */
+       if (co->index >= UART_NR)
+               co->index = 0;
+       uap = amba_ports[co->index];
+       if (!uap)
+               return -ENODEV;
+
+       uap->port.uartclk = clk_get_rate(uap->clk);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               pl010_console_get_options(uap, &baud, &parity, &bits);
+
+       return uart_set_options(&uap->port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver amba_reg;
+static struct console amba_console = {
+       .name           = "ttyAM",
+       .write          = pl010_console_write,
+       .device         = uart_console_device,
+       .setup          = pl010_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &amba_reg,
+};
+
+#define AMBA_CONSOLE   &amba_console
+#else
+#define AMBA_CONSOLE   NULL
+#endif
+
+static struct uart_driver amba_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "ttyAM",
+       .dev_name               = "ttyAM",
+       .major                  = SERIAL_AMBA_MAJOR,
+       .minor                  = SERIAL_AMBA_MINOR,
+       .nr                     = UART_NR,
+       .cons                   = AMBA_CONSOLE,
+};
+
+static int pl010_probe(struct amba_device *dev, struct amba_id *id)
+{
+       struct uart_amba_port *uap;
+       void __iomem *base;
+       int i, ret;
+
+       for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
+               if (amba_ports[i] == NULL)
+                       break;
+
+       if (i == ARRAY_SIZE(amba_ports)) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
+       if (!uap) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       base = ioremap(dev->res.start, resource_size(&dev->res));
+       if (!base) {
+               ret = -ENOMEM;
+               goto free;
+       }
+
+       uap->clk = clk_get(&dev->dev, NULL);
+       if (IS_ERR(uap->clk)) {
+               ret = PTR_ERR(uap->clk);
+               goto unmap;
+       }
+
+       uap->port.dev = &dev->dev;
+       uap->port.mapbase = dev->res.start;
+       uap->port.membase = base;
+       uap->port.iotype = UPIO_MEM;
+       uap->port.irq = dev->irq[0];
+       uap->port.fifosize = 16;
+       uap->port.ops = &amba_pl010_pops;
+       uap->port.flags = UPF_BOOT_AUTOCONF;
+       uap->port.line = i;
+       uap->dev = dev;
+       uap->data = dev->dev.platform_data;
+
+       amba_ports[i] = uap;
+
+       amba_set_drvdata(dev, uap);
+       ret = uart_add_one_port(&amba_reg, &uap->port);
+       if (ret) {
+               amba_set_drvdata(dev, NULL);
+               amba_ports[i] = NULL;
+               clk_put(uap->clk);
+ unmap:
+               iounmap(base);
+ free:
+               kfree(uap);
+       }
+ out:
+       return ret;
+}
+
+static int pl010_remove(struct amba_device *dev)
+{
+       struct uart_amba_port *uap = amba_get_drvdata(dev);
+       int i;
+
+       amba_set_drvdata(dev, NULL);
+
+       uart_remove_one_port(&amba_reg, &uap->port);
+
+       for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
+               if (amba_ports[i] == uap)
+                       amba_ports[i] = NULL;
+
+       iounmap(uap->port.membase);
+       clk_put(uap->clk);
+       kfree(uap);
+       return 0;
+}
+
+static int pl010_suspend(struct amba_device *dev, pm_message_t state)
+{
+       struct uart_amba_port *uap = amba_get_drvdata(dev);
+
+       if (uap)
+               uart_suspend_port(&amba_reg, &uap->port);
+
+       return 0;
+}
+
+static int pl010_resume(struct amba_device *dev)
+{
+       struct uart_amba_port *uap = amba_get_drvdata(dev);
+
+       if (uap)
+               uart_resume_port(&amba_reg, &uap->port);
+
+       return 0;
+}
+
+static struct amba_id pl010_ids[] = {
+       {
+               .id     = 0x00041010,
+               .mask   = 0x000fffff,
+       },
+       { 0, 0 },
+};
+
+static struct amba_driver pl010_driver = {
+       .drv = {
+               .name   = "uart-pl010",
+       },
+       .id_table       = pl010_ids,
+       .probe          = pl010_probe,
+       .remove         = pl010_remove,
+       .suspend        = pl010_suspend,
+       .resume         = pl010_resume,
+};
+
+static int __init pl010_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "Serial: AMBA driver\n");
+
+       ret = uart_register_driver(&amba_reg);
+       if (ret == 0) {
+               ret = amba_driver_register(&pl010_driver);
+               if (ret)
+                       uart_unregister_driver(&amba_reg);
+       }
+       return ret;
+}
+
+static void __exit pl010_exit(void)
+{
+       amba_driver_unregister(&pl010_driver);
+       uart_unregister_driver(&amba_reg);
+}
+
+module_init(pl010_init);
+module_exit(pl010_exit);
+
+MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd");
+MODULE_DESCRIPTION("ARM AMBA serial port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
new file mode 100644 (file)
index 0000000..e76d7d0
--- /dev/null
@@ -0,0 +1,1519 @@
+/*
+ *  linux/drivers/char/amba.c
+ *
+ *  Driver for AMBA serial ports
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ *  Copyright 1999 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *  Copyright (C) 2010 ST-Ericsson SA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * This is a generic driver for ARM AMBA-type serial ports.  They
+ * have a lot of 16550-like features, but are not register compatible.
+ * Note that although they do have CTS, DCD and DSR inputs, they do
+ * not have an RI input, nor do they have DTR or RTS outputs.  If
+ * required, these have to be supplied via some other means (eg, GPIO)
+ * and hooked into this driver.
+ */
+
+#if defined(CONFIG_SERIAL_AMBA_PL011_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/serial.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+
+#include <asm/io.h>
+#include <asm/sizes.h>
+
+#define UART_NR                        14
+
+#define SERIAL_AMBA_MAJOR      204
+#define SERIAL_AMBA_MINOR      64
+#define SERIAL_AMBA_NR         UART_NR
+
+#define AMBA_ISR_PASS_LIMIT    256
+
+#define UART_DR_ERROR          (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)
+#define UART_DUMMY_DR_RX       (1 << 16)
+
+/* There is by now at least one vendor with differing details, so handle it */
+struct vendor_data {
+       unsigned int            ifls;
+       unsigned int            fifosize;
+       unsigned int            lcrh_tx;
+       unsigned int            lcrh_rx;
+       bool                    oversampling;
+       bool                    dma_threshold;
+};
+
+static struct vendor_data vendor_arm = {
+       .ifls                   = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
+       .fifosize               = 16,
+       .lcrh_tx                = UART011_LCRH,
+       .lcrh_rx                = UART011_LCRH,
+       .oversampling           = false,
+       .dma_threshold          = false,
+};
+
+static struct vendor_data vendor_st = {
+       .ifls                   = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF,
+       .fifosize               = 64,
+       .lcrh_tx                = ST_UART011_LCRH_TX,
+       .lcrh_rx                = ST_UART011_LCRH_RX,
+       .oversampling           = true,
+       .dma_threshold          = true,
+};
+
+/* Deals with DMA transactions */
+struct pl011_dmatx_data {
+       struct dma_chan         *chan;
+       struct scatterlist      sg;
+       char                    *buf;
+       bool                    queued;
+};
+
+/*
+ * We wrap our port structure around the generic uart_port.
+ */
+struct uart_amba_port {
+       struct uart_port        port;
+       struct clk              *clk;
+       const struct vendor_data *vendor;
+       unsigned int            dmacr;          /* dma control reg */
+       unsigned int            im;             /* interrupt mask */
+       unsigned int            old_status;
+       unsigned int            fifosize;       /* vendor-specific */
+       unsigned int            lcrh_tx;        /* vendor-specific */
+       unsigned int            lcrh_rx;        /* vendor-specific */
+       bool                    autorts;
+       char                    type[12];
+#ifdef CONFIG_DMA_ENGINE
+       /* DMA stuff */
+       bool                    using_dma;
+       struct pl011_dmatx_data dmatx;
+#endif
+};
+
+/*
+ * All the DMA operation mode stuff goes inside this ifdef.
+ * This assumes that you have a generic DMA device interface,
+ * no custom DMA interfaces are supported.
+ */
+#ifdef CONFIG_DMA_ENGINE
+
+#define PL011_DMA_BUFFER_SIZE PAGE_SIZE
+
+static void pl011_dma_probe_initcall(struct uart_amba_port *uap)
+{
+       /* DMA is the sole user of the platform data right now */
+       struct amba_pl011_data *plat = uap->port.dev->platform_data;
+       struct dma_slave_config tx_conf = {
+               .dst_addr = uap->port.mapbase + UART01x_DR,
+               .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
+               .direction = DMA_TO_DEVICE,
+               .dst_maxburst = uap->fifosize >> 1,
+       };
+       struct dma_chan *chan;
+       dma_cap_mask_t mask;
+
+       /* We need platform data */
+       if (!plat || !plat->dma_filter) {
+               dev_info(uap->port.dev, "no DMA platform data\n");
+               return;
+       }
+
+       /* Try to acquire a generic DMA engine slave channel */
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+
+       chan = dma_request_channel(mask, plat->dma_filter, plat->dma_tx_param);
+       if (!chan) {
+               dev_err(uap->port.dev, "no TX DMA channel!\n");
+               return;
+       }
+
+       dmaengine_slave_config(chan, &tx_conf);
+       uap->dmatx.chan = chan;
+
+       dev_info(uap->port.dev, "DMA channel TX %s\n",
+                dma_chan_name(uap->dmatx.chan));
+}
+
+#ifndef MODULE
+/*
+ * Stack up the UARTs and let the above initcall be done at device
+ * initcall time, because the serial driver is called as an arch
+ * initcall, and at this time the DMA subsystem is not yet registered.
+ * At this point the driver will switch over to using DMA where desired.
+ */
+struct dma_uap {
+       struct list_head node;
+       struct uart_amba_port *uap;
+};
+
+static LIST_HEAD(pl011_dma_uarts);
+
+static int __init pl011_dma_initcall(void)
+{
+       struct list_head *node, *tmp;
+
+       list_for_each_safe(node, tmp, &pl011_dma_uarts) {
+               struct dma_uap *dmau = list_entry(node, struct dma_uap, node);
+               pl011_dma_probe_initcall(dmau->uap);
+               list_del(node);
+               kfree(dmau);
+       }
+       return 0;
+}
+
+device_initcall(pl011_dma_initcall);
+
+static void pl011_dma_probe(struct uart_amba_port *uap)
+{
+       struct dma_uap *dmau = kzalloc(sizeof(struct dma_uap), GFP_KERNEL);
+       if (dmau) {
+               dmau->uap = uap;
+               list_add_tail(&dmau->node, &pl011_dma_uarts);
+       }
+}
+#else
+static void pl011_dma_probe(struct uart_amba_port *uap)
+{
+       pl011_dma_probe_initcall(uap);
+}
+#endif
+
+static void pl011_dma_remove(struct uart_amba_port *uap)
+{
+       /* TODO: remove the initcall if it has not yet executed */
+       if (uap->dmatx.chan)
+               dma_release_channel(uap->dmatx.chan);
+}
+
+
+/* Forward declare this for the refill routine */
+static int pl011_dma_tx_refill(struct uart_amba_port *uap);
+
+/*
+ * The current DMA TX buffer has been sent.
+ * Try to queue up another DMA buffer.
+ */
+static void pl011_dma_tx_callback(void *data)
+{
+       struct uart_amba_port *uap = data;
+       struct pl011_dmatx_data *dmatx = &uap->dmatx;
+       unsigned long flags;
+       u16 dmacr;
+
+       spin_lock_irqsave(&uap->port.lock, flags);
+       if (uap->dmatx.queued)
+               dma_unmap_sg(dmatx->chan->device->dev, &dmatx->sg, 1,
+                            DMA_TO_DEVICE);
+
+       dmacr = uap->dmacr;
+       uap->dmacr = dmacr & ~UART011_TXDMAE;
+       writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+
+       /*
+        * If TX DMA was disabled, it means that we've stopped the DMA for
+        * some reason (eg, XOFF received, or we want to send an X-char.)
+        *
+        * Note: we need to be careful here of a potential race between DMA
+        * and the rest of the driver - if the driver disables TX DMA while
+        * a TX buffer completing, we must update the tx queued status to
+        * get further refills (hence we check dmacr).
+        */
+       if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) ||
+           uart_circ_empty(&uap->port.state->xmit)) {
+               uap->dmatx.queued = false;
+               spin_unlock_irqrestore(&uap->port.lock, flags);
+               return;
+       }
+
+       if (pl011_dma_tx_refill(uap) <= 0) {
+               /*
+                * We didn't queue a DMA buffer for some reason, but we
+                * have data pending to be sent.  Re-enable the TX IRQ.
+                */
+               uap->im |= UART011_TXIM;
+               writew(uap->im, uap->port.membase + UART011_IMSC);
+       }
+       spin_unlock_irqrestore(&uap->port.lock, flags);
+}
+
+/*
+ * Try to refill the TX DMA buffer.
+ * Locking: called with port lock held and IRQs disabled.
+ * Returns:
+ *   1 if we queued up a TX DMA buffer.
+ *   0 if we didn't want to handle this by DMA
+ *  <0 on error
+ */
+static int pl011_dma_tx_refill(struct uart_amba_port *uap)
+{
+       struct pl011_dmatx_data *dmatx = &uap->dmatx;
+       struct dma_chan *chan = dmatx->chan;
+       struct dma_device *dma_dev = chan->device;
+       struct dma_async_tx_descriptor *desc;
+       struct circ_buf *xmit = &uap->port.state->xmit;
+       unsigned int count;
+
+       /*
+        * Try to avoid the overhead involved in using DMA if the
+        * transaction fits in the first half of the FIFO, by using
+        * the standard interrupt handling.  This ensures that we
+        * issue a uart_write_wakeup() at the appropriate time.
+        */
+       count = uart_circ_chars_pending(xmit);
+       if (count < (uap->fifosize >> 1)) {
+               uap->dmatx.queued = false;
+               return 0;
+       }
+
+       /*
+        * Bodge: don't send the last character by DMA, as this
+        * will prevent XON from notifying us to restart DMA.
+        */
+       count -= 1;
+
+       /* Else proceed to copy the TX chars to the DMA buffer and fire DMA */
+       if (count > PL011_DMA_BUFFER_SIZE)
+               count = PL011_DMA_BUFFER_SIZE;
+
+       if (xmit->tail < xmit->head)
+               memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], count);
+       else {
+               size_t first = UART_XMIT_SIZE - xmit->tail;
+               size_t second = xmit->head;
+
+               memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], first);
+               if (second)
+                       memcpy(&dmatx->buf[first], &xmit->buf[0], second);
+       }
+
+       dmatx->sg.length = count;
+
+       if (dma_map_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE) != 1) {
+               uap->dmatx.queued = false;
+               dev_dbg(uap->port.dev, "unable to map TX DMA\n");
+               return -EBUSY;
+       }
+
+       desc = dma_dev->device_prep_slave_sg(chan, &dmatx->sg, 1, DMA_TO_DEVICE,
+                                            DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!desc) {
+               dma_unmap_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE);
+               uap->dmatx.queued = false;
+               /*
+                * If DMA cannot be used right now, we complete this
+                * transaction via IRQ and let the TTY layer retry.
+                */
+               dev_dbg(uap->port.dev, "TX DMA busy\n");
+               return -EBUSY;
+       }
+
+       /* Some data to go along to the callback */
+       desc->callback = pl011_dma_tx_callback;
+       desc->callback_param = uap;
+
+       /* All errors should happen at prepare time */
+       dmaengine_submit(desc);
+
+       /* Fire the DMA transaction */
+       dma_dev->device_issue_pending(chan);
+
+       uap->dmacr |= UART011_TXDMAE;
+       writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+       uap->dmatx.queued = true;
+
+       /*
+        * Now we know that DMA will fire, so advance the ring buffer
+        * with the stuff we just dispatched.
+        */
+       xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
+       uap->port.icount.tx += count;
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&uap->port);
+
+       return 1;
+}
+
+/*
+ * We received a transmit interrupt without a pending X-char but with
+ * pending characters.
+ * Locking: called with port lock held and IRQs disabled.
+ * Returns:
+ *   false if we want to use PIO to transmit
+ *   true if we queued a DMA buffer
+ */
+static bool pl011_dma_tx_irq(struct uart_amba_port *uap)
+{
+       if (!uap->using_dma)
+               return false;
+
+       /*
+        * If we already have a TX buffer queued, but received a
+        * TX interrupt, it will be because we've just sent an X-char.
+        * Ensure the TX DMA is enabled and the TX IRQ is disabled.
+        */
+       if (uap->dmatx.queued) {
+               uap->dmacr |= UART011_TXDMAE;
+               writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+               uap->im &= ~UART011_TXIM;
+               writew(uap->im, uap->port.membase + UART011_IMSC);
+               return true;
+       }
+
+       /*
+        * We don't have a TX buffer queued, so try to queue one.
+        * If we succesfully queued a buffer, mask the TX IRQ.
+        */
+       if (pl011_dma_tx_refill(uap) > 0) {
+               uap->im &= ~UART011_TXIM;
+               writew(uap->im, uap->port.membase + UART011_IMSC);
+               return true;
+       }
+       return false;
+}
+
+/*
+ * Stop the DMA transmit (eg, due to received XOFF).
+ * Locking: called with port lock held and IRQs disabled.
+ */
+static inline void pl011_dma_tx_stop(struct uart_amba_port *uap)
+{
+       if (uap->dmatx.queued) {
+               uap->dmacr &= ~UART011_TXDMAE;
+               writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+       }
+}
+
+/*
+ * Try to start a DMA transmit, or in the case of an XON/OFF
+ * character queued for send, try to get that character out ASAP.
+ * Locking: called with port lock held and IRQs disabled.
+ * Returns:
+ *   false if we want the TX IRQ to be enabled
+ *   true if we have a buffer queued
+ */
+static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
+{
+       u16 dmacr;
+
+       if (!uap->using_dma)
+               return false;
+
+       if (!uap->port.x_char) {
+               /* no X-char, try to push chars out in DMA mode */
+               bool ret = true;
+
+               if (!uap->dmatx.queued) {
+                       if (pl011_dma_tx_refill(uap) > 0) {
+                               uap->im &= ~UART011_TXIM;
+                               ret = true;
+                       } else {
+                               uap->im |= UART011_TXIM;
+                               ret = false;
+                       }
+                       writew(uap->im, uap->port.membase + UART011_IMSC);
+               } else if (!(uap->dmacr & UART011_TXDMAE)) {
+                       uap->dmacr |= UART011_TXDMAE;
+                       writew(uap->dmacr,
+                                      uap->port.membase + UART011_DMACR);
+               }
+               return ret;
+       }
+
+       /*
+        * We have an X-char to send.  Disable DMA to prevent it loading
+        * the TX fifo, and then see if we can stuff it into the FIFO.
+        */
+       dmacr = uap->dmacr;
+       uap->dmacr &= ~UART011_TXDMAE;
+       writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+
+       if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) {
+               /*
+                * No space in the FIFO, so enable the transmit interrupt
+                * so we know when there is space.  Note that once we've
+                * loaded the character, we should just re-enable DMA.
+                */
+               return false;
+       }
+
+       writew(uap->port.x_char, uap->port.membase + UART01x_DR);
+       uap->port.icount.tx++;
+       uap->port.x_char = 0;
+
+       /* Success - restore the DMA state */
+       uap->dmacr = dmacr;
+       writew(dmacr, uap->port.membase + UART011_DMACR);
+
+       return true;
+}
+
+/*
+ * Flush the transmit buffer.
+ * Locking: called with port lock held and IRQs disabled.
+ */
+static void pl011_dma_flush_buffer(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+
+       if (!uap->using_dma)
+               return;
+
+       /* Avoid deadlock with the DMA engine callback */
+       spin_unlock(&uap->port.lock);
+       dmaengine_terminate_all(uap->dmatx.chan);
+       spin_lock(&uap->port.lock);
+       if (uap->dmatx.queued) {
+               dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1,
+                            DMA_TO_DEVICE);
+               uap->dmatx.queued = false;
+               uap->dmacr &= ~UART011_TXDMAE;
+               writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+       }
+}
+
+
+static void pl011_dma_startup(struct uart_amba_port *uap)
+{
+       if (!uap->dmatx.chan)
+               return;
+
+       uap->dmatx.buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL);
+       if (!uap->dmatx.buf) {
+               dev_err(uap->port.dev, "no memory for DMA TX buffer\n");
+               uap->port.fifosize = uap->fifosize;
+               return;
+       }
+
+       sg_init_one(&uap->dmatx.sg, uap->dmatx.buf, PL011_DMA_BUFFER_SIZE);
+
+       /* The DMA buffer is now the FIFO the TTY subsystem can use */
+       uap->port.fifosize = PL011_DMA_BUFFER_SIZE;
+       uap->using_dma = true;
+
+       /* Turn on DMA error (RX/TX will be enabled on demand) */
+       uap->dmacr |= UART011_DMAONERR;
+       writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+
+       /*
+        * ST Micro variants has some specific dma burst threshold
+        * compensation. Set this to 16 bytes, so burst will only
+        * be issued above/below 16 bytes.
+        */
+       if (uap->vendor->dma_threshold)
+               writew(ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16,
+                              uap->port.membase + ST_UART011_DMAWM);
+}
+
+static void pl011_dma_shutdown(struct uart_amba_port *uap)
+{
+       if (!uap->using_dma)
+               return;
+
+       /* Disable RX and TX DMA */
+       while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
+               barrier();
+
+       spin_lock_irq(&uap->port.lock);
+       uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE);
+       writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+       spin_unlock_irq(&uap->port.lock);
+
+       /* In theory, this should already be done by pl011_dma_flush_buffer */
+       dmaengine_terminate_all(uap->dmatx.chan);
+       if (uap->dmatx.queued) {
+               dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1,
+                            DMA_TO_DEVICE);
+               uap->dmatx.queued = false;
+       }
+
+       kfree(uap->dmatx.buf);
+
+       uap->using_dma = false;
+}
+
+#else
+/* Blank functions if the DMA engine is not available */
+static inline void pl011_dma_probe(struct uart_amba_port *uap)
+{
+}
+
+static inline void pl011_dma_remove(struct uart_amba_port *uap)
+{
+}
+
+static inline void pl011_dma_startup(struct uart_amba_port *uap)
+{
+}
+
+static inline void pl011_dma_shutdown(struct uart_amba_port *uap)
+{
+}
+
+static inline bool pl011_dma_tx_irq(struct uart_amba_port *uap)
+{
+       return false;
+}
+
+static inline void pl011_dma_tx_stop(struct uart_amba_port *uap)
+{
+}
+
+static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
+{
+       return false;
+}
+
+#define pl011_dma_flush_buffer NULL
+#endif
+
+
+static void pl011_stop_tx(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+
+       uap->im &= ~UART011_TXIM;
+       writew(uap->im, uap->port.membase + UART011_IMSC);
+       pl011_dma_tx_stop(uap);
+}
+
+static void pl011_start_tx(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+
+       if (!pl011_dma_tx_start(uap)) {
+               uap->im |= UART011_TXIM;
+               writew(uap->im, uap->port.membase + UART011_IMSC);
+       }
+}
+
+static void pl011_stop_rx(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+
+       uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM|
+                    UART011_PEIM|UART011_BEIM|UART011_OEIM);
+       writew(uap->im, uap->port.membase + UART011_IMSC);
+}
+
+static void pl011_enable_ms(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+
+       uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM;
+       writew(uap->im, uap->port.membase + UART011_IMSC);
+}
+
+static void pl011_rx_chars(struct uart_amba_port *uap)
+{
+       struct tty_struct *tty = uap->port.state->port.tty;
+       unsigned int status, ch, flag, max_count = 256;
+
+       status = readw(uap->port.membase + UART01x_FR);
+       while ((status & UART01x_FR_RXFE) == 0 && max_count--) {
+               ch = readw(uap->port.membase + UART01x_DR) | UART_DUMMY_DR_RX;
+               flag = TTY_NORMAL;
+               uap->port.icount.rx++;
+
+               /*
+                * Note that the error handling code is
+                * out of the main execution path
+                */
+               if (unlikely(ch & UART_DR_ERROR)) {
+                       if (ch & UART011_DR_BE) {
+                               ch &= ~(UART011_DR_FE | UART011_DR_PE);
+                               uap->port.icount.brk++;
+                               if (uart_handle_break(&uap->port))
+                                       goto ignore_char;
+                       } else if (ch & UART011_DR_PE)
+                               uap->port.icount.parity++;
+                       else if (ch & UART011_DR_FE)
+                               uap->port.icount.frame++;
+                       if (ch & UART011_DR_OE)
+                               uap->port.icount.overrun++;
+
+                       ch &= uap->port.read_status_mask;
+
+                       if (ch & UART011_DR_BE)
+                               flag = TTY_BREAK;
+                       else if (ch & UART011_DR_PE)
+                               flag = TTY_PARITY;
+                       else if (ch & UART011_DR_FE)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(&uap->port, ch & 255))
+                       goto ignore_char;
+
+               uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag);
+
+       ignore_char:
+               status = readw(uap->port.membase + UART01x_FR);
+       }
+       spin_unlock(&uap->port.lock);
+       tty_flip_buffer_push(tty);
+       spin_lock(&uap->port.lock);
+}
+
+static void pl011_tx_chars(struct uart_amba_port *uap)
+{
+       struct circ_buf *xmit = &uap->port.state->xmit;
+       int count;
+
+       if (uap->port.x_char) {
+               writew(uap->port.x_char, uap->port.membase + UART01x_DR);
+               uap->port.icount.tx++;
+               uap->port.x_char = 0;
+               return;
+       }
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) {
+               pl011_stop_tx(&uap->port);
+               return;
+       }
+
+       /* If we are using DMA mode, try to send some characters. */
+       if (pl011_dma_tx_irq(uap))
+               return;
+
+       count = uap->fifosize >> 1;
+       do {
+               writew(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               uap->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (--count > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&uap->port);
+
+       if (uart_circ_empty(xmit))
+               pl011_stop_tx(&uap->port);
+}
+
+static void pl011_modem_status(struct uart_amba_port *uap)
+{
+       unsigned int status, delta;
+
+       status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
+
+       delta = status ^ uap->old_status;
+       uap->old_status = status;
+
+       if (!delta)
+               return;
+
+       if (delta & UART01x_FR_DCD)
+               uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD);
+
+       if (delta & UART01x_FR_DSR)
+               uap->port.icount.dsr++;
+
+       if (delta & UART01x_FR_CTS)
+               uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS);
+
+       wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
+}
+
+static irqreturn_t pl011_int(int irq, void *dev_id)
+{
+       struct uart_amba_port *uap = dev_id;
+       unsigned long flags;
+       unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
+       int handled = 0;
+
+       spin_lock_irqsave(&uap->port.lock, flags);
+
+       status = readw(uap->port.membase + UART011_MIS);
+       if (status) {
+               do {
+                       writew(status & ~(UART011_TXIS|UART011_RTIS|
+                                         UART011_RXIS),
+                              uap->port.membase + UART011_ICR);
+
+                       if (status & (UART011_RTIS|UART011_RXIS))
+                               pl011_rx_chars(uap);
+                       if (status & (UART011_DSRMIS|UART011_DCDMIS|
+                                     UART011_CTSMIS|UART011_RIMIS))
+                               pl011_modem_status(uap);
+                       if (status & UART011_TXIS)
+                               pl011_tx_chars(uap);
+
+                       if (pass_counter-- == 0)
+                               break;
+
+                       status = readw(uap->port.membase + UART011_MIS);
+               } while (status != 0);
+               handled = 1;
+       }
+
+       spin_unlock_irqrestore(&uap->port.lock, flags);
+
+       return IRQ_RETVAL(handled);
+}
+
+static unsigned int pl01x_tx_empty(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int status = readw(uap->port.membase + UART01x_FR);
+       return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT;
+}
+
+static unsigned int pl01x_get_mctrl(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int result = 0;
+       unsigned int status = readw(uap->port.membase + UART01x_FR);
+
+#define TIOCMBIT(uartbit, tiocmbit)    \
+       if (status & uartbit)           \
+               result |= tiocmbit
+
+       TIOCMBIT(UART01x_FR_DCD, TIOCM_CAR);
+       TIOCMBIT(UART01x_FR_DSR, TIOCM_DSR);
+       TIOCMBIT(UART01x_FR_CTS, TIOCM_CTS);
+       TIOCMBIT(UART011_FR_RI, TIOCM_RNG);
+#undef TIOCMBIT
+       return result;
+}
+
+static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int cr;
+
+       cr = readw(uap->port.membase + UART011_CR);
+
+#define        TIOCMBIT(tiocmbit, uartbit)             \
+       if (mctrl & tiocmbit)           \
+               cr |= uartbit;          \
+       else                            \
+               cr &= ~uartbit
+
+       TIOCMBIT(TIOCM_RTS, UART011_CR_RTS);
+       TIOCMBIT(TIOCM_DTR, UART011_CR_DTR);
+       TIOCMBIT(TIOCM_OUT1, UART011_CR_OUT1);
+       TIOCMBIT(TIOCM_OUT2, UART011_CR_OUT2);
+       TIOCMBIT(TIOCM_LOOP, UART011_CR_LBE);
+
+       if (uap->autorts) {
+               /* We need to disable auto-RTS if we want to turn RTS off */
+               TIOCMBIT(TIOCM_RTS, UART011_CR_RTSEN);
+       }
+#undef TIOCMBIT
+
+       writew(cr, uap->port.membase + UART011_CR);
+}
+
+static void pl011_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned long flags;
+       unsigned int lcr_h;
+
+       spin_lock_irqsave(&uap->port.lock, flags);
+       lcr_h = readw(uap->port.membase + uap->lcrh_tx);
+       if (break_state == -1)
+               lcr_h |= UART01x_LCRH_BRK;
+       else
+               lcr_h &= ~UART01x_LCRH_BRK;
+       writew(lcr_h, uap->port.membase + uap->lcrh_tx);
+       spin_unlock_irqrestore(&uap->port.lock, flags);
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+static int pl010_get_poll_char(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int status;
+
+       status = readw(uap->port.membase + UART01x_FR);
+       if (status & UART01x_FR_RXFE)
+               return NO_POLL_CHAR;
+
+       return readw(uap->port.membase + UART01x_DR);
+}
+
+static void pl010_put_poll_char(struct uart_port *port,
+                        unsigned char ch)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+
+       while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
+               barrier();
+
+       writew(ch, uap->port.membase + UART01x_DR);
+}
+
+#endif /* CONFIG_CONSOLE_POLL */
+
+static int pl011_startup(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int cr;
+       int retval;
+
+       /*
+        * Try to enable the clock producer.
+        */
+       retval = clk_enable(uap->clk);
+       if (retval)
+               goto out;
+
+       uap->port.uartclk = clk_get_rate(uap->clk);
+
+       /*
+        * Allocate the IRQ
+        */
+       retval = request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
+       if (retval)
+               goto clk_dis;
+
+       writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS);
+
+       /*
+        * Provoke TX FIFO interrupt into asserting.
+        */
+       cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE;
+       writew(cr, uap->port.membase + UART011_CR);
+       writew(0, uap->port.membase + UART011_FBRD);
+       writew(1, uap->port.membase + UART011_IBRD);
+       writew(0, uap->port.membase + uap->lcrh_rx);
+       if (uap->lcrh_tx != uap->lcrh_rx) {
+               int i;
+               /*
+                * Wait 10 PCLKs before writing LCRH_TX register,
+                * to get this delay write read only register 10 times
+                */
+               for (i = 0; i < 10; ++i)
+                       writew(0xff, uap->port.membase + UART011_MIS);
+               writew(0, uap->port.membase + uap->lcrh_tx);
+       }
+       writew(0, uap->port.membase + UART01x_DR);
+       while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
+               barrier();
+
+       cr = UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE;
+       writew(cr, uap->port.membase + UART011_CR);
+
+       /* Clear pending error interrupts */
+       writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS,
+              uap->port.membase + UART011_ICR);
+
+       /*
+        * initialise the old status of the modem signals
+        */
+       uap->old_status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
+
+       /* Startup DMA */
+       pl011_dma_startup(uap);
+
+       /*
+        * Finally, enable interrupts
+        */
+       spin_lock_irq(&uap->port.lock);
+       uap->im = UART011_RXIM | UART011_RTIM;
+       writew(uap->im, uap->port.membase + UART011_IMSC);
+       spin_unlock_irq(&uap->port.lock);
+
+       return 0;
+
+ clk_dis:
+       clk_disable(uap->clk);
+ out:
+       return retval;
+}
+
+static void pl011_shutdown_channel(struct uart_amba_port *uap,
+                                       unsigned int lcrh)
+{
+      unsigned long val;
+
+      val = readw(uap->port.membase + lcrh);
+      val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN);
+      writew(val, uap->port.membase + lcrh);
+}
+
+static void pl011_shutdown(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+
+       /*
+        * disable all interrupts
+        */
+       spin_lock_irq(&uap->port.lock);
+       uap->im = 0;
+       writew(uap->im, uap->port.membase + UART011_IMSC);
+       writew(0xffff, uap->port.membase + UART011_ICR);
+       spin_unlock_irq(&uap->port.lock);
+
+       pl011_dma_shutdown(uap);
+
+       /*
+        * Free the interrupt
+        */
+       free_irq(uap->port.irq, uap);
+
+       /*
+        * disable the port
+        */
+       uap->autorts = false;
+       writew(UART01x_CR_UARTEN | UART011_CR_TXE, uap->port.membase + UART011_CR);
+
+       /*
+        * disable break condition and fifos
+        */
+       pl011_shutdown_channel(uap, uap->lcrh_rx);
+       if (uap->lcrh_rx != uap->lcrh_tx)
+               pl011_shutdown_channel(uap, uap->lcrh_tx);
+
+       /*
+        * Shut down the clock producer
+        */
+       clk_disable(uap->clk);
+}
+
+static void
+pl011_set_termios(struct uart_port *port, struct ktermios *termios,
+                    struct ktermios *old)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int lcr_h, old_cr;
+       unsigned long flags;
+       unsigned int baud, quot, clkdiv;
+
+       if (uap->vendor->oversampling)
+               clkdiv = 8;
+       else
+               clkdiv = 16;
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old, 0,
+                                 port->uartclk / clkdiv);
+
+       if (baud > port->uartclk/16)
+               quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud);
+       else
+               quot = DIV_ROUND_CLOSEST(port->uartclk * 4, baud);
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               lcr_h = UART01x_LCRH_WLEN_5;
+               break;
+       case CS6:
+               lcr_h = UART01x_LCRH_WLEN_6;
+               break;
+       case CS7:
+               lcr_h = UART01x_LCRH_WLEN_7;
+               break;
+       default: // CS8
+               lcr_h = UART01x_LCRH_WLEN_8;
+               break;
+       }
+       if (termios->c_cflag & CSTOPB)
+               lcr_h |= UART01x_LCRH_STP2;
+       if (termios->c_cflag & PARENB) {
+               lcr_h |= UART01x_LCRH_PEN;
+               if (!(termios->c_cflag & PARODD))
+                       lcr_h |= UART01x_LCRH_EPS;
+       }
+       if (uap->fifosize > 1)
+               lcr_h |= UART01x_LCRH_FEN;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       port->read_status_mask = UART011_DR_OE | 255;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= UART011_DR_FE | UART011_DR_PE;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               port->read_status_mask |= UART011_DR_BE;
+
+       /*
+        * Characters to ignore
+        */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= UART011_DR_FE | UART011_DR_PE;
+       if (termios->c_iflag & IGNBRK) {
+               port->ignore_status_mask |= UART011_DR_BE;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       port->ignore_status_mask |= UART011_DR_OE;
+       }
+
+       /*
+        * Ignore all characters if CREAD is not set.
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               port->ignore_status_mask |= UART_DUMMY_DR_RX;
+
+       if (UART_ENABLE_MS(port, termios->c_cflag))
+               pl011_enable_ms(port);
+
+       /* first, disable everything */
+       old_cr = readw(port->membase + UART011_CR);
+       writew(0, port->membase + UART011_CR);
+
+       if (termios->c_cflag & CRTSCTS) {
+               if (old_cr & UART011_CR_RTS)
+                       old_cr |= UART011_CR_RTSEN;
+
+               old_cr |= UART011_CR_CTSEN;
+               uap->autorts = true;
+       } else {
+               old_cr &= ~(UART011_CR_CTSEN | UART011_CR_RTSEN);
+               uap->autorts = false;
+       }
+
+       if (uap->vendor->oversampling) {
+               if (baud > port->uartclk / 16)
+                       old_cr |= ST_UART011_CR_OVSFACT;
+               else
+                       old_cr &= ~ST_UART011_CR_OVSFACT;
+       }
+
+       /* Set baud rate */
+       writew(quot & 0x3f, port->membase + UART011_FBRD);
+       writew(quot >> 6, port->membase + UART011_IBRD);
+
+       /*
+        * ----------v----------v----------v----------v-----
+        * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
+        * ----------^----------^----------^----------^-----
+        */
+       writew(lcr_h, port->membase + uap->lcrh_rx);
+       if (uap->lcrh_rx != uap->lcrh_tx) {
+               int i;
+               /*
+                * Wait 10 PCLKs before writing LCRH_TX register,
+                * to get this delay write read only register 10 times
+                */
+               for (i = 0; i < 10; ++i)
+                       writew(0xff, uap->port.membase + UART011_MIS);
+               writew(lcr_h, port->membase + uap->lcrh_tx);
+       }
+       writew(old_cr, port->membase + UART011_CR);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *pl011_type(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       return uap->port.type == PORT_AMBA ? uap->type : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'
+ */
+static void pl010_release_port(struct uart_port *port)
+{
+       release_mem_region(port->mapbase, SZ_4K);
+}
+
+/*
+ * Request the memory region(s) being used by 'port'
+ */
+static int pl010_request_port(struct uart_port *port)
+{
+       return request_mem_region(port->mapbase, SZ_4K, "uart-pl011")
+                       != NULL ? 0 : -EBUSY;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void pl010_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = PORT_AMBA;
+               pl010_request_port(port);
+       }
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       int ret = 0;
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
+               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 amba_pl011_pops = {
+       .tx_empty       = pl01x_tx_empty,
+       .set_mctrl      = pl011_set_mctrl,
+       .get_mctrl      = pl01x_get_mctrl,
+       .stop_tx        = pl011_stop_tx,
+       .start_tx       = pl011_start_tx,
+       .stop_rx        = pl011_stop_rx,
+       .enable_ms      = pl011_enable_ms,
+       .break_ctl      = pl011_break_ctl,
+       .startup        = pl011_startup,
+       .shutdown       = pl011_shutdown,
+       .flush_buffer   = pl011_dma_flush_buffer,
+       .set_termios    = pl011_set_termios,
+       .type           = pl011_type,
+       .release_port   = pl010_release_port,
+       .request_port   = pl010_request_port,
+       .config_port    = pl010_config_port,
+       .verify_port    = pl010_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char = pl010_get_poll_char,
+       .poll_put_char = pl010_put_poll_char,
+#endif
+};
+
+static struct uart_amba_port *amba_ports[UART_NR];
+
+#ifdef CONFIG_SERIAL_AMBA_PL011_CONSOLE
+
+static void pl011_console_putchar(struct uart_port *port, int ch)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+
+       while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
+               barrier();
+       writew(ch, uap->port.membase + UART01x_DR);
+}
+
+static void
+pl011_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct uart_amba_port *uap = amba_ports[co->index];
+       unsigned int status, old_cr, new_cr;
+
+       clk_enable(uap->clk);
+
+       /*
+        *      First save the CR then disable the interrupts
+        */
+       old_cr = readw(uap->port.membase + UART011_CR);
+       new_cr = old_cr & ~UART011_CR_CTSEN;
+       new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
+       writew(new_cr, uap->port.membase + UART011_CR);
+
+       uart_console_write(&uap->port, s, count, pl011_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the TCR
+        */
+       do {
+               status = readw(uap->port.membase + UART01x_FR);
+       } while (status & UART01x_FR_BUSY);
+       writew(old_cr, uap->port.membase + UART011_CR);
+
+       clk_disable(uap->clk);
+}
+
+static void __init
+pl011_console_get_options(struct uart_amba_port *uap, int *baud,
+                            int *parity, int *bits)
+{
+       if (readw(uap->port.membase + UART011_CR) & UART01x_CR_UARTEN) {
+               unsigned int lcr_h, ibrd, fbrd;
+
+               lcr_h = readw(uap->port.membase + uap->lcrh_tx);
+
+               *parity = 'n';
+               if (lcr_h & UART01x_LCRH_PEN) {
+                       if (lcr_h & UART01x_LCRH_EPS)
+                               *parity = 'e';
+                       else
+                               *parity = 'o';
+               }
+
+               if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7)
+                       *bits = 7;
+               else
+                       *bits = 8;
+
+               ibrd = readw(uap->port.membase + UART011_IBRD);
+               fbrd = readw(uap->port.membase + UART011_FBRD);
+
+               *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd);
+
+               if (uap->vendor->oversampling) {
+                       if (readw(uap->port.membase + UART011_CR)
+                                 & ST_UART011_CR_OVSFACT)
+                               *baud *= 2;
+               }
+       }
+}
+
+static int __init pl011_console_setup(struct console *co, char *options)
+{
+       struct uart_amba_port *uap;
+       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.
+        */
+       if (co->index >= UART_NR)
+               co->index = 0;
+       uap = amba_ports[co->index];
+       if (!uap)
+               return -ENODEV;
+
+       uap->port.uartclk = clk_get_rate(uap->clk);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               pl011_console_get_options(uap, &baud, &parity, &bits);
+
+       return uart_set_options(&uap->port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver amba_reg;
+static struct console amba_console = {
+       .name           = "ttyAMA",
+       .write          = pl011_console_write,
+       .device         = uart_console_device,
+       .setup          = pl011_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &amba_reg,
+};
+
+#define AMBA_CONSOLE   (&amba_console)
+#else
+#define AMBA_CONSOLE   NULL
+#endif
+
+static struct uart_driver amba_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "ttyAMA",
+       .dev_name               = "ttyAMA",
+       .major                  = SERIAL_AMBA_MAJOR,
+       .minor                  = SERIAL_AMBA_MINOR,
+       .nr                     = UART_NR,
+       .cons                   = AMBA_CONSOLE,
+};
+
+static int pl011_probe(struct amba_device *dev, struct amba_id *id)
+{
+       struct uart_amba_port *uap;
+       struct vendor_data *vendor = id->data;
+       void __iomem *base;
+       int i, ret;
+
+       for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
+               if (amba_ports[i] == NULL)
+                       break;
+
+       if (i == ARRAY_SIZE(amba_ports)) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
+       if (uap == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       base = ioremap(dev->res.start, resource_size(&dev->res));
+       if (!base) {
+               ret = -ENOMEM;
+               goto free;
+       }
+
+       uap->clk = clk_get(&dev->dev, NULL);
+       if (IS_ERR(uap->clk)) {
+               ret = PTR_ERR(uap->clk);
+               goto unmap;
+       }
+
+       uap->vendor = vendor;
+       uap->lcrh_rx = vendor->lcrh_rx;
+       uap->lcrh_tx = vendor->lcrh_tx;
+       uap->fifosize = vendor->fifosize;
+       uap->port.dev = &dev->dev;
+       uap->port.mapbase = dev->res.start;
+       uap->port.membase = base;
+       uap->port.iotype = UPIO_MEM;
+       uap->port.irq = dev->irq[0];
+       uap->port.fifosize = uap->fifosize;
+       uap->port.ops = &amba_pl011_pops;
+       uap->port.flags = UPF_BOOT_AUTOCONF;
+       uap->port.line = i;
+       pl011_dma_probe(uap);
+
+       snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev));
+
+       amba_ports[i] = uap;
+
+       amba_set_drvdata(dev, uap);
+       ret = uart_add_one_port(&amba_reg, &uap->port);
+       if (ret) {
+               amba_set_drvdata(dev, NULL);
+               amba_ports[i] = NULL;
+               pl011_dma_remove(uap);
+               clk_put(uap->clk);
+ unmap:
+               iounmap(base);
+ free:
+               kfree(uap);
+       }
+ out:
+       return ret;
+}
+
+static int pl011_remove(struct amba_device *dev)
+{
+       struct uart_amba_port *uap = amba_get_drvdata(dev);
+       int i;
+
+       amba_set_drvdata(dev, NULL);
+
+       uart_remove_one_port(&amba_reg, &uap->port);
+
+       for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
+               if (amba_ports[i] == uap)
+                       amba_ports[i] = NULL;
+
+       pl011_dma_remove(uap);
+       iounmap(uap->port.membase);
+       clk_put(uap->clk);
+       kfree(uap);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int pl011_suspend(struct amba_device *dev, pm_message_t state)
+{
+       struct uart_amba_port *uap = amba_get_drvdata(dev);
+
+       if (!uap)
+               return -EINVAL;
+
+       return uart_suspend_port(&amba_reg, &uap->port);
+}
+
+static int pl011_resume(struct amba_device *dev)
+{
+       struct uart_amba_port *uap = amba_get_drvdata(dev);
+
+       if (!uap)
+               return -EINVAL;
+
+       return uart_resume_port(&amba_reg, &uap->port);
+}
+#endif
+
+static struct amba_id pl011_ids[] = {
+       {
+               .id     = 0x00041011,
+               .mask   = 0x000fffff,
+               .data   = &vendor_arm,
+       },
+       {
+               .id     = 0x00380802,
+               .mask   = 0x00ffffff,
+               .data   = &vendor_st,
+       },
+       { 0, 0 },
+};
+
+static struct amba_driver pl011_driver = {
+       .drv = {
+               .name   = "uart-pl011",
+       },
+       .id_table       = pl011_ids,
+       .probe          = pl011_probe,
+       .remove         = pl011_remove,
+#ifdef CONFIG_PM
+       .suspend        = pl011_suspend,
+       .resume         = pl011_resume,
+#endif
+};
+
+static int __init pl011_init(void)
+{
+       int ret;
+       printk(KERN_INFO "Serial: AMBA PL011 UART driver\n");
+
+       ret = uart_register_driver(&amba_reg);
+       if (ret == 0) {
+               ret = amba_driver_register(&pl011_driver);
+               if (ret)
+                       uart_unregister_driver(&amba_reg);
+       }
+       return ret;
+}
+
+static void __exit pl011_exit(void)
+{
+       amba_driver_unregister(&pl011_driver);
+       uart_unregister_driver(&amba_reg);
+}
+
+/*
+ * While this can be a module, if builtin it's most likely the console
+ * So let's leave module_exit but move module_init to an earlier place
+ */
+arch_initcall(pl011_init);
+module_exit(pl011_exit);
+
+MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd");
+MODULE_DESCRIPTION("ARM AMBA serial port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c
new file mode 100644 (file)
index 0000000..095a5d5
--- /dev/null
@@ -0,0 +1,709 @@
+/*
+ *  Driver for GRLIB serial ports (APBUART)
+ *
+ *  Based on linux/drivers/serial/amba.c
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *  Copyright (C) 2003 Konrad Eisele <eiselekd@web.de>
+ *  Copyright (C) 2006 Daniel Hellstrom <daniel@gaisler.com>, Aeroflex Gaisler AB
+ *  Copyright (C) 2008 Gilead Kutnick <kutnickg@zin-tech.com>
+ *  Copyright (C) 2009 Kristoffer Glembo <kristoffer@gaisler.com>, Aeroflex Gaisler AB
+ */
+
+#if defined(CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/kthread.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/serial_core.h>
+#include <asm/irq.h>
+
+#include "apbuart.h"
+
+#define SERIAL_APBUART_MAJOR   TTY_MAJOR
+#define SERIAL_APBUART_MINOR   64
+#define UART_DUMMY_RSR_RX      0x8000  /* for ignore all read */
+
+static void apbuart_tx_chars(struct uart_port *port);
+
+static void apbuart_stop_tx(struct uart_port *port)
+{
+       unsigned int cr;
+
+       cr = UART_GET_CTRL(port);
+       cr &= ~UART_CTRL_TI;
+       UART_PUT_CTRL(port, cr);
+}
+
+static void apbuart_start_tx(struct uart_port *port)
+{
+       unsigned int cr;
+
+       cr = UART_GET_CTRL(port);
+       cr |= UART_CTRL_TI;
+       UART_PUT_CTRL(port, cr);
+
+       if (UART_GET_STATUS(port) & UART_STATUS_THE)
+               apbuart_tx_chars(port);
+}
+
+static void apbuart_stop_rx(struct uart_port *port)
+{
+       unsigned int cr;
+
+       cr = UART_GET_CTRL(port);
+       cr &= ~(UART_CTRL_RI);
+       UART_PUT_CTRL(port, cr);
+}
+
+static void apbuart_enable_ms(struct uart_port *port)
+{
+       /* No modem status change interrupts for APBUART */
+}
+
+static void apbuart_rx_chars(struct uart_port *port)
+{
+       struct tty_struct *tty = port->state->port.tty;
+       unsigned int status, ch, rsr, flag;
+       unsigned int max_chars = port->fifosize;
+
+       status = UART_GET_STATUS(port);
+
+       while (UART_RX_DATA(status) && (max_chars--)) {
+
+               ch = UART_GET_CHAR(port);
+               flag = TTY_NORMAL;
+
+               port->icount.rx++;
+
+               rsr = UART_GET_STATUS(port) | UART_DUMMY_RSR_RX;
+               UART_PUT_STATUS(port, 0);
+               if (rsr & UART_STATUS_ERR) {
+
+                       if (rsr & UART_STATUS_BR) {
+                               rsr &= ~(UART_STATUS_FE | UART_STATUS_PE);
+                               port->icount.brk++;
+                               if (uart_handle_break(port))
+                                       goto ignore_char;
+                       } else if (rsr & UART_STATUS_PE) {
+                               port->icount.parity++;
+                       } else if (rsr & UART_STATUS_FE) {
+                               port->icount.frame++;
+                       }
+                       if (rsr & UART_STATUS_OE)
+                               port->icount.overrun++;
+
+                       rsr &= port->read_status_mask;
+
+                       if (rsr & UART_STATUS_PE)
+                               flag = TTY_PARITY;
+                       else if (rsr & UART_STATUS_FE)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(port, ch))
+                       goto ignore_char;
+
+               uart_insert_char(port, rsr, UART_STATUS_OE, ch, flag);
+
+
+             ignore_char:
+               status = UART_GET_STATUS(port);
+       }
+
+       tty_flip_buffer_push(tty);
+}
+
+static void apbuart_tx_chars(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->state->xmit;
+       int count;
+
+       if (port->x_char) {
+               UART_PUT_CHAR(port, port->x_char);
+               port->icount.tx++;
+               port->x_char = 0;
+               return;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               apbuart_stop_tx(port);
+               return;
+       }
+
+       /* amba: fill FIFO */
+       count = port->fifosize >> 1;
+       do {
+               UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (--count > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit))
+               apbuart_stop_tx(port);
+}
+
+static irqreturn_t apbuart_int(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       unsigned int status;
+
+       spin_lock(&port->lock);
+
+       status = UART_GET_STATUS(port);
+       if (status & UART_STATUS_DR)
+               apbuart_rx_chars(port);
+       if (status & UART_STATUS_THE)
+               apbuart_tx_chars(port);
+
+       spin_unlock(&port->lock);
+
+       return IRQ_HANDLED;
+}
+
+static unsigned int apbuart_tx_empty(struct uart_port *port)
+{
+       unsigned int status = UART_GET_STATUS(port);
+       return status & UART_STATUS_THE ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int apbuart_get_mctrl(struct uart_port *port)
+{
+       /* The GRLIB APBUART handles flow control in hardware */
+       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+static void apbuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       /* The GRLIB APBUART handles flow control in hardware */
+}
+
+static void apbuart_break_ctl(struct uart_port *port, int break_state)
+{
+       /* We don't support sending break */
+}
+
+static int apbuart_startup(struct uart_port *port)
+{
+       int retval;
+       unsigned int cr;
+
+       /* Allocate the IRQ */
+       retval = request_irq(port->irq, apbuart_int, 0, "apbuart", port);
+       if (retval)
+               return retval;
+
+       /* Finally, enable interrupts */
+       cr = UART_GET_CTRL(port);
+       UART_PUT_CTRL(port,
+                     cr | UART_CTRL_RE | UART_CTRL_TE |
+                     UART_CTRL_RI | UART_CTRL_TI);
+
+       return 0;
+}
+
+static void apbuart_shutdown(struct uart_port *port)
+{
+       unsigned int cr;
+
+       /* disable all interrupts, disable the port */
+       cr = UART_GET_CTRL(port);
+       UART_PUT_CTRL(port,
+                     cr & ~(UART_CTRL_RE | UART_CTRL_TE |
+                            UART_CTRL_RI | UART_CTRL_TI));
+
+       /* Free the interrupt */
+       free_irq(port->irq, port);
+}
+
+static void apbuart_set_termios(struct uart_port *port,
+                               struct ktermios *termios, struct ktermios *old)
+{
+       unsigned int cr;
+       unsigned long flags;
+       unsigned int baud, quot;
+
+       /* Ask the core to calculate the divisor for us. */
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
+       if (baud == 0)
+               panic("invalid baudrate %i\n", port->uartclk / 16);
+
+       /* uart_get_divisor calc a *16 uart freq, apbuart is *8 */
+       quot = (uart_get_divisor(port, baud)) * 2;
+       cr = UART_GET_CTRL(port);
+       cr &= ~(UART_CTRL_PE | UART_CTRL_PS);
+
+       if (termios->c_cflag & PARENB) {
+               cr |= UART_CTRL_PE;
+               if ((termios->c_cflag & PARODD))
+                       cr |= UART_CTRL_PS;
+       }
+
+       /* Enable flow control. */
+       if (termios->c_cflag & CRTSCTS)
+               cr |= UART_CTRL_FL;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Update the per-port timeout. */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       port->read_status_mask = UART_STATUS_OE;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= UART_STATUS_FE | UART_STATUS_PE;
+
+       /* Characters to ignore */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= UART_STATUS_FE | UART_STATUS_PE;
+
+       /* Ignore all characters if CREAD is not set. */
+       if ((termios->c_cflag & CREAD) == 0)
+               port->ignore_status_mask |= UART_DUMMY_RSR_RX;
+
+       /* Set baud rate */
+       quot -= 1;
+       UART_PUT_SCAL(port, quot);
+       UART_PUT_CTRL(port, cr);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *apbuart_type(struct uart_port *port)
+{
+       return port->type == PORT_APBUART ? "GRLIB/APBUART" : NULL;
+}
+
+static void apbuart_release_port(struct uart_port *port)
+{
+       release_mem_region(port->mapbase, 0x100);
+}
+
+static int apbuart_request_port(struct uart_port *port)
+{
+       return request_mem_region(port->mapbase, 0x100, "grlib-apbuart")
+           != NULL ? 0 : -EBUSY;
+       return 0;
+}
+
+/* Configure/autoconfigure the port */
+static void apbuart_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = PORT_APBUART;
+               apbuart_request_port(port);
+       }
+}
+
+/* Verify the new serial_struct (for TIOCSSERIAL) */
+static int apbuart_verify_port(struct uart_port *port,
+                              struct serial_struct *ser)
+{
+       int ret = 0;
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_APBUART)
+               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 grlib_apbuart_ops = {
+       .tx_empty = apbuart_tx_empty,
+       .set_mctrl = apbuart_set_mctrl,
+       .get_mctrl = apbuart_get_mctrl,
+       .stop_tx = apbuart_stop_tx,
+       .start_tx = apbuart_start_tx,
+       .stop_rx = apbuart_stop_rx,
+       .enable_ms = apbuart_enable_ms,
+       .break_ctl = apbuart_break_ctl,
+       .startup = apbuart_startup,
+       .shutdown = apbuart_shutdown,
+       .set_termios = apbuart_set_termios,
+       .type = apbuart_type,
+       .release_port = apbuart_release_port,
+       .request_port = apbuart_request_port,
+       .config_port = apbuart_config_port,
+       .verify_port = apbuart_verify_port,
+};
+
+static struct uart_port grlib_apbuart_ports[UART_NR];
+static struct device_node *grlib_apbuart_nodes[UART_NR];
+
+static int apbuart_scan_fifo_size(struct uart_port *port, int portnumber)
+{
+       int ctrl, loop = 0;
+       int status;
+       int fifosize;
+       unsigned long flags;
+
+       ctrl = UART_GET_CTRL(port);
+
+       /*
+        * Enable the transceiver and wait for it to be ready to send data.
+        * Clear interrupts so that this process will not be externally
+        * interrupted in the middle (which can cause the transceiver to
+        * drain prematurely).
+        */
+
+       local_irq_save(flags);
+
+       UART_PUT_CTRL(port, ctrl | UART_CTRL_TE);
+
+       while (!UART_TX_READY(UART_GET_STATUS(port)))
+               loop++;
+
+       /*
+        * Disable the transceiver so data isn't actually sent during the
+        * actual test.
+        */
+
+       UART_PUT_CTRL(port, ctrl & ~(UART_CTRL_TE));
+
+       fifosize = 1;
+       UART_PUT_CHAR(port, 0);
+
+       /*
+        * So long as transmitting a character increments the tranceivier FIFO
+        * length the FIFO must be at least that big. These bytes will
+        * automatically drain off of the FIFO.
+        */
+
+       status = UART_GET_STATUS(port);
+       while (((status >> 20) & 0x3F) == fifosize) {
+               fifosize++;
+               UART_PUT_CHAR(port, 0);
+               status = UART_GET_STATUS(port);
+       }
+
+       fifosize--;
+
+       UART_PUT_CTRL(port, ctrl);
+       local_irq_restore(flags);
+
+       if (fifosize == 0)
+               fifosize = 1;
+
+       return fifosize;
+}
+
+static void apbuart_flush_fifo(struct uart_port *port)
+{
+       int i;
+
+       for (i = 0; i < port->fifosize; i++)
+               UART_GET_CHAR(port);
+}
+
+
+/* ======================================================================== */
+/* Console driver, if enabled                                               */
+/* ======================================================================== */
+
+#ifdef CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE
+
+static void apbuart_console_putchar(struct uart_port *port, int ch)
+{
+       unsigned int status;
+       do {
+               status = UART_GET_STATUS(port);
+       } while (!UART_TX_READY(status));
+       UART_PUT_CHAR(port, ch);
+}
+
+static void
+apbuart_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct uart_port *port = &grlib_apbuart_ports[co->index];
+       unsigned int status, old_cr, new_cr;
+
+       /* First save the CR then disable the interrupts */
+       old_cr = UART_GET_CTRL(port);
+       new_cr = old_cr & ~(UART_CTRL_RI | UART_CTRL_TI);
+       UART_PUT_CTRL(port, new_cr);
+
+       uart_console_write(port, s, count, apbuart_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the TCR
+        */
+       do {
+               status = UART_GET_STATUS(port);
+       } while (!UART_TX_READY(status));
+       UART_PUT_CTRL(port, old_cr);
+}
+
+static void __init
+apbuart_console_get_options(struct uart_port *port, int *baud,
+                           int *parity, int *bits)
+{
+       if (UART_GET_CTRL(port) & (UART_CTRL_RE | UART_CTRL_TE)) {
+
+               unsigned int quot, status;
+               status = UART_GET_STATUS(port);
+
+               *parity = 'n';
+               if (status & UART_CTRL_PE) {
+                       if ((status & UART_CTRL_PS) == 0)
+                               *parity = 'e';
+                       else
+                               *parity = 'o';
+               }
+
+               *bits = 8;
+               quot = UART_GET_SCAL(port) / 8;
+               *baud = port->uartclk / (16 * (quot + 1));
+       }
+}
+
+static int __init apbuart_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       int baud = 38400;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       pr_debug("apbuart_console_setup co=%p, co->index=%i, options=%s\n",
+                co, co->index, options);
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index >= grlib_apbuart_port_nr)
+               co->index = 0;
+
+       port = &grlib_apbuart_ports[co->index];
+
+       spin_lock_init(&port->lock);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               apbuart_console_get_options(port, &baud, &parity, &bits);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver grlib_apbuart_driver;
+
+static struct console grlib_apbuart_console = {
+       .name = "ttyS",
+       .write = apbuart_console_write,
+       .device = uart_console_device,
+       .setup = apbuart_console_setup,
+       .flags = CON_PRINTBUFFER,
+       .index = -1,
+       .data = &grlib_apbuart_driver,
+};
+
+
+static int grlib_apbuart_configure(void);
+
+static int __init apbuart_console_init(void)
+{
+       if (grlib_apbuart_configure())
+               return -ENODEV;
+       register_console(&grlib_apbuart_console);
+       return 0;
+}
+
+console_initcall(apbuart_console_init);
+
+#define APBUART_CONSOLE        (&grlib_apbuart_console)
+#else
+#define APBUART_CONSOLE        NULL
+#endif
+
+static struct uart_driver grlib_apbuart_driver = {
+       .owner = THIS_MODULE,
+       .driver_name = "serial",
+       .dev_name = "ttyS",
+       .major = SERIAL_APBUART_MAJOR,
+       .minor = SERIAL_APBUART_MINOR,
+       .nr = UART_NR,
+       .cons = APBUART_CONSOLE,
+};
+
+
+/* ======================================================================== */
+/* OF Platform Driver                                                       */
+/* ======================================================================== */
+
+static int __devinit apbuart_probe(struct platform_device *op,
+                                  const struct of_device_id *match)
+{
+       int i = -1;
+       struct uart_port *port = NULL;
+
+       i = 0;
+       for (i = 0; i < grlib_apbuart_port_nr; i++) {
+               if (op->dev.of_node == grlib_apbuart_nodes[i])
+                       break;
+       }
+
+       port = &grlib_apbuart_ports[i];
+       port->dev = &op->dev;
+
+       uart_add_one_port(&grlib_apbuart_driver, (struct uart_port *) port);
+
+       apbuart_flush_fifo((struct uart_port *) port);
+
+       printk(KERN_INFO "grlib-apbuart at 0x%llx, irq %d\n",
+              (unsigned long long) port->mapbase, port->irq);
+       return 0;
+}
+
+static struct of_device_id __initdata apbuart_match[] = {
+       {
+        .name = "GAISLER_APBUART",
+        },
+       {
+        .name = "01_00c",
+        },
+       {},
+};
+
+static struct of_platform_driver grlib_apbuart_of_driver = {
+       .probe = apbuart_probe,
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = "grlib-apbuart",
+               .of_match_table = apbuart_match,
+       },
+};
+
+
+static int grlib_apbuart_configure(void)
+{
+       struct device_node *np, *rp;
+       const u32 *prop;
+       int freq_khz, line = 0;
+
+       /* Get bus frequency */
+       rp = of_find_node_by_path("/");
+       if (!rp)
+               return -ENODEV;
+       rp = of_get_next_child(rp, NULL);
+       if (!rp)
+               return -ENODEV;
+       prop = of_get_property(rp, "clock-frequency", NULL);
+       if (!prop)
+               return -ENODEV;
+       freq_khz = *prop;
+
+       for_each_matching_node(np, apbuart_match) {
+               const int *irqs, *ampopts;
+               const struct amba_prom_registers *regs;
+               struct uart_port *port;
+               unsigned long addr;
+
+               ampopts = of_get_property(np, "ampopts", NULL);
+               if (ampopts && (*ampopts == 0))
+                       continue; /* Ignore if used by another OS instance */
+
+               irqs = of_get_property(np, "interrupts", NULL);
+               regs = of_get_property(np, "reg", NULL);
+
+               if (!irqs || !regs)
+                       continue;
+
+               grlib_apbuart_nodes[line] = np;
+
+               addr = regs->phys_addr;
+
+               port = &grlib_apbuart_ports[line];
+
+               port->mapbase = addr;
+               port->membase = ioremap(addr, sizeof(struct grlib_apbuart_regs_map));
+               port->irq = *irqs;
+               port->iotype = UPIO_MEM;
+               port->ops = &grlib_apbuart_ops;
+               port->flags = UPF_BOOT_AUTOCONF;
+               port->line = line;
+               port->uartclk = freq_khz * 1000;
+               port->fifosize = apbuart_scan_fifo_size((struct uart_port *) port, line);
+               line++;
+
+               /* We support maximum UART_NR uarts ... */
+               if (line == UART_NR)
+                       break;
+       }
+
+       grlib_apbuart_driver.nr = grlib_apbuart_port_nr = line;
+       return line ? 0 : -ENODEV;
+}
+
+static int __init grlib_apbuart_init(void)
+{
+       int ret;
+
+       /* Find all APBUARTS in device the tree and initialize their ports */
+       ret = grlib_apbuart_configure();
+       if (ret)
+               return ret;
+
+       printk(KERN_INFO "Serial: GRLIB APBUART driver\n");
+
+       ret = uart_register_driver(&grlib_apbuart_driver);
+
+       if (ret) {
+               printk(KERN_ERR "%s: uart_register_driver failed (%i)\n",
+                      __FILE__, ret);
+               return ret;
+       }
+
+       ret = of_register_platform_driver(&grlib_apbuart_of_driver);
+       if (ret) {
+               printk(KERN_ERR
+                      "%s: of_register_platform_driver failed (%i)\n",
+                      __FILE__, ret);
+               uart_unregister_driver(&grlib_apbuart_driver);
+               return ret;
+       }
+
+       return ret;
+}
+
+static void __exit grlib_apbuart_exit(void)
+{
+       int i;
+
+       for (i = 0; i < grlib_apbuart_port_nr; i++)
+               uart_remove_one_port(&grlib_apbuart_driver,
+                                    &grlib_apbuart_ports[i]);
+
+       uart_unregister_driver(&grlib_apbuart_driver);
+       of_unregister_platform_driver(&grlib_apbuart_of_driver);
+}
+
+module_init(grlib_apbuart_init);
+module_exit(grlib_apbuart_exit);
+
+MODULE_AUTHOR("Aeroflex Gaisler AB");
+MODULE_DESCRIPTION("GRLIB APBUART serial driver");
+MODULE_VERSION("2.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/apbuart.h b/drivers/tty/serial/apbuart.h
new file mode 100644 (file)
index 0000000..5faf87c
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef __GRLIB_APBUART_H__
+#define __GRLIB_APBUART_H__
+
+#include <asm/io.h>
+
+#define UART_NR                8
+static int grlib_apbuart_port_nr;
+
+struct grlib_apbuart_regs_map {
+       u32 data;
+       u32 status;
+       u32 ctrl;
+       u32 scaler;
+};
+
+struct amba_prom_registers {
+       unsigned int phys_addr;
+       unsigned int reg_size;
+};
+
+/*
+ *  The following defines the bits in the APBUART Status Registers.
+ */
+#define UART_STATUS_DR   0x00000001    /* Data Ready */
+#define UART_STATUS_TSE  0x00000002    /* TX Send Register Empty */
+#define UART_STATUS_THE  0x00000004    /* TX Hold Register Empty */
+#define UART_STATUS_BR   0x00000008    /* Break Error */
+#define UART_STATUS_OE   0x00000010    /* RX Overrun Error */
+#define UART_STATUS_PE   0x00000020    /* RX Parity Error */
+#define UART_STATUS_FE   0x00000040    /* RX Framing Error */
+#define UART_STATUS_ERR  0x00000078    /* Error Mask */
+
+/*
+ *  The following defines the bits in the APBUART Ctrl Registers.
+ */
+#define UART_CTRL_RE     0x00000001    /* Receiver enable */
+#define UART_CTRL_TE     0x00000002    /* Transmitter enable */
+#define UART_CTRL_RI     0x00000004    /* Receiver interrupt enable */
+#define UART_CTRL_TI     0x00000008    /* Transmitter irq */
+#define UART_CTRL_PS     0x00000010    /* Parity select */
+#define UART_CTRL_PE     0x00000020    /* Parity enable */
+#define UART_CTRL_FL     0x00000040    /* Flow control enable */
+#define UART_CTRL_LB     0x00000080    /* Loopback enable */
+
+#define APBBASE(port) ((struct grlib_apbuart_regs_map *)((port)->membase))
+
+#define APBBASE_DATA_P(port)   (&(APBBASE(port)->data))
+#define APBBASE_STATUS_P(port) (&(APBBASE(port)->status))
+#define APBBASE_CTRL_P(port)   (&(APBBASE(port)->ctrl))
+#define APBBASE_SCALAR_P(port) (&(APBBASE(port)->scaler))
+
+#define UART_GET_CHAR(port)    (__raw_readl(APBBASE_DATA_P(port)))
+#define UART_PUT_CHAR(port, v) (__raw_writel(v, APBBASE_DATA_P(port)))
+#define UART_GET_STATUS(port)  (__raw_readl(APBBASE_STATUS_P(port)))
+#define UART_PUT_STATUS(port, v)(__raw_writel(v, APBBASE_STATUS_P(port)))
+#define UART_GET_CTRL(port)    (__raw_readl(APBBASE_CTRL_P(port)))
+#define UART_PUT_CTRL(port, v) (__raw_writel(v, APBBASE_CTRL_P(port)))
+#define UART_GET_SCAL(port)    (__raw_readl(APBBASE_SCALAR_P(port)))
+#define UART_PUT_SCAL(port, v) (__raw_writel(v, APBBASE_SCALAR_P(port)))
+
+#define UART_RX_DATA(s)                (((s) & UART_STATUS_DR) != 0)
+#define UART_TX_READY(s)       (((s) & UART_STATUS_THE) != 0)
+
+#endif /* __GRLIB_APBUART_H__ */
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
new file mode 100644 (file)
index 0000000..3892666
--- /dev/null
@@ -0,0 +1,1808 @@
+/*
+ *  linux/drivers/char/atmel_serial.c
+ *
+ *  Driver for Atmel AT91 / AT32 Serial ports
+ *  Copyright (C) 2003 Rick Bronson
+ *
+ *  Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd.
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ *  DMA support added by Chip Coldwell.
+ *
+ * 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/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/tty_flip.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/atmel_pdc.h>
+#include <linux/atmel_serial.h>
+#include <linux/uaccess.h>
+
+#include <asm/io.h>
+#include <asm/ioctls.h>
+
+#include <asm/mach/serial_at91.h>
+#include <mach/board.h>
+
+#ifdef CONFIG_ARM
+#include <mach/cpu.h>
+#include <mach/gpio.h>
+#endif
+
+#define PDC_BUFFER_SIZE                512
+/* Revisit: We should calculate this based on the actual port settings */
+#define PDC_RX_TIMEOUT         (3 * 10)                /* 3 bytes */
+
+#if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+static void atmel_start_rx(struct uart_port *port);
+static void atmel_stop_rx(struct uart_port *port);
+
+#ifdef CONFIG_SERIAL_ATMEL_TTYAT
+
+/* Use device name ttyAT, major 204 and minor 154-169.  This is necessary if we
+ * should coexist with the 8250 driver, such as if we have an external 16C550
+ * UART. */
+#define SERIAL_ATMEL_MAJOR     204
+#define MINOR_START            154
+#define ATMEL_DEVICENAME       "ttyAT"
+
+#else
+
+/* Use device name ttyS, major 4, minor 64-68.  This is the usual serial port
+ * name, but it is legally reserved for the 8250 driver. */
+#define SERIAL_ATMEL_MAJOR     TTY_MAJOR
+#define MINOR_START            64
+#define ATMEL_DEVICENAME       "ttyS"
+
+#endif
+
+#define ATMEL_ISR_PASS_LIMIT   256
+
+/* UART registers. CR is write-only, hence no GET macro */
+#define UART_PUT_CR(port,v)    __raw_writel(v, (port)->membase + ATMEL_US_CR)
+#define UART_GET_MR(port)      __raw_readl((port)->membase + ATMEL_US_MR)
+#define UART_PUT_MR(port,v)    __raw_writel(v, (port)->membase + ATMEL_US_MR)
+#define UART_PUT_IER(port,v)   __raw_writel(v, (port)->membase + ATMEL_US_IER)
+#define UART_PUT_IDR(port,v)   __raw_writel(v, (port)->membase + ATMEL_US_IDR)
+#define UART_GET_IMR(port)     __raw_readl((port)->membase + ATMEL_US_IMR)
+#define UART_GET_CSR(port)     __raw_readl((port)->membase + ATMEL_US_CSR)
+#define UART_GET_CHAR(port)    __raw_readl((port)->membase + ATMEL_US_RHR)
+#define UART_PUT_CHAR(port,v)  __raw_writel(v, (port)->membase + ATMEL_US_THR)
+#define UART_GET_BRGR(port)    __raw_readl((port)->membase + ATMEL_US_BRGR)
+#define UART_PUT_BRGR(port,v)  __raw_writel(v, (port)->membase + ATMEL_US_BRGR)
+#define UART_PUT_RTOR(port,v)  __raw_writel(v, (port)->membase + ATMEL_US_RTOR)
+#define UART_PUT_TTGR(port, v) __raw_writel(v, (port)->membase + ATMEL_US_TTGR)
+
+ /* PDC registers */
+#define UART_PUT_PTCR(port,v)  __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR)
+#define UART_GET_PTSR(port)    __raw_readl((port)->membase + ATMEL_PDC_PTSR)
+
+#define UART_PUT_RPR(port,v)   __raw_writel(v, (port)->membase + ATMEL_PDC_RPR)
+#define UART_GET_RPR(port)     __raw_readl((port)->membase + ATMEL_PDC_RPR)
+#define UART_PUT_RCR(port,v)   __raw_writel(v, (port)->membase + ATMEL_PDC_RCR)
+#define UART_PUT_RNPR(port,v)  __raw_writel(v, (port)->membase + ATMEL_PDC_RNPR)
+#define UART_PUT_RNCR(port,v)  __raw_writel(v, (port)->membase + ATMEL_PDC_RNCR)
+
+#define UART_PUT_TPR(port,v)   __raw_writel(v, (port)->membase + ATMEL_PDC_TPR)
+#define UART_PUT_TCR(port,v)   __raw_writel(v, (port)->membase + ATMEL_PDC_TCR)
+#define UART_GET_TCR(port)     __raw_readl((port)->membase + ATMEL_PDC_TCR)
+
+static int (*atmel_open_hook)(struct uart_port *);
+static void (*atmel_close_hook)(struct uart_port *);
+
+struct atmel_dma_buffer {
+       unsigned char   *buf;
+       dma_addr_t      dma_addr;
+       unsigned int    dma_size;
+       unsigned int    ofs;
+};
+
+struct atmel_uart_char {
+       u16             status;
+       u16             ch;
+};
+
+#define ATMEL_SERIAL_RINGSIZE 1024
+
+/*
+ * We wrap our port structure around the generic uart_port.
+ */
+struct atmel_uart_port {
+       struct uart_port        uart;           /* uart */
+       struct clk              *clk;           /* uart clock */
+       int                     may_wakeup;     /* cached value of device_may_wakeup for times we need to disable it */
+       u32                     backup_imr;     /* IMR saved during suspend */
+       int                     break_active;   /* break being received */
+
+       short                   use_dma_rx;     /* enable PDC receiver */
+       short                   pdc_rx_idx;     /* current PDC RX buffer */
+       struct atmel_dma_buffer pdc_rx[2];      /* PDC receier */
+
+       short                   use_dma_tx;     /* enable PDC transmitter */
+       struct atmel_dma_buffer pdc_tx;         /* PDC transmitter */
+
+       struct tasklet_struct   tasklet;
+       unsigned int            irq_status;
+       unsigned int            irq_status_prev;
+
+       struct circ_buf         rx_ring;
+
+       struct serial_rs485     rs485;          /* rs485 settings */
+       unsigned int            tx_done_mask;
+};
+
+static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
+
+#ifdef SUPPORT_SYSRQ
+static struct console atmel_console;
+#endif
+
+static inline struct atmel_uart_port *
+to_atmel_uart_port(struct uart_port *uart)
+{
+       return container_of(uart, struct atmel_uart_port, uart);
+}
+
+#ifdef CONFIG_SERIAL_ATMEL_PDC
+static bool atmel_use_dma_rx(struct uart_port *port)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       return atmel_port->use_dma_rx;
+}
+
+static bool atmel_use_dma_tx(struct uart_port *port)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       return atmel_port->use_dma_tx;
+}
+#else
+static bool atmel_use_dma_rx(struct uart_port *port)
+{
+       return false;
+}
+
+static bool atmel_use_dma_tx(struct uart_port *port)
+{
+       return false;
+}
+#endif
+
+/* Enable or disable the rs485 support */
+void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       unsigned int mode;
+
+       spin_lock(&port->lock);
+
+       /* Disable interrupts */
+       UART_PUT_IDR(port, atmel_port->tx_done_mask);
+
+       mode = UART_GET_MR(port);
+
+       /* Resetting serial mode to RS232 (0x0) */
+       mode &= ~ATMEL_US_USMODE;
+
+       atmel_port->rs485 = *rs485conf;
+
+       if (rs485conf->flags & SER_RS485_ENABLED) {
+               dev_dbg(port->dev, "Setting UART to RS485\n");
+               atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
+               if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND)
+                       UART_PUT_TTGR(port, rs485conf->delay_rts_after_send);
+               mode |= ATMEL_US_USMODE_RS485;
+       } else {
+               dev_dbg(port->dev, "Setting UART to RS232\n");
+               if (atmel_use_dma_tx(port))
+                       atmel_port->tx_done_mask = ATMEL_US_ENDTX |
+                               ATMEL_US_TXBUFE;
+               else
+                       atmel_port->tx_done_mask = ATMEL_US_TXRDY;
+       }
+       UART_PUT_MR(port, mode);
+
+       /* Enable interrupts */
+       UART_PUT_IER(port, atmel_port->tx_done_mask);
+
+       spin_unlock(&port->lock);
+
+}
+
+/*
+ * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
+ */
+static u_int atmel_tx_empty(struct uart_port *port)
+{
+       return (UART_GET_CSR(port) & ATMEL_US_TXEMPTY) ? TIOCSER_TEMT : 0;
+}
+
+/*
+ * Set state of the modem control output lines
+ */
+static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
+{
+       unsigned int control = 0;
+       unsigned int mode;
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+#ifdef CONFIG_ARCH_AT91RM9200
+       if (cpu_is_at91rm9200()) {
+               /*
+                * AT91RM9200 Errata #39: RTS0 is not internally connected
+                * to PA21. We need to drive the pin manually.
+                */
+               if (port->mapbase == AT91RM9200_BASE_US0) {
+                       if (mctrl & TIOCM_RTS)
+                               at91_set_gpio_value(AT91_PIN_PA21, 0);
+                       else
+                               at91_set_gpio_value(AT91_PIN_PA21, 1);
+               }
+       }
+#endif
+
+       if (mctrl & TIOCM_RTS)
+               control |= ATMEL_US_RTSEN;
+       else
+               control |= ATMEL_US_RTSDIS;
+
+       if (mctrl & TIOCM_DTR)
+               control |= ATMEL_US_DTREN;
+       else
+               control |= ATMEL_US_DTRDIS;
+
+       UART_PUT_CR(port, control);
+
+       /* Local loopback mode? */
+       mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE;
+       if (mctrl & TIOCM_LOOP)
+               mode |= ATMEL_US_CHMODE_LOC_LOOP;
+       else
+               mode |= ATMEL_US_CHMODE_NORMAL;
+
+       /* Resetting serial mode to RS232 (0x0) */
+       mode &= ~ATMEL_US_USMODE;
+
+       if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
+               dev_dbg(port->dev, "Setting UART to RS485\n");
+               if (atmel_port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
+                       UART_PUT_TTGR(port,
+                                       atmel_port->rs485.delay_rts_after_send);
+               mode |= ATMEL_US_USMODE_RS485;
+       } else {
+               dev_dbg(port->dev, "Setting UART to RS232\n");
+       }
+       UART_PUT_MR(port, mode);
+}
+
+/*
+ * Get state of the modem control input lines
+ */
+static u_int atmel_get_mctrl(struct uart_port *port)
+{
+       unsigned int status, ret = 0;
+
+       status = UART_GET_CSR(port);
+
+       /*
+        * The control signals are active low.
+        */
+       if (!(status & ATMEL_US_DCD))
+               ret |= TIOCM_CD;
+       if (!(status & ATMEL_US_CTS))
+               ret |= TIOCM_CTS;
+       if (!(status & ATMEL_US_DSR))
+               ret |= TIOCM_DSR;
+       if (!(status & ATMEL_US_RI))
+               ret |= TIOCM_RI;
+
+       return ret;
+}
+
+/*
+ * Stop transmitting.
+ */
+static void atmel_stop_tx(struct uart_port *port)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       if (atmel_use_dma_tx(port)) {
+               /* disable PDC transmit */
+               UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
+       }
+       /* Disable interrupts */
+       UART_PUT_IDR(port, atmel_port->tx_done_mask);
+
+       if (atmel_port->rs485.flags & SER_RS485_ENABLED)
+               atmel_start_rx(port);
+}
+
+/*
+ * Start transmitting.
+ */
+static void atmel_start_tx(struct uart_port *port)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       if (atmel_use_dma_tx(port)) {
+               if (UART_GET_PTSR(port) & ATMEL_PDC_TXTEN)
+                       /* The transmitter is already running.  Yes, we
+                          really need this.*/
+                       return;
+
+               if (atmel_port->rs485.flags & SER_RS485_ENABLED)
+                       atmel_stop_rx(port);
+
+               /* re-enable PDC transmit */
+               UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
+       }
+       /* Enable interrupts */
+       UART_PUT_IER(port, atmel_port->tx_done_mask);
+}
+
+/*
+ * start receiving - port is in process of being opened.
+ */
+static void atmel_start_rx(struct uart_port *port)
+{
+       UART_PUT_CR(port, ATMEL_US_RSTSTA);  /* reset status and receiver */
+
+       if (atmel_use_dma_rx(port)) {
+               /* enable PDC controller */
+               UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
+                       port->read_status_mask);
+               UART_PUT_PTCR(port, ATMEL_PDC_RXTEN);
+       } else {
+               UART_PUT_IER(port, ATMEL_US_RXRDY);
+       }
+}
+
+/*
+ * Stop receiving - port is in process of being closed.
+ */
+static void atmel_stop_rx(struct uart_port *port)
+{
+       if (atmel_use_dma_rx(port)) {
+               /* disable PDC receive */
+               UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS);
+               UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
+                       port->read_status_mask);
+       } else {
+               UART_PUT_IDR(port, ATMEL_US_RXRDY);
+       }
+}
+
+/*
+ * Enable modem status interrupts
+ */
+static void atmel_enable_ms(struct uart_port *port)
+{
+       UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC
+                       | ATMEL_US_DCDIC | ATMEL_US_CTSIC);
+}
+
+/*
+ * Control the transmission of a break signal
+ */
+static void atmel_break_ctl(struct uart_port *port, int break_state)
+{
+       if (break_state != 0)
+               UART_PUT_CR(port, ATMEL_US_STTBRK);     /* start break */
+       else
+               UART_PUT_CR(port, ATMEL_US_STPBRK);     /* stop break */
+}
+
+/*
+ * Stores the incoming character in the ring buffer
+ */
+static void
+atmel_buffer_rx_char(struct uart_port *port, unsigned int status,
+                    unsigned int ch)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       struct circ_buf *ring = &atmel_port->rx_ring;
+       struct atmel_uart_char *c;
+
+       if (!CIRC_SPACE(ring->head, ring->tail, ATMEL_SERIAL_RINGSIZE))
+               /* Buffer overflow, ignore char */
+               return;
+
+       c = &((struct atmel_uart_char *)ring->buf)[ring->head];
+       c->status       = status;
+       c->ch           = ch;
+
+       /* Make sure the character is stored before we update head. */
+       smp_wmb();
+
+       ring->head = (ring->head + 1) & (ATMEL_SERIAL_RINGSIZE - 1);
+}
+
+/*
+ * Deal with parity, framing and overrun errors.
+ */
+static void atmel_pdc_rxerr(struct uart_port *port, unsigned int status)
+{
+       /* clear error */
+       UART_PUT_CR(port, ATMEL_US_RSTSTA);
+
+       if (status & ATMEL_US_RXBRK) {
+               /* ignore side-effect */
+               status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME);
+               port->icount.brk++;
+       }
+       if (status & ATMEL_US_PARE)
+               port->icount.parity++;
+       if (status & ATMEL_US_FRAME)
+               port->icount.frame++;
+       if (status & ATMEL_US_OVRE)
+               port->icount.overrun++;
+}
+
+/*
+ * Characters received (called from interrupt handler)
+ */
+static void atmel_rx_chars(struct uart_port *port)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       unsigned int status, ch;
+
+       status = UART_GET_CSR(port);
+       while (status & ATMEL_US_RXRDY) {
+               ch = UART_GET_CHAR(port);
+
+               /*
+                * note that the error handling code is
+                * out of the main execution path
+                */
+               if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME
+                                      | ATMEL_US_OVRE | ATMEL_US_RXBRK)
+                            || atmel_port->break_active)) {
+
+                       /* clear error */
+                       UART_PUT_CR(port, ATMEL_US_RSTSTA);
+
+                       if (status & ATMEL_US_RXBRK
+                           && !atmel_port->break_active) {
+                               atmel_port->break_active = 1;
+                               UART_PUT_IER(port, ATMEL_US_RXBRK);
+                       } else {
+                               /*
+                                * This is either the end-of-break
+                                * condition or we've received at
+                                * least one character without RXBRK
+                                * being set. In both cases, the next
+                                * RXBRK will indicate start-of-break.
+                                */
+                               UART_PUT_IDR(port, ATMEL_US_RXBRK);
+                               status &= ~ATMEL_US_RXBRK;
+                               atmel_port->break_active = 0;
+                       }
+               }
+
+               atmel_buffer_rx_char(port, status, ch);
+               status = UART_GET_CSR(port);
+       }
+
+       tasklet_schedule(&atmel_port->tasklet);
+}
+
+/*
+ * Transmit characters (called from tasklet with TXRDY interrupt
+ * disabled)
+ */
+static void atmel_tx_chars(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->state->xmit;
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       if (port->x_char && UART_GET_CSR(port) & atmel_port->tx_done_mask) {
+               UART_PUT_CHAR(port, port->x_char);
+               port->icount.tx++;
+               port->x_char = 0;
+       }
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+               return;
+
+       while (UART_GET_CSR(port) & atmel_port->tx_done_mask) {
+               UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (!uart_circ_empty(xmit))
+               /* Enable interrupts */
+               UART_PUT_IER(port, atmel_port->tx_done_mask);
+}
+
+/*
+ * receive interrupt handler.
+ */
+static void
+atmel_handle_receive(struct uart_port *port, unsigned int pending)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       if (atmel_use_dma_rx(port)) {
+               /*
+                * PDC receive. Just schedule the tasklet and let it
+                * figure out the details.
+                *
+                * TODO: We're not handling error flags correctly at
+                * the moment.
+                */
+               if (pending & (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)) {
+                       UART_PUT_IDR(port, (ATMEL_US_ENDRX
+                                               | ATMEL_US_TIMEOUT));
+                       tasklet_schedule(&atmel_port->tasklet);
+               }
+
+               if (pending & (ATMEL_US_RXBRK | ATMEL_US_OVRE |
+                               ATMEL_US_FRAME | ATMEL_US_PARE))
+                       atmel_pdc_rxerr(port, pending);
+       }
+
+       /* Interrupt receive */
+       if (pending & ATMEL_US_RXRDY)
+               atmel_rx_chars(port);
+       else if (pending & ATMEL_US_RXBRK) {
+               /*
+                * End of break detected. If it came along with a
+                * character, atmel_rx_chars will handle it.
+                */
+               UART_PUT_CR(port, ATMEL_US_RSTSTA);
+               UART_PUT_IDR(port, ATMEL_US_RXBRK);
+               atmel_port->break_active = 0;
+       }
+}
+
+/*
+ * transmit interrupt handler. (Transmit is IRQF_NODELAY safe)
+ */
+static void
+atmel_handle_transmit(struct uart_port *port, unsigned int pending)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       if (pending & atmel_port->tx_done_mask) {
+               /* Either PDC or interrupt transmission */
+               UART_PUT_IDR(port, atmel_port->tx_done_mask);
+               tasklet_schedule(&atmel_port->tasklet);
+       }
+}
+
+/*
+ * status flags interrupt handler.
+ */
+static void
+atmel_handle_status(struct uart_port *port, unsigned int pending,
+                   unsigned int status)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC
+                               | ATMEL_US_CTSIC)) {
+               atmel_port->irq_status = status;
+               tasklet_schedule(&atmel_port->tasklet);
+       }
+}
+
+/*
+ * Interrupt handler
+ */
+static irqreturn_t atmel_interrupt(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       unsigned int status, pending, pass_counter = 0;
+
+       do {
+               status = UART_GET_CSR(port);
+               pending = status & UART_GET_IMR(port);
+               if (!pending)
+                       break;
+
+               atmel_handle_receive(port, pending);
+               atmel_handle_status(port, pending, status);
+               atmel_handle_transmit(port, pending);
+       } while (pass_counter++ < ATMEL_ISR_PASS_LIMIT);
+
+       return pass_counter ? IRQ_HANDLED : IRQ_NONE;
+}
+
+/*
+ * Called from tasklet with ENDTX and TXBUFE interrupts disabled.
+ */
+static void atmel_tx_dma(struct uart_port *port)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       struct circ_buf *xmit = &port->state->xmit;
+       struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
+       int count;
+
+       /* nothing left to transmit? */
+       if (UART_GET_TCR(port))
+               return;
+
+       xmit->tail += pdc->ofs;
+       xmit->tail &= UART_XMIT_SIZE - 1;
+
+       port->icount.tx += pdc->ofs;
+       pdc->ofs = 0;
+
+       /* more to transmit - setup next transfer */
+
+       /* disable PDC transmit */
+       UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
+
+       if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) {
+               dma_sync_single_for_device(port->dev,
+                                          pdc->dma_addr,
+                                          pdc->dma_size,
+                                          DMA_TO_DEVICE);
+
+               count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+               pdc->ofs = count;
+
+               UART_PUT_TPR(port, pdc->dma_addr + xmit->tail);
+               UART_PUT_TCR(port, count);
+               /* re-enable PDC transmit */
+               UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
+               /* Enable interrupts */
+               UART_PUT_IER(port, atmel_port->tx_done_mask);
+       } else {
+               if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
+                       /* DMA done, stop TX, start RX for RS485 */
+                       atmel_start_rx(port);
+               }
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+}
+
+static void atmel_rx_from_ring(struct uart_port *port)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       struct circ_buf *ring = &atmel_port->rx_ring;
+       unsigned int flg;
+       unsigned int status;
+
+       while (ring->head != ring->tail) {
+               struct atmel_uart_char c;
+
+               /* Make sure c is loaded after head. */
+               smp_rmb();
+
+               c = ((struct atmel_uart_char *)ring->buf)[ring->tail];
+
+               ring->tail = (ring->tail + 1) & (ATMEL_SERIAL_RINGSIZE - 1);
+
+               port->icount.rx++;
+               status = c.status;
+               flg = TTY_NORMAL;
+
+               /*
+                * note that the error handling code is
+                * out of the main execution path
+                */
+               if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME
+                                      | ATMEL_US_OVRE | ATMEL_US_RXBRK))) {
+                       if (status & ATMEL_US_RXBRK) {
+                               /* ignore side-effect */
+                               status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME);
+
+                               port->icount.brk++;
+                               if (uart_handle_break(port))
+                                       continue;
+                       }
+                       if (status & ATMEL_US_PARE)
+                               port->icount.parity++;
+                       if (status & ATMEL_US_FRAME)
+                               port->icount.frame++;
+                       if (status & ATMEL_US_OVRE)
+                               port->icount.overrun++;
+
+                       status &= port->read_status_mask;
+
+                       if (status & ATMEL_US_RXBRK)
+                               flg = TTY_BREAK;
+                       else if (status & ATMEL_US_PARE)
+                               flg = TTY_PARITY;
+                       else if (status & ATMEL_US_FRAME)
+                               flg = TTY_FRAME;
+               }
+
+
+               if (uart_handle_sysrq_char(port, c.ch))
+                       continue;
+
+               uart_insert_char(port, status, ATMEL_US_OVRE, c.ch, flg);
+       }
+
+       /*
+        * Drop the lock here since it might end up calling
+        * uart_start(), which takes the lock.
+        */
+       spin_unlock(&port->lock);
+       tty_flip_buffer_push(port->state->port.tty);
+       spin_lock(&port->lock);
+}
+
+static void atmel_rx_from_dma(struct uart_port *port)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       struct tty_struct *tty = port->state->port.tty;
+       struct atmel_dma_buffer *pdc;
+       int rx_idx = atmel_port->pdc_rx_idx;
+       unsigned int head;
+       unsigned int tail;
+       unsigned int count;
+
+       do {
+               /* Reset the UART timeout early so that we don't miss one */
+               UART_PUT_CR(port, ATMEL_US_STTTO);
+
+               pdc = &atmel_port->pdc_rx[rx_idx];
+               head = UART_GET_RPR(port) - pdc->dma_addr;
+               tail = pdc->ofs;
+
+               /* If the PDC has switched buffers, RPR won't contain
+                * any address within the current buffer. Since head
+                * is unsigned, we just need a one-way comparison to
+                * find out.
+                *
+                * In this case, we just need to consume the entire
+                * buffer and resubmit it for DMA. This will clear the
+                * ENDRX bit as well, so that we can safely re-enable
+                * all interrupts below.
+                */
+               head = min(head, pdc->dma_size);
+
+               if (likely(head != tail)) {
+                       dma_sync_single_for_cpu(port->dev, pdc->dma_addr,
+                                       pdc->dma_size, DMA_FROM_DEVICE);
+
+                       /*
+                        * head will only wrap around when we recycle
+                        * the DMA buffer, and when that happens, we
+                        * explicitly set tail to 0. So head will
+                        * always be greater than tail.
+                        */
+                       count = head - tail;
+
+                       tty_insert_flip_string(tty, pdc->buf + pdc->ofs, count);
+
+                       dma_sync_single_for_device(port->dev, pdc->dma_addr,
+                                       pdc->dma_size, DMA_FROM_DEVICE);
+
+                       port->icount.rx += count;
+                       pdc->ofs = head;
+               }
+
+               /*
+                * If the current buffer is full, we need to check if
+                * the next one contains any additional data.
+                */
+               if (head >= pdc->dma_size) {
+                       pdc->ofs = 0;
+                       UART_PUT_RNPR(port, pdc->dma_addr);
+                       UART_PUT_RNCR(port, pdc->dma_size);
+
+                       rx_idx = !rx_idx;
+                       atmel_port->pdc_rx_idx = rx_idx;
+               }
+       } while (head >= pdc->dma_size);
+
+       /*
+        * Drop the lock here since it might end up calling
+        * uart_start(), which takes the lock.
+        */
+       spin_unlock(&port->lock);
+       tty_flip_buffer_push(tty);
+       spin_lock(&port->lock);
+
+       UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
+}
+
+/*
+ * tasklet handling tty stuff outside the interrupt handler.
+ */
+static void atmel_tasklet_func(unsigned long data)
+{
+       struct uart_port *port = (struct uart_port *)data;
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       unsigned int status;
+       unsigned int status_change;
+
+       /* The interrupt handler does not take the lock */
+       spin_lock(&port->lock);
+
+       if (atmel_use_dma_tx(port))
+               atmel_tx_dma(port);
+       else
+               atmel_tx_chars(port);
+
+       status = atmel_port->irq_status;
+       status_change = status ^ atmel_port->irq_status_prev;
+
+       if (status_change & (ATMEL_US_RI | ATMEL_US_DSR
+                               | ATMEL_US_DCD | ATMEL_US_CTS)) {
+               /* TODO: All reads to CSR will clear these interrupts! */
+               if (status_change & ATMEL_US_RI)
+                       port->icount.rng++;
+               if (status_change & ATMEL_US_DSR)
+                       port->icount.dsr++;
+               if (status_change & ATMEL_US_DCD)
+                       uart_handle_dcd_change(port, !(status & ATMEL_US_DCD));
+               if (status_change & ATMEL_US_CTS)
+                       uart_handle_cts_change(port, !(status & ATMEL_US_CTS));
+
+               wake_up_interruptible(&port->state->port.delta_msr_wait);
+
+               atmel_port->irq_status_prev = status;
+       }
+
+       if (atmel_use_dma_rx(port))
+               atmel_rx_from_dma(port);
+       else
+               atmel_rx_from_ring(port);
+
+       spin_unlock(&port->lock);
+}
+
+/*
+ * Perform initialization and enable port for reception
+ */
+static int atmel_startup(struct uart_port *port)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       struct tty_struct *tty = port->state->port.tty;
+       int retval;
+
+       /*
+        * Ensure that no interrupts are enabled otherwise when
+        * request_irq() is called we could get stuck trying to
+        * handle an unexpected interrupt
+        */
+       UART_PUT_IDR(port, -1);
+
+       /*
+        * Allocate the IRQ
+        */
+       retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED,
+                       tty ? tty->name : "atmel_serial", port);
+       if (retval) {
+               printk("atmel_serial: atmel_startup - Can't get irq\n");
+               return retval;
+       }
+
+       /*
+        * Initialize DMA (if necessary)
+        */
+       if (atmel_use_dma_rx(port)) {
+               int i;
+
+               for (i = 0; i < 2; i++) {
+                       struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
+
+                       pdc->buf = kmalloc(PDC_BUFFER_SIZE, GFP_KERNEL);
+                       if (pdc->buf == NULL) {
+                               if (i != 0) {
+                                       dma_unmap_single(port->dev,
+                                               atmel_port->pdc_rx[0].dma_addr,
+                                               PDC_BUFFER_SIZE,
+                                               DMA_FROM_DEVICE);
+                                       kfree(atmel_port->pdc_rx[0].buf);
+                               }
+                               free_irq(port->irq, port);
+                               return -ENOMEM;
+                       }
+                       pdc->dma_addr = dma_map_single(port->dev,
+                                                      pdc->buf,
+                                                      PDC_BUFFER_SIZE,
+                                                      DMA_FROM_DEVICE);
+                       pdc->dma_size = PDC_BUFFER_SIZE;
+                       pdc->ofs = 0;
+               }
+
+               atmel_port->pdc_rx_idx = 0;
+
+               UART_PUT_RPR(port, atmel_port->pdc_rx[0].dma_addr);
+               UART_PUT_RCR(port, PDC_BUFFER_SIZE);
+
+               UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr);
+               UART_PUT_RNCR(port, PDC_BUFFER_SIZE);
+       }
+       if (atmel_use_dma_tx(port)) {
+               struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
+               struct circ_buf *xmit = &port->state->xmit;
+
+               pdc->buf = xmit->buf;
+               pdc->dma_addr = dma_map_single(port->dev,
+                                              pdc->buf,
+                                              UART_XMIT_SIZE,
+                                              DMA_TO_DEVICE);
+               pdc->dma_size = UART_XMIT_SIZE;
+               pdc->ofs = 0;
+       }
+
+       /*
+        * If there is a specific "open" function (to register
+        * control line interrupts)
+        */
+       if (atmel_open_hook) {
+               retval = atmel_open_hook(port);
+               if (retval) {
+                       free_irq(port->irq, port);
+                       return retval;
+               }
+       }
+
+       /* Save current CSR for comparison in atmel_tasklet_func() */
+       atmel_port->irq_status_prev = UART_GET_CSR(port);
+       atmel_port->irq_status = atmel_port->irq_status_prev;
+
+       /*
+        * Finally, enable the serial port
+        */
+       UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
+       /* enable xmit & rcvr */
+       UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
+
+       if (atmel_use_dma_rx(port)) {
+               /* set UART timeout */
+               UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
+               UART_PUT_CR(port, ATMEL_US_STTTO);
+
+               UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
+               /* enable PDC controller */
+               UART_PUT_PTCR(port, ATMEL_PDC_RXTEN);
+       } else {
+               /* enable receive only */
+               UART_PUT_IER(port, ATMEL_US_RXRDY);
+       }
+
+       return 0;
+}
+
+/*
+ * Disable the port
+ */
+static void atmel_shutdown(struct uart_port *port)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       /*
+        * Ensure everything is stopped.
+        */
+       atmel_stop_rx(port);
+       atmel_stop_tx(port);
+
+       /*
+        * Shut-down the DMA.
+        */
+       if (atmel_use_dma_rx(port)) {
+               int i;
+
+               for (i = 0; i < 2; i++) {
+                       struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
+
+                       dma_unmap_single(port->dev,
+                                        pdc->dma_addr,
+                                        pdc->dma_size,
+                                        DMA_FROM_DEVICE);
+                       kfree(pdc->buf);
+               }
+       }
+       if (atmel_use_dma_tx(port)) {
+               struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
+
+               dma_unmap_single(port->dev,
+                                pdc->dma_addr,
+                                pdc->dma_size,
+                                DMA_TO_DEVICE);
+       }
+
+       /*
+        * Disable all interrupts, port and break condition.
+        */
+       UART_PUT_CR(port, ATMEL_US_RSTSTA);
+       UART_PUT_IDR(port, -1);
+
+       /*
+        * Free the interrupt
+        */
+       free_irq(port->irq, port);
+
+       /*
+        * If there is a specific "close" function (to unregister
+        * control line interrupts)
+        */
+       if (atmel_close_hook)
+               atmel_close_hook(port);
+}
+
+/*
+ * Flush any TX data submitted for DMA. Called when the TX circular
+ * buffer is reset.
+ */
+static void atmel_flush_buffer(struct uart_port *port)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       if (atmel_use_dma_tx(port)) {
+               UART_PUT_TCR(port, 0);
+               atmel_port->pdc_tx.ofs = 0;
+       }
+}
+
+/*
+ * Power / Clock management.
+ */
+static void atmel_serial_pm(struct uart_port *port, unsigned int state,
+                           unsigned int oldstate)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       switch (state) {
+       case 0:
+               /*
+                * Enable the peripheral clock for this serial port.
+                * This is called on uart_open() or a resume event.
+                */
+               clk_enable(atmel_port->clk);
+
+               /* re-enable interrupts if we disabled some on suspend */
+               UART_PUT_IER(port, atmel_port->backup_imr);
+               break;
+       case 3:
+               /* Back up the interrupt mask and disable all interrupts */
+               atmel_port->backup_imr = UART_GET_IMR(port);
+               UART_PUT_IDR(port, -1);
+
+               /*
+                * Disable the peripheral clock for this serial port.
+                * This is called on uart_close() or a suspend event.
+                */
+               clk_disable(atmel_port->clk);
+               break;
+       default:
+               printk(KERN_ERR "atmel_serial: unknown pm %d\n", state);
+       }
+}
+
+/*
+ * Change the port parameters
+ */
+static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
+                             struct ktermios *old)
+{
+       unsigned long flags;
+       unsigned int mode, imr, quot, baud;
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       /* Get current mode register */
+       mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL
+                                       | ATMEL_US_NBSTOP | ATMEL_US_PAR
+                                       | ATMEL_US_USMODE);
+
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
+       quot = uart_get_divisor(port, baud);
+
+       if (quot > 65535) {     /* BRGR is 16-bit, so switch to slower clock */
+               quot /= 8;
+               mode |= ATMEL_US_USCLKS_MCK_DIV8;
+       }
+
+       /* byte size */
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               mode |= ATMEL_US_CHRL_5;
+               break;
+       case CS6:
+               mode |= ATMEL_US_CHRL_6;
+               break;
+       case CS7:
+               mode |= ATMEL_US_CHRL_7;
+               break;
+       default:
+               mode |= ATMEL_US_CHRL_8;
+               break;
+       }
+
+       /* stop bits */
+       if (termios->c_cflag & CSTOPB)
+               mode |= ATMEL_US_NBSTOP_2;
+
+       /* parity */
+       if (termios->c_cflag & PARENB) {
+               /* Mark or Space parity */
+               if (termios->c_cflag & CMSPAR) {
+                       if (termios->c_cflag & PARODD)
+                               mode |= ATMEL_US_PAR_MARK;
+                       else
+                               mode |= ATMEL_US_PAR_SPACE;
+               } else if (termios->c_cflag & PARODD)
+                       mode |= ATMEL_US_PAR_ODD;
+               else
+                       mode |= ATMEL_US_PAR_EVEN;
+       } else
+               mode |= ATMEL_US_PAR_NONE;
+
+       /* hardware handshake (RTS/CTS) */
+       if (termios->c_cflag & CRTSCTS)
+               mode |= ATMEL_US_USMODE_HWHS;
+       else
+               mode |= ATMEL_US_USMODE_NORMAL;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       port->read_status_mask = ATMEL_US_OVRE;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE);
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               port->read_status_mask |= ATMEL_US_RXBRK;
+
+       if (atmel_use_dma_rx(port))
+               /* need to enable error interrupts */
+               UART_PUT_IER(port, port->read_status_mask);
+
+       /*
+        * Characters to ignore
+        */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE);
+       if (termios->c_iflag & IGNBRK) {
+               port->ignore_status_mask |= ATMEL_US_RXBRK;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       port->ignore_status_mask |= ATMEL_US_OVRE;
+       }
+       /* TODO: Ignore all characters if CREAD is set.*/
+
+       /* update the per-port timeout */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       /*
+        * save/disable interrupts. The tty layer will ensure that the
+        * transmitter is empty if requested by the caller, so there's
+        * no need to wait for it here.
+        */
+       imr = UART_GET_IMR(port);
+       UART_PUT_IDR(port, -1);
+
+       /* disable receiver and transmitter */
+       UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS);
+
+       /* Resetting serial mode to RS232 (0x0) */
+       mode &= ~ATMEL_US_USMODE;
+
+       if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
+               dev_dbg(port->dev, "Setting UART to RS485\n");
+               if (atmel_port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
+                       UART_PUT_TTGR(port,
+                                       atmel_port->rs485.delay_rts_after_send);
+               mode |= ATMEL_US_USMODE_RS485;
+       } else {
+               dev_dbg(port->dev, "Setting UART to RS232\n");
+       }
+
+       /* set the parity, stop bits and data size */
+       UART_PUT_MR(port, mode);
+
+       /* set the baud rate */
+       UART_PUT_BRGR(port, quot);
+       UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
+       UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
+
+       /* restore interrupts */
+       UART_PUT_IER(port, imr);
+
+       /* CTS flow-control and modem-status interrupts */
+       if (UART_ENABLE_MS(port, termios->c_cflag))
+               port->ops->enable_ms(port);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/*
+ * Return string describing the specified port
+ */
+static const char *atmel_type(struct uart_port *port)
+{
+       return (port->type == PORT_ATMEL) ? "ATMEL_SERIAL" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'.
+ */
+static void atmel_release_port(struct uart_port *port)
+{
+       struct platform_device *pdev = to_platform_device(port->dev);
+       int size = pdev->resource[0].end - pdev->resource[0].start + 1;
+
+       release_mem_region(port->mapbase, size);
+
+       if (port->flags & UPF_IOREMAP) {
+               iounmap(port->membase);
+               port->membase = NULL;
+       }
+}
+
+/*
+ * Request the memory region(s) being used by 'port'.
+ */
+static int atmel_request_port(struct uart_port *port)
+{
+       struct platform_device *pdev = to_platform_device(port->dev);
+       int size = pdev->resource[0].end - pdev->resource[0].start + 1;
+
+       if (!request_mem_region(port->mapbase, size, "atmel_serial"))
+               return -EBUSY;
+
+       if (port->flags & UPF_IOREMAP) {
+               port->membase = ioremap(port->mapbase, size);
+               if (port->membase == NULL) {
+                       release_mem_region(port->mapbase, size);
+                       return -ENOMEM;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void atmel_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = PORT_ATMEL;
+               atmel_request_port(port);
+       }
+}
+
+/*
+ * Verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int atmel_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       int ret = 0;
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_ATMEL)
+               ret = -EINVAL;
+       if (port->irq != ser->irq)
+               ret = -EINVAL;
+       if (ser->io_type != SERIAL_IO_MEM)
+               ret = -EINVAL;
+       if (port->uartclk / 16 != ser->baud_base)
+               ret = -EINVAL;
+       if ((void *)port->mapbase != ser->iomem_base)
+               ret = -EINVAL;
+       if (port->iobase != ser->port)
+               ret = -EINVAL;
+       if (ser->hub6 != 0)
+               ret = -EINVAL;
+       return ret;
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+static int atmel_poll_get_char(struct uart_port *port)
+{
+       while (!(UART_GET_CSR(port) & ATMEL_US_RXRDY))
+               cpu_relax();
+
+       return UART_GET_CHAR(port);
+}
+
+static void atmel_poll_put_char(struct uart_port *port, unsigned char ch)
+{
+       while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY))
+               cpu_relax();
+
+       UART_PUT_CHAR(port, ch);
+}
+#endif
+
+static int
+atmel_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
+{
+       struct serial_rs485 rs485conf;
+
+       switch (cmd) {
+       case TIOCSRS485:
+               if (copy_from_user(&rs485conf, (struct serial_rs485 *) arg,
+                                       sizeof(rs485conf)))
+                       return -EFAULT;
+
+               atmel_config_rs485(port, &rs485conf);
+               break;
+
+       case TIOCGRS485:
+               if (copy_to_user((struct serial_rs485 *) arg,
+                                       &(to_atmel_uart_port(port)->rs485),
+                                       sizeof(rs485conf)))
+                       return -EFAULT;
+               break;
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+       return 0;
+}
+
+
+
+static struct uart_ops atmel_pops = {
+       .tx_empty       = atmel_tx_empty,
+       .set_mctrl      = atmel_set_mctrl,
+       .get_mctrl      = atmel_get_mctrl,
+       .stop_tx        = atmel_stop_tx,
+       .start_tx       = atmel_start_tx,
+       .stop_rx        = atmel_stop_rx,
+       .enable_ms      = atmel_enable_ms,
+       .break_ctl      = atmel_break_ctl,
+       .startup        = atmel_startup,
+       .shutdown       = atmel_shutdown,
+       .flush_buffer   = atmel_flush_buffer,
+       .set_termios    = atmel_set_termios,
+       .type           = atmel_type,
+       .release_port   = atmel_release_port,
+       .request_port   = atmel_request_port,
+       .config_port    = atmel_config_port,
+       .verify_port    = atmel_verify_port,
+       .pm             = atmel_serial_pm,
+       .ioctl          = atmel_ioctl,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char  = atmel_poll_get_char,
+       .poll_put_char  = atmel_poll_put_char,
+#endif
+};
+
+/*
+ * Configure the port from the platform device resource info.
+ */
+static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
+                                     struct platform_device *pdev)
+{
+       struct uart_port *port = &atmel_port->uart;
+       struct atmel_uart_data *data = pdev->dev.platform_data;
+
+       port->iotype            = UPIO_MEM;
+       port->flags             = UPF_BOOT_AUTOCONF;
+       port->ops               = &atmel_pops;
+       port->fifosize          = 1;
+       port->line              = pdev->id;
+       port->dev               = &pdev->dev;
+       port->mapbase   = pdev->resource[0].start;
+       port->irq       = pdev->resource[1].start;
+
+       tasklet_init(&atmel_port->tasklet, atmel_tasklet_func,
+                       (unsigned long)port);
+
+       memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
+
+       if (data->regs)
+               /* Already mapped by setup code */
+               port->membase = data->regs;
+       else {
+               port->flags     |= UPF_IOREMAP;
+               port->membase   = NULL;
+       }
+
+       /* for console, the clock could already be configured */
+       if (!atmel_port->clk) {
+               atmel_port->clk = clk_get(&pdev->dev, "usart");
+               clk_enable(atmel_port->clk);
+               port->uartclk = clk_get_rate(atmel_port->clk);
+               clk_disable(atmel_port->clk);
+               /* only enable clock when USART is in use */
+       }
+
+       atmel_port->use_dma_rx = data->use_dma_rx;
+       atmel_port->use_dma_tx = data->use_dma_tx;
+       atmel_port->rs485       = data->rs485;
+       /* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
+       if (atmel_port->rs485.flags & SER_RS485_ENABLED)
+               atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
+       else if (atmel_use_dma_tx(port)) {
+               port->fifosize = PDC_BUFFER_SIZE;
+               atmel_port->tx_done_mask = ATMEL_US_ENDTX | ATMEL_US_TXBUFE;
+       } else {
+               atmel_port->tx_done_mask = ATMEL_US_TXRDY;
+       }
+}
+
+/*
+ * Register board-specific modem-control line handlers.
+ */
+void __init atmel_register_uart_fns(struct atmel_port_fns *fns)
+{
+       if (fns->enable_ms)
+               atmel_pops.enable_ms = fns->enable_ms;
+       if (fns->get_mctrl)
+               atmel_pops.get_mctrl = fns->get_mctrl;
+       if (fns->set_mctrl)
+               atmel_pops.set_mctrl = fns->set_mctrl;
+       atmel_open_hook         = fns->open;
+       atmel_close_hook        = fns->close;
+       atmel_pops.pm           = fns->pm;
+       atmel_pops.set_wake     = fns->set_wake;
+}
+
+#ifdef CONFIG_SERIAL_ATMEL_CONSOLE
+static void atmel_console_putchar(struct uart_port *port, int ch)
+{
+       while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY))
+               cpu_relax();
+       UART_PUT_CHAR(port, ch);
+}
+
+/*
+ * Interrupts are disabled on entering
+ */
+static void atmel_console_write(struct console *co, const char *s, u_int count)
+{
+       struct uart_port *port = &atmel_ports[co->index].uart;
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       unsigned int status, imr;
+       unsigned int pdc_tx;
+
+       /*
+        * First, save IMR and then disable interrupts
+        */
+       imr = UART_GET_IMR(port);
+       UART_PUT_IDR(port, ATMEL_US_RXRDY | atmel_port->tx_done_mask);
+
+       /* Store PDC transmit status and disable it */
+       pdc_tx = UART_GET_PTSR(port) & ATMEL_PDC_TXTEN;
+       UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
+
+       uart_console_write(port, s, count, atmel_console_putchar);
+
+       /*
+        * Finally, wait for transmitter to become empty
+        * and restore IMR
+        */
+       do {
+               status = UART_GET_CSR(port);
+       } while (!(status & ATMEL_US_TXRDY));
+
+       /* Restore PDC transmit status */
+       if (pdc_tx)
+               UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
+
+       /* set interrupts back the way they were */
+       UART_PUT_IER(port, imr);
+}
+
+/*
+ * If the port was already initialised (eg, by a boot loader),
+ * try to determine the current setup.
+ */
+static void __init atmel_console_get_options(struct uart_port *port, int *baud,
+                                            int *parity, int *bits)
+{
+       unsigned int mr, quot;
+
+       /*
+        * If the baud rate generator isn't running, the port wasn't
+        * initialized by the boot loader.
+        */
+       quot = UART_GET_BRGR(port) & ATMEL_US_CD;
+       if (!quot)
+               return;
+
+       mr = UART_GET_MR(port) & ATMEL_US_CHRL;
+       if (mr == ATMEL_US_CHRL_8)
+               *bits = 8;
+       else
+               *bits = 7;
+
+       mr = UART_GET_MR(port) & ATMEL_US_PAR;
+       if (mr == ATMEL_US_PAR_EVEN)
+               *parity = 'e';
+       else if (mr == ATMEL_US_PAR_ODD)
+               *parity = 'o';
+
+       /*
+        * The serial core only rounds down when matching this to a
+        * supported baud rate. Make sure we don't end up slightly
+        * lower than one of those, as it would make us fall through
+        * to a much lower baud rate than we really want.
+        */
+       *baud = port->uartclk / (16 * (quot - 1));
+}
+
+static int __init atmel_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port = &atmel_ports[co->index].uart;
+       int baud = 115200;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (port->membase == NULL) {
+               /* Port not initialized yet - delay setup */
+               return -ENODEV;
+       }
+
+       clk_enable(atmel_ports[co->index].clk);
+
+       UART_PUT_IDR(port, -1);
+       UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
+       UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               atmel_console_get_options(port, &baud, &parity, &bits);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver atmel_uart;
+
+static struct console atmel_console = {
+       .name           = ATMEL_DEVICENAME,
+       .write          = atmel_console_write,
+       .device         = uart_console_device,
+       .setup          = atmel_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &atmel_uart,
+};
+
+#define ATMEL_CONSOLE_DEVICE   (&atmel_console)
+
+/*
+ * Early console initialization (before VM subsystem initialized).
+ */
+static int __init atmel_console_init(void)
+{
+       if (atmel_default_console_device) {
+               add_preferred_console(ATMEL_DEVICENAME,
+                                     atmel_default_console_device->id, NULL);
+               atmel_init_port(&atmel_ports[atmel_default_console_device->id],
+                               atmel_default_console_device);
+               register_console(&atmel_console);
+       }
+
+       return 0;
+}
+
+console_initcall(atmel_console_init);
+
+/*
+ * Late console initialization.
+ */
+static int __init atmel_late_console_init(void)
+{
+       if (atmel_default_console_device
+           && !(atmel_console.flags & CON_ENABLED))
+               register_console(&atmel_console);
+
+       return 0;
+}
+
+core_initcall(atmel_late_console_init);
+
+static inline bool atmel_is_console_port(struct uart_port *port)
+{
+       return port->cons && port->cons->index == port->line;
+}
+
+#else
+#define ATMEL_CONSOLE_DEVICE   NULL
+
+static inline bool atmel_is_console_port(struct uart_port *port)
+{
+       return false;
+}
+#endif
+
+static struct uart_driver atmel_uart = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "atmel_serial",
+       .dev_name       = ATMEL_DEVICENAME,
+       .major          = SERIAL_ATMEL_MAJOR,
+       .minor          = MINOR_START,
+       .nr             = ATMEL_MAX_UART,
+       .cons           = ATMEL_CONSOLE_DEVICE,
+};
+
+#ifdef CONFIG_PM
+static bool atmel_serial_clk_will_stop(void)
+{
+#ifdef CONFIG_ARCH_AT91
+       return at91_suspend_entering_slow_clock();
+#else
+       return false;
+#endif
+}
+
+static int atmel_serial_suspend(struct platform_device *pdev,
+                               pm_message_t state)
+{
+       struct uart_port *port = platform_get_drvdata(pdev);
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       if (atmel_is_console_port(port) && console_suspend_enabled) {
+               /* Drain the TX shifter */
+               while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY))
+                       cpu_relax();
+       }
+
+       /* we can not wake up if we're running on slow clock */
+       atmel_port->may_wakeup = device_may_wakeup(&pdev->dev);
+       if (atmel_serial_clk_will_stop())
+               device_set_wakeup_enable(&pdev->dev, 0);
+
+       uart_suspend_port(&atmel_uart, port);
+
+       return 0;
+}
+
+static int atmel_serial_resume(struct platform_device *pdev)
+{
+       struct uart_port *port = platform_get_drvdata(pdev);
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       uart_resume_port(&atmel_uart, port);
+       device_set_wakeup_enable(&pdev->dev, atmel_port->may_wakeup);
+
+       return 0;
+}
+#else
+#define atmel_serial_suspend NULL
+#define atmel_serial_resume NULL
+#endif
+
+static int __devinit atmel_serial_probe(struct platform_device *pdev)
+{
+       struct atmel_uart_port *port;
+       void *data;
+       int ret;
+
+       BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
+
+       port = &atmel_ports[pdev->id];
+       port->backup_imr = 0;
+
+       atmel_init_port(port, pdev);
+
+       if (!atmel_use_dma_rx(&port->uart)) {
+               ret = -ENOMEM;
+               data = kmalloc(sizeof(struct atmel_uart_char)
+                               * ATMEL_SERIAL_RINGSIZE, GFP_KERNEL);
+               if (!data)
+                       goto err_alloc_ring;
+               port->rx_ring.buf = data;
+       }
+
+       ret = uart_add_one_port(&atmel_uart, &port->uart);
+       if (ret)
+               goto err_add_port;
+
+#ifdef CONFIG_SERIAL_ATMEL_CONSOLE
+       if (atmel_is_console_port(&port->uart)
+                       && ATMEL_CONSOLE_DEVICE->flags & CON_ENABLED) {
+               /*
+                * The serial core enabled the clock for us, so undo
+                * the clk_enable() in atmel_console_setup()
+                */
+               clk_disable(port->clk);
+       }
+#endif
+
+       device_init_wakeup(&pdev->dev, 1);
+       platform_set_drvdata(pdev, port);
+
+       return 0;
+
+err_add_port:
+       kfree(port->rx_ring.buf);
+       port->rx_ring.buf = NULL;
+err_alloc_ring:
+       if (!atmel_is_console_port(&port->uart)) {
+               clk_put(port->clk);
+               port->clk = NULL;
+       }
+
+       return ret;
+}
+
+static int __devexit atmel_serial_remove(struct platform_device *pdev)
+{
+       struct uart_port *port = platform_get_drvdata(pdev);
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       int ret = 0;
+
+       device_init_wakeup(&pdev->dev, 0);
+       platform_set_drvdata(pdev, NULL);
+
+       ret = uart_remove_one_port(&atmel_uart, port);
+
+       tasklet_kill(&atmel_port->tasklet);
+       kfree(atmel_port->rx_ring.buf);
+
+       /* "port" is allocated statically, so we shouldn't free it */
+
+       clk_put(atmel_port->clk);
+
+       return ret;
+}
+
+static struct platform_driver atmel_serial_driver = {
+       .probe          = atmel_serial_probe,
+       .remove         = __devexit_p(atmel_serial_remove),
+       .suspend        = atmel_serial_suspend,
+       .resume         = atmel_serial_resume,
+       .driver         = {
+               .name   = "atmel_usart",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init atmel_serial_init(void)
+{
+       int ret;
+
+       ret = uart_register_driver(&atmel_uart);
+       if (ret)
+               return ret;
+
+       ret = platform_driver_register(&atmel_serial_driver);
+       if (ret)
+               uart_unregister_driver(&atmel_uart);
+
+       return ret;
+}
+
+static void __exit atmel_serial_exit(void)
+{
+       platform_driver_unregister(&atmel_serial_driver);
+       uart_unregister_driver(&atmel_uart);
+}
+
+module_init(atmel_serial_init);
+module_exit(atmel_serial_exit);
+
+MODULE_AUTHOR("Rick Bronson");
+MODULE_DESCRIPTION("Atmel AT91 / AT32 serial port driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:atmel_usart");
diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c
new file mode 100644 (file)
index 0000000..a1a0e55
--- /dev/null
@@ -0,0 +1,891 @@
+/*
+ * 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.
+ *
+ * Derived from many drivers using generic_serial interface.
+ *
+ * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ *
+ *  Serial driver for BCM63xx integrated UART.
+ *
+ * Hardware flow control was _not_ tested since I only have RX/TX on
+ * my board.
+ */
+
+#if defined(CONFIG_SERIAL_BCM63XX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/clk.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/sysrq.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+
+#include <bcm63xx_clk.h>
+#include <bcm63xx_irq.h>
+#include <bcm63xx_regs.h>
+#include <bcm63xx_io.h>
+
+#define BCM63XX_NR_UARTS       2
+
+static struct uart_port ports[BCM63XX_NR_UARTS];
+
+/*
+ * rx interrupt mask / stat
+ *
+ * mask:
+ *  - rx fifo full
+ *  - rx fifo above threshold
+ *  - rx fifo not empty for too long
+ */
+#define UART_RX_INT_MASK       (UART_IR_MASK(UART_IR_RXOVER) |         \
+                               UART_IR_MASK(UART_IR_RXTHRESH) |        \
+                               UART_IR_MASK(UART_IR_RXTIMEOUT))
+
+#define UART_RX_INT_STAT       (UART_IR_STAT(UART_IR_RXOVER) |         \
+                               UART_IR_STAT(UART_IR_RXTHRESH) |        \
+                               UART_IR_STAT(UART_IR_RXTIMEOUT))
+
+/*
+ * tx interrupt mask / stat
+ *
+ * mask:
+ * - tx fifo empty
+ * - tx fifo below threshold
+ */
+#define UART_TX_INT_MASK       (UART_IR_MASK(UART_IR_TXEMPTY) |        \
+                               UART_IR_MASK(UART_IR_TXTRESH))
+
+#define UART_TX_INT_STAT       (UART_IR_STAT(UART_IR_TXEMPTY) |        \
+                               UART_IR_STAT(UART_IR_TXTRESH))
+
+/*
+ * external input interrupt
+ *
+ * mask: any edge on CTS, DCD
+ */
+#define UART_EXTINP_INT_MASK   (UART_EXTINP_IRMASK(UART_EXTINP_IR_CTS) | \
+                                UART_EXTINP_IRMASK(UART_EXTINP_IR_DCD))
+
+/*
+ * handy uart register accessor
+ */
+static inline unsigned int bcm_uart_readl(struct uart_port *port,
+                                        unsigned int offset)
+{
+       return bcm_readl(port->membase + offset);
+}
+
+static inline void bcm_uart_writel(struct uart_port *port,
+                                 unsigned int value, unsigned int offset)
+{
+       bcm_writel(value, port->membase + offset);
+}
+
+/*
+ * serial core request to check if uart tx fifo is empty
+ */
+static unsigned int bcm_uart_tx_empty(struct uart_port *port)
+{
+       unsigned int val;
+
+       val = bcm_uart_readl(port, UART_IR_REG);
+       return (val & UART_IR_STAT(UART_IR_TXEMPTY)) ? 1 : 0;
+}
+
+/*
+ * serial core request to set RTS and DTR pin state and loopback mode
+ */
+static void bcm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       unsigned int val;
+
+       val = bcm_uart_readl(port, UART_MCTL_REG);
+       val &= ~(UART_MCTL_DTR_MASK | UART_MCTL_RTS_MASK);
+       /* invert of written value is reflected on the pin */
+       if (!(mctrl & TIOCM_DTR))
+               val |= UART_MCTL_DTR_MASK;
+       if (!(mctrl & TIOCM_RTS))
+               val |= UART_MCTL_RTS_MASK;
+       bcm_uart_writel(port, val, UART_MCTL_REG);
+
+       val = bcm_uart_readl(port, UART_CTL_REG);
+       if (mctrl & TIOCM_LOOP)
+               val |= UART_CTL_LOOPBACK_MASK;
+       else
+               val &= ~UART_CTL_LOOPBACK_MASK;
+       bcm_uart_writel(port, val, UART_CTL_REG);
+}
+
+/*
+ * serial core request to return RI, CTS, DCD and DSR pin state
+ */
+static unsigned int bcm_uart_get_mctrl(struct uart_port *port)
+{
+       unsigned int val, mctrl;
+
+       mctrl = 0;
+       val = bcm_uart_readl(port, UART_EXTINP_REG);
+       if (val & UART_EXTINP_RI_MASK)
+               mctrl |= TIOCM_RI;
+       if (val & UART_EXTINP_CTS_MASK)
+               mctrl |= TIOCM_CTS;
+       if (val & UART_EXTINP_DCD_MASK)
+               mctrl |= TIOCM_CD;
+       if (val & UART_EXTINP_DSR_MASK)
+               mctrl |= TIOCM_DSR;
+       return mctrl;
+}
+
+/*
+ * serial core request to disable tx ASAP (used for flow control)
+ */
+static void bcm_uart_stop_tx(struct uart_port *port)
+{
+       unsigned int val;
+
+       val = bcm_uart_readl(port, UART_CTL_REG);
+       val &= ~(UART_CTL_TXEN_MASK);
+       bcm_uart_writel(port, val, UART_CTL_REG);
+
+       val = bcm_uart_readl(port, UART_IR_REG);
+       val &= ~UART_TX_INT_MASK;
+       bcm_uart_writel(port, val, UART_IR_REG);
+}
+
+/*
+ * serial core request to (re)enable tx
+ */
+static void bcm_uart_start_tx(struct uart_port *port)
+{
+       unsigned int val;
+
+       val = bcm_uart_readl(port, UART_IR_REG);
+       val |= UART_TX_INT_MASK;
+       bcm_uart_writel(port, val, UART_IR_REG);
+
+       val = bcm_uart_readl(port, UART_CTL_REG);
+       val |= UART_CTL_TXEN_MASK;
+       bcm_uart_writel(port, val, UART_CTL_REG);
+}
+
+/*
+ * serial core request to stop rx, called before port shutdown
+ */
+static void bcm_uart_stop_rx(struct uart_port *port)
+{
+       unsigned int val;
+
+       val = bcm_uart_readl(port, UART_IR_REG);
+       val &= ~UART_RX_INT_MASK;
+       bcm_uart_writel(port, val, UART_IR_REG);
+}
+
+/*
+ * serial core request to enable modem status interrupt reporting
+ */
+static void bcm_uart_enable_ms(struct uart_port *port)
+{
+       unsigned int val;
+
+       val = bcm_uart_readl(port, UART_IR_REG);
+       val |= UART_IR_MASK(UART_IR_EXTIP);
+       bcm_uart_writel(port, val, UART_IR_REG);
+}
+
+/*
+ * serial core request to start/stop emitting break char
+ */
+static void bcm_uart_break_ctl(struct uart_port *port, int ctl)
+{
+       unsigned long flags;
+       unsigned int val;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       val = bcm_uart_readl(port, UART_CTL_REG);
+       if (ctl)
+               val |= UART_CTL_XMITBRK_MASK;
+       else
+               val &= ~UART_CTL_XMITBRK_MASK;
+       bcm_uart_writel(port, val, UART_CTL_REG);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/*
+ * return port type in string format
+ */
+static const char *bcm_uart_type(struct uart_port *port)
+{
+       return (port->type == PORT_BCM63XX) ? "bcm63xx_uart" : NULL;
+}
+
+/*
+ * read all chars in rx fifo and send them to core
+ */
+static void bcm_uart_do_rx(struct uart_port *port)
+{
+       struct tty_struct *tty;
+       unsigned int max_count;
+
+       /* limit number of char read in interrupt, should not be
+        * higher than fifo size anyway since we're much faster than
+        * serial port */
+       max_count = 32;
+       tty = port->state->port.tty;
+       do {
+               unsigned int iestat, c, cstat;
+               char flag;
+
+               /* get overrun/fifo empty information from ier
+                * register */
+               iestat = bcm_uart_readl(port, UART_IR_REG);
+               if (!(iestat & UART_IR_STAT(UART_IR_RXNOTEMPTY)))
+                       break;
+
+               cstat = c = bcm_uart_readl(port, UART_FIFO_REG);
+               port->icount.rx++;
+               flag = TTY_NORMAL;
+               c &= 0xff;
+
+               if (unlikely((cstat & UART_FIFO_ANYERR_MASK))) {
+                       /* do stats first */
+                       if (cstat & UART_FIFO_BRKDET_MASK) {
+                               port->icount.brk++;
+                               if (uart_handle_break(port))
+                                       continue;
+                       }
+
+                       if (cstat & UART_FIFO_PARERR_MASK)
+                               port->icount.parity++;
+                       if (cstat & UART_FIFO_FRAMEERR_MASK)
+                               port->icount.frame++;
+
+                       /* update flag wrt read_status_mask */
+                       cstat &= port->read_status_mask;
+                       if (cstat & UART_FIFO_BRKDET_MASK)
+                               flag = TTY_BREAK;
+                       if (cstat & UART_FIFO_FRAMEERR_MASK)
+                               flag = TTY_FRAME;
+                       if (cstat & UART_FIFO_PARERR_MASK)
+                               flag = TTY_PARITY;
+               }
+
+               if (uart_handle_sysrq_char(port, c))
+                       continue;
+
+               if (unlikely(iestat & UART_IR_STAT(UART_IR_RXOVER))) {
+                       port->icount.overrun++;
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+               }
+
+               if ((cstat & port->ignore_status_mask) == 0)
+                       tty_insert_flip_char(tty, c, flag);
+
+       } while (--max_count);
+
+       tty_flip_buffer_push(tty);
+}
+
+/*
+ * fill tx fifo with chars to send, stop when fifo is about to be full
+ * or when all chars have been sent.
+ */
+static void bcm_uart_do_tx(struct uart_port *port)
+{
+       struct circ_buf *xmit;
+       unsigned int val, max_count;
+
+       if (port->x_char) {
+               bcm_uart_writel(port, port->x_char, UART_FIFO_REG);
+               port->icount.tx++;
+               port->x_char = 0;
+               return;
+       }
+
+       if (uart_tx_stopped(port)) {
+               bcm_uart_stop_tx(port);
+               return;
+       }
+
+       xmit = &port->state->xmit;
+       if (uart_circ_empty(xmit))
+               goto txq_empty;
+
+       val = bcm_uart_readl(port, UART_MCTL_REG);
+       val = (val & UART_MCTL_TXFIFOFILL_MASK) >> UART_MCTL_TXFIFOFILL_SHIFT;
+       max_count = port->fifosize - val;
+
+       while (max_count--) {
+               unsigned int c;
+
+               c = xmit->buf[xmit->tail];
+               bcm_uart_writel(port, c, UART_FIFO_REG);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit))
+               goto txq_empty;
+       return;
+
+txq_empty:
+       /* nothing to send, disable transmit interrupt */
+       val = bcm_uart_readl(port, UART_IR_REG);
+       val &= ~UART_TX_INT_MASK;
+       bcm_uart_writel(port, val, UART_IR_REG);
+       return;
+}
+
+/*
+ * process uart interrupt
+ */
+static irqreturn_t bcm_uart_interrupt(int irq, void *dev_id)
+{
+       struct uart_port *port;
+       unsigned int irqstat;
+
+       port = dev_id;
+       spin_lock(&port->lock);
+
+       irqstat = bcm_uart_readl(port, UART_IR_REG);
+       if (irqstat & UART_RX_INT_STAT)
+               bcm_uart_do_rx(port);
+
+       if (irqstat & UART_TX_INT_STAT)
+               bcm_uart_do_tx(port);
+
+       if (irqstat & UART_IR_MASK(UART_IR_EXTIP)) {
+               unsigned int estat;
+
+               estat = bcm_uart_readl(port, UART_EXTINP_REG);
+               if (estat & UART_EXTINP_IRSTAT(UART_EXTINP_IR_CTS))
+                       uart_handle_cts_change(port,
+                                              estat & UART_EXTINP_CTS_MASK);
+               if (estat & UART_EXTINP_IRSTAT(UART_EXTINP_IR_DCD))
+                       uart_handle_dcd_change(port,
+                                              estat & UART_EXTINP_DCD_MASK);
+       }
+
+       spin_unlock(&port->lock);
+       return IRQ_HANDLED;
+}
+
+/*
+ * enable rx & tx operation on uart
+ */
+static void bcm_uart_enable(struct uart_port *port)
+{
+       unsigned int val;
+
+       val = bcm_uart_readl(port, UART_CTL_REG);
+       val |= (UART_CTL_BRGEN_MASK | UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK);
+       bcm_uart_writel(port, val, UART_CTL_REG);
+}
+
+/*
+ * disable rx & tx operation on uart
+ */
+static void bcm_uart_disable(struct uart_port *port)
+{
+       unsigned int val;
+
+       val = bcm_uart_readl(port, UART_CTL_REG);
+       val &= ~(UART_CTL_BRGEN_MASK | UART_CTL_TXEN_MASK |
+                UART_CTL_RXEN_MASK);
+       bcm_uart_writel(port, val, UART_CTL_REG);
+}
+
+/*
+ * clear all unread data in rx fifo and unsent data in tx fifo
+ */
+static void bcm_uart_flush(struct uart_port *port)
+{
+       unsigned int val;
+
+       /* empty rx and tx fifo */
+       val = bcm_uart_readl(port, UART_CTL_REG);
+       val |= UART_CTL_RSTRXFIFO_MASK | UART_CTL_RSTTXFIFO_MASK;
+       bcm_uart_writel(port, val, UART_CTL_REG);
+
+       /* read any pending char to make sure all irq status are
+        * cleared */
+       (void)bcm_uart_readl(port, UART_FIFO_REG);
+}
+
+/*
+ * serial core request to initialize uart and start rx operation
+ */
+static int bcm_uart_startup(struct uart_port *port)
+{
+       unsigned int val;
+       int ret;
+
+       /* mask all irq and flush port */
+       bcm_uart_disable(port);
+       bcm_uart_writel(port, 0, UART_IR_REG);
+       bcm_uart_flush(port);
+
+       /* clear any pending external input interrupt */
+       (void)bcm_uart_readl(port, UART_EXTINP_REG);
+
+       /* set rx/tx fifo thresh to fifo half size */
+       val = bcm_uart_readl(port, UART_MCTL_REG);
+       val &= ~(UART_MCTL_RXFIFOTHRESH_MASK | UART_MCTL_TXFIFOTHRESH_MASK);
+       val |= (port->fifosize / 2) << UART_MCTL_RXFIFOTHRESH_SHIFT;
+       val |= (port->fifosize / 2) << UART_MCTL_TXFIFOTHRESH_SHIFT;
+       bcm_uart_writel(port, val, UART_MCTL_REG);
+
+       /* set rx fifo timeout to 1 char time */
+       val = bcm_uart_readl(port, UART_CTL_REG);
+       val &= ~UART_CTL_RXTMOUTCNT_MASK;
+       val |= 1 << UART_CTL_RXTMOUTCNT_SHIFT;
+       bcm_uart_writel(port, val, UART_CTL_REG);
+
+       /* report any edge on dcd and cts */
+       val = UART_EXTINP_INT_MASK;
+       val |= UART_EXTINP_DCD_NOSENSE_MASK;
+       val |= UART_EXTINP_CTS_NOSENSE_MASK;
+       bcm_uart_writel(port, val, UART_EXTINP_REG);
+
+       /* register irq and enable rx interrupts */
+       ret = request_irq(port->irq, bcm_uart_interrupt, 0,
+                         bcm_uart_type(port), port);
+       if (ret)
+               return ret;
+       bcm_uart_writel(port, UART_RX_INT_MASK, UART_IR_REG);
+       bcm_uart_enable(port);
+       return 0;
+}
+
+/*
+ * serial core request to flush & disable uart
+ */
+static void bcm_uart_shutdown(struct uart_port *port)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       bcm_uart_writel(port, 0, UART_IR_REG);
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       bcm_uart_disable(port);
+       bcm_uart_flush(port);
+       free_irq(port->irq, port);
+}
+
+/*
+ * serial core request to change current uart setting
+ */
+static void bcm_uart_set_termios(struct uart_port *port,
+                                struct ktermios *new,
+                                struct ktermios *old)
+{
+       unsigned int ctl, baud, quot, ier;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* disable uart while changing speed */
+       bcm_uart_disable(port);
+       bcm_uart_flush(port);
+
+       /* update Control register */
+       ctl = bcm_uart_readl(port, UART_CTL_REG);
+       ctl &= ~UART_CTL_BITSPERSYM_MASK;
+
+       switch (new->c_cflag & CSIZE) {
+       case CS5:
+               ctl |= (0 << UART_CTL_BITSPERSYM_SHIFT);
+               break;
+       case CS6:
+               ctl |= (1 << UART_CTL_BITSPERSYM_SHIFT);
+               break;
+       case CS7:
+               ctl |= (2 << UART_CTL_BITSPERSYM_SHIFT);
+               break;
+       default:
+               ctl |= (3 << UART_CTL_BITSPERSYM_SHIFT);
+               break;
+       }
+
+       ctl &= ~UART_CTL_STOPBITS_MASK;
+       if (new->c_cflag & CSTOPB)
+               ctl |= UART_CTL_STOPBITS_2;
+       else
+               ctl |= UART_CTL_STOPBITS_1;
+
+       ctl &= ~(UART_CTL_RXPAREN_MASK | UART_CTL_TXPAREN_MASK);
+       if (new->c_cflag & PARENB)
+               ctl |= (UART_CTL_RXPAREN_MASK | UART_CTL_TXPAREN_MASK);
+       ctl &= ~(UART_CTL_RXPAREVEN_MASK | UART_CTL_TXPAREVEN_MASK);
+       if (new->c_cflag & PARODD)
+               ctl |= (UART_CTL_RXPAREVEN_MASK | UART_CTL_TXPAREVEN_MASK);
+       bcm_uart_writel(port, ctl, UART_CTL_REG);
+
+       /* update Baudword register */
+       baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
+       quot = uart_get_divisor(port, baud) - 1;
+       bcm_uart_writel(port, quot, UART_BAUD_REG);
+
+       /* update Interrupt register */
+       ier = bcm_uart_readl(port, UART_IR_REG);
+
+       ier &= ~UART_IR_MASK(UART_IR_EXTIP);
+       if (UART_ENABLE_MS(port, new->c_cflag))
+               ier |= UART_IR_MASK(UART_IR_EXTIP);
+
+       bcm_uart_writel(port, ier, UART_IR_REG);
+
+       /* update read/ignore mask */
+       port->read_status_mask = UART_FIFO_VALID_MASK;
+       if (new->c_iflag & INPCK) {
+               port->read_status_mask |= UART_FIFO_FRAMEERR_MASK;
+               port->read_status_mask |= UART_FIFO_PARERR_MASK;
+       }
+       if (new->c_iflag & (BRKINT))
+               port->read_status_mask |= UART_FIFO_BRKDET_MASK;
+
+       port->ignore_status_mask = 0;
+       if (new->c_iflag & IGNPAR)
+               port->ignore_status_mask |= UART_FIFO_PARERR_MASK;
+       if (new->c_iflag & IGNBRK)
+               port->ignore_status_mask |= UART_FIFO_BRKDET_MASK;
+       if (!(new->c_cflag & CREAD))
+               port->ignore_status_mask |= UART_FIFO_VALID_MASK;
+
+       uart_update_timeout(port, new->c_cflag, baud);
+       bcm_uart_enable(port);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/*
+ * serial core request to claim uart iomem
+ */
+static int bcm_uart_request_port(struct uart_port *port)
+{
+       unsigned int size;
+
+       size = RSET_UART_SIZE;
+       if (!request_mem_region(port->mapbase, size, "bcm63xx")) {
+               dev_err(port->dev, "Memory region busy\n");
+               return -EBUSY;
+       }
+
+       port->membase = ioremap(port->mapbase, size);
+       if (!port->membase) {
+               dev_err(port->dev, "Unable to map registers\n");
+               release_mem_region(port->mapbase, size);
+               return -EBUSY;
+       }
+       return 0;
+}
+
+/*
+ * serial core request to release uart iomem
+ */
+static void bcm_uart_release_port(struct uart_port *port)
+{
+       release_mem_region(port->mapbase, RSET_UART_SIZE);
+       iounmap(port->membase);
+}
+
+/*
+ * serial core request to do any port required autoconfiguration
+ */
+static void bcm_uart_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               if (bcm_uart_request_port(port))
+                       return;
+               port->type = PORT_BCM63XX;
+       }
+}
+
+/*
+ * serial core request to check that port information in serinfo are
+ * suitable
+ */
+static int bcm_uart_verify_port(struct uart_port *port,
+                               struct serial_struct *serinfo)
+{
+       if (port->type != PORT_BCM63XX)
+               return -EINVAL;
+       if (port->irq != serinfo->irq)
+               return -EINVAL;
+       if (port->iotype != serinfo->io_type)
+               return -EINVAL;
+       if (port->mapbase != (unsigned long)serinfo->iomem_base)
+               return -EINVAL;
+       return 0;
+}
+
+/* serial core callbacks */
+static struct uart_ops bcm_uart_ops = {
+       .tx_empty       = bcm_uart_tx_empty,
+       .get_mctrl      = bcm_uart_get_mctrl,
+       .set_mctrl      = bcm_uart_set_mctrl,
+       .start_tx       = bcm_uart_start_tx,
+       .stop_tx        = bcm_uart_stop_tx,
+       .stop_rx        = bcm_uart_stop_rx,
+       .enable_ms      = bcm_uart_enable_ms,
+       .break_ctl      = bcm_uart_break_ctl,
+       .startup        = bcm_uart_startup,
+       .shutdown       = bcm_uart_shutdown,
+       .set_termios    = bcm_uart_set_termios,
+       .type           = bcm_uart_type,
+       .release_port   = bcm_uart_release_port,
+       .request_port   = bcm_uart_request_port,
+       .config_port    = bcm_uart_config_port,
+       .verify_port    = bcm_uart_verify_port,
+};
+
+
+
+#ifdef CONFIG_SERIAL_BCM63XX_CONSOLE
+static inline void wait_for_xmitr(struct uart_port *port)
+{
+       unsigned int tmout;
+
+       /* Wait up to 10ms for the character(s) to be sent. */
+       tmout = 10000;
+       while (--tmout) {
+               unsigned int val;
+
+               val = bcm_uart_readl(port, UART_IR_REG);
+               if (val & UART_IR_STAT(UART_IR_TXEMPTY))
+                       break;
+               udelay(1);
+       }
+
+       /* Wait up to 1s for flow control if necessary */
+       if (port->flags & UPF_CONS_FLOW) {
+               tmout = 1000000;
+               while (--tmout) {
+                       unsigned int val;
+
+                       val = bcm_uart_readl(port, UART_EXTINP_REG);
+                       if (val & UART_EXTINP_CTS_MASK)
+                               break;
+                       udelay(1);
+               }
+       }
+}
+
+/*
+ * output given char
+ */
+static void bcm_console_putchar(struct uart_port *port, int ch)
+{
+       wait_for_xmitr(port);
+       bcm_uart_writel(port, ch, UART_FIFO_REG);
+}
+
+/*
+ * console core request to output given string
+ */
+static void bcm_console_write(struct console *co, const char *s,
+                             unsigned int count)
+{
+       struct uart_port *port;
+       unsigned long flags;
+       int locked;
+
+       port = &ports[co->index];
+
+       local_irq_save(flags);
+       if (port->sysrq) {
+               /* bcm_uart_interrupt() already took the lock */
+               locked = 0;
+       } else if (oops_in_progress) {
+               locked = spin_trylock(&port->lock);
+       } else {
+               spin_lock(&port->lock);
+               locked = 1;
+       }
+
+       /* call helper to deal with \r\n */
+       uart_console_write(port, s, count, bcm_console_putchar);
+
+       /* and wait for char to be transmitted */
+       wait_for_xmitr(port);
+
+       if (locked)
+               spin_unlock(&port->lock);
+       local_irq_restore(flags);
+}
+
+/*
+ * console core request to setup given console, find matching uart
+ * port and setup it.
+ */
+static int bcm_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (co->index < 0 || co->index >= BCM63XX_NR_UARTS)
+               return -EINVAL;
+       port = &ports[co->index];
+       if (!port->membase)
+               return -ENODEV;
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver bcm_uart_driver;
+
+static struct console bcm63xx_console = {
+       .name           = "ttyS",
+       .write          = bcm_console_write,
+       .device         = uart_console_device,
+       .setup          = bcm_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &bcm_uart_driver,
+};
+
+static int __init bcm63xx_console_init(void)
+{
+       register_console(&bcm63xx_console);
+       return 0;
+}
+
+console_initcall(bcm63xx_console_init);
+
+#define BCM63XX_CONSOLE        (&bcm63xx_console)
+#else
+#define BCM63XX_CONSOLE        NULL
+#endif /* CONFIG_SERIAL_BCM63XX_CONSOLE */
+
+static struct uart_driver bcm_uart_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "bcm63xx_uart",
+       .dev_name       = "ttyS",
+       .major          = TTY_MAJOR,
+       .minor          = 64,
+       .nr             = BCM63XX_NR_UARTS,
+       .cons           = BCM63XX_CONSOLE,
+};
+
+/*
+ * platform driver probe/remove callback
+ */
+static int __devinit bcm_uart_probe(struct platform_device *pdev)
+{
+       struct resource *res_mem, *res_irq;
+       struct uart_port *port;
+       struct clk *clk;
+       int ret;
+
+       if (pdev->id < 0 || pdev->id >= BCM63XX_NR_UARTS)
+               return -EINVAL;
+
+       if (ports[pdev->id].membase)
+               return -EBUSY;
+
+       res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res_mem)
+               return -ENODEV;
+
+       res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res_irq)
+               return -ENODEV;
+
+       clk = clk_get(&pdev->dev, "periph");
+       if (IS_ERR(clk))
+               return -ENODEV;
+
+       port = &ports[pdev->id];
+       memset(port, 0, sizeof(*port));
+       port->iotype = UPIO_MEM;
+       port->mapbase = res_mem->start;
+       port->irq = res_irq->start;
+       port->ops = &bcm_uart_ops;
+       port->flags = UPF_BOOT_AUTOCONF;
+       port->dev = &pdev->dev;
+       port->fifosize = 16;
+       port->uartclk = clk_get_rate(clk) / 2;
+       port->line = pdev->id;
+       clk_put(clk);
+
+       ret = uart_add_one_port(&bcm_uart_driver, port);
+       if (ret) {
+               ports[pdev->id].membase = 0;
+               return ret;
+       }
+       platform_set_drvdata(pdev, port);
+       return 0;
+}
+
+static int __devexit bcm_uart_remove(struct platform_device *pdev)
+{
+       struct uart_port *port;
+
+       port = platform_get_drvdata(pdev);
+       uart_remove_one_port(&bcm_uart_driver, port);
+       platform_set_drvdata(pdev, NULL);
+       /* mark port as free */
+       ports[pdev->id].membase = 0;
+       return 0;
+}
+
+/*
+ * platform driver stuff
+ */
+static struct platform_driver bcm_uart_platform_driver = {
+       .probe  = bcm_uart_probe,
+       .remove = __devexit_p(bcm_uart_remove),
+       .driver = {
+               .owner = THIS_MODULE,
+               .name  = "bcm63xx_uart",
+       },
+};
+
+static int __init bcm_uart_init(void)
+{
+       int ret;
+
+       ret = uart_register_driver(&bcm_uart_driver);
+       if (ret)
+               return ret;
+
+       ret = platform_driver_register(&bcm_uart_platform_driver);
+       if (ret)
+               uart_unregister_driver(&bcm_uart_driver);
+
+       return ret;
+}
+
+static void __exit bcm_uart_exit(void)
+{
+       platform_driver_unregister(&bcm_uart_platform_driver);
+       uart_unregister_driver(&bcm_uart_driver);
+}
+
+module_init(bcm_uart_init);
+module_exit(bcm_uart_exit);
+
+MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>");
+MODULE_DESCRIPTION("Broadcom 63<xx integrated uart driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/bfin_5xx.c b/drivers/tty/serial/bfin_5xx.c
new file mode 100644 (file)
index 0000000..e381b89
--- /dev/null
@@ -0,0 +1,1600 @@
+/*
+ * Blackfin On-Chip Serial Driver
+ *
+ * Copyright 2006-2010 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#define DRIVER_NAME "bfin-uart"
+#define pr_fmt(fmt) DRIVER_NAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/gfp.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/kgdb.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/portmux.h>
+#include <asm/cacheflush.h>
+#include <asm/dma.h>
+
+#define port_membase(uart)     (((struct bfin_serial_port *)(uart))->port.membase)
+#define get_lsr_cache(uart)    (((struct bfin_serial_port *)(uart))->lsr)
+#define put_lsr_cache(uart, v) (((struct bfin_serial_port *)(uart))->lsr = (v))
+#include <asm/bfin_serial.h>
+
+#ifdef CONFIG_SERIAL_BFIN_MODULE
+# undef CONFIG_EARLY_PRINTK
+#endif
+
+#ifdef CONFIG_SERIAL_BFIN_MODULE
+# undef CONFIG_EARLY_PRINTK
+#endif
+
+/* UART name and device definitions */
+#define BFIN_SERIAL_DEV_NAME   "ttyBF"
+#define BFIN_SERIAL_MAJOR      204
+#define BFIN_SERIAL_MINOR      64
+
+static struct bfin_serial_port *bfin_serial_ports[BFIN_UART_NR_PORTS];
+
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+
+# ifndef CONFIG_SERIAL_BFIN_PIO
+#  error KGDB only support UART in PIO mode.
+# endif
+
+static int kgdboc_port_line;
+static int kgdboc_break_enabled;
+#endif
+/*
+ * Setup for console. Argument comes from the menuconfig
+ */
+#define DMA_RX_XCOUNT          512
+#define DMA_RX_YCOUNT          (PAGE_SIZE / DMA_RX_XCOUNT)
+
+#define DMA_RX_FLUSH_JIFFIES   (HZ / 50)
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart);
+#else
+static void bfin_serial_tx_chars(struct bfin_serial_port *uart);
+#endif
+
+static void bfin_serial_reset_irda(struct uart_port *port);
+
+#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
+       defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
+static unsigned int bfin_serial_get_mctrl(struct uart_port *port)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       if (uart->cts_pin < 0)
+               return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+
+       /* CTS PIN is negative assertive. */
+       if (UART_GET_CTS(uart))
+               return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+       else
+               return TIOCM_DSR | TIOCM_CAR;
+}
+
+static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       if (uart->rts_pin < 0)
+               return;
+
+       /* RTS PIN is negative assertive. */
+       if (mctrl & TIOCM_RTS)
+               UART_ENABLE_RTS(uart);
+       else
+               UART_DISABLE_RTS(uart);
+}
+
+/*
+ * Handle any change of modem status signal.
+ */
+static irqreturn_t bfin_serial_mctrl_cts_int(int irq, void *dev_id)
+{
+       struct bfin_serial_port *uart = dev_id;
+       unsigned int status;
+
+       status = bfin_serial_get_mctrl(&uart->port);
+       uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
+#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
+       uart->scts = 1;
+       UART_CLEAR_SCTS(uart);
+       UART_CLEAR_IER(uart, EDSSI);
+#endif
+
+       return IRQ_HANDLED;
+}
+#else
+static unsigned int bfin_serial_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+#endif
+
+/*
+ * interrupts are disabled on entry
+ */
+static void bfin_serial_stop_tx(struct uart_port *port)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+#ifdef CONFIG_SERIAL_BFIN_DMA
+       struct circ_buf *xmit = &uart->port.state->xmit;
+#endif
+
+       while (!(UART_GET_LSR(uart) & TEMT))
+               cpu_relax();
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+       disable_dma(uart->tx_dma_channel);
+       xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
+       uart->port.icount.tx += uart->tx_count;
+       uart->tx_count = 0;
+       uart->tx_done = 1;
+#else
+#ifdef CONFIG_BF54x
+       /* Clear TFI bit */
+       UART_PUT_LSR(uart, TFI);
+#endif
+       UART_CLEAR_IER(uart, ETBEI);
+#endif
+}
+
+/*
+ * port is locked and interrupts are disabled
+ */
+static void bfin_serial_start_tx(struct uart_port *port)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       struct tty_struct *tty = uart->port.state->port.tty;
+
+#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
+       if (uart->scts && !(bfin_serial_get_mctrl(&uart->port) & TIOCM_CTS)) {
+               uart->scts = 0;
+               uart_handle_cts_change(&uart->port, uart->scts);
+       }
+#endif
+
+       /*
+        * To avoid losting RX interrupt, we reset IR function
+        * before sending data.
+        */
+       if (tty->termios->c_line == N_IRDA)
+               bfin_serial_reset_irda(port);
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+       if (uart->tx_done)
+               bfin_serial_dma_tx_chars(uart);
+#else
+       UART_SET_IER(uart, ETBEI);
+       bfin_serial_tx_chars(uart);
+#endif
+}
+
+/*
+ * Interrupts are enabled
+ */
+static void bfin_serial_stop_rx(struct uart_port *port)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+       UART_CLEAR_IER(uart, ERBFI);
+}
+
+/*
+ * Set the modem control timer to fire immediately.
+ */
+static void bfin_serial_enable_ms(struct uart_port *port)
+{
+}
+
+
+#if ANOMALY_05000363 && defined(CONFIG_SERIAL_BFIN_PIO)
+# define UART_GET_ANOMALY_THRESHOLD(uart)    ((uart)->anomaly_threshold)
+# define UART_SET_ANOMALY_THRESHOLD(uart, v) ((uart)->anomaly_threshold = (v))
+#else
+# define UART_GET_ANOMALY_THRESHOLD(uart)    0
+# define UART_SET_ANOMALY_THRESHOLD(uart, v)
+#endif
+
+#ifdef CONFIG_SERIAL_BFIN_PIO
+static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
+{
+       struct tty_struct *tty = NULL;
+       unsigned int status, ch, flg;
+       static struct timeval anomaly_start = { .tv_sec = 0 };
+
+       status = UART_GET_LSR(uart);
+       UART_CLEAR_LSR(uart);
+
+       ch = UART_GET_CHAR(uart);
+       uart->port.icount.rx++;
+
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+       if (kgdb_connected && kgdboc_port_line == uart->port.line
+               && kgdboc_break_enabled)
+               if (ch == 0x3) {/* Ctrl + C */
+                       kgdb_breakpoint();
+                       return;
+               }
+
+       if (!uart->port.state || !uart->port.state->port.tty)
+               return;
+#endif
+       tty = uart->port.state->port.tty;
+
+       if (ANOMALY_05000363) {
+               /* The BF533 (and BF561) family of processors have a nice anomaly
+                * where they continuously generate characters for a "single" break.
+                * We have to basically ignore this flood until the "next" valid
+                * character comes across.  Due to the nature of the flood, it is
+                * not possible to reliably catch bytes that are sent too quickly
+                * after this break.  So application code talking to the Blackfin
+                * which sends a break signal must allow at least 1.5 character
+                * times after the end of the break for things to stabilize.  This
+                * timeout was picked as it must absolutely be larger than 1
+                * character time +/- some percent.  So 1.5 sounds good.  All other
+                * Blackfin families operate properly.  Woo.
+                */
+               if (anomaly_start.tv_sec) {
+                       struct timeval curr;
+                       suseconds_t usecs;
+
+                       if ((~ch & (~ch + 1)) & 0xff)
+                               goto known_good_char;
+
+                       do_gettimeofday(&curr);
+                       if (curr.tv_sec - anomaly_start.tv_sec > 1)
+                               goto known_good_char;
+
+                       usecs = 0;
+                       if (curr.tv_sec != anomaly_start.tv_sec)
+                               usecs += USEC_PER_SEC;
+                       usecs += curr.tv_usec - anomaly_start.tv_usec;
+
+                       if (usecs > UART_GET_ANOMALY_THRESHOLD(uart))
+                               goto known_good_char;
+
+                       if (ch)
+                               anomaly_start.tv_sec = 0;
+                       else
+                               anomaly_start = curr;
+
+                       return;
+
+ known_good_char:
+                       status &= ~BI;
+                       anomaly_start.tv_sec = 0;
+               }
+       }
+
+       if (status & BI) {
+               if (ANOMALY_05000363)
+                       if (bfin_revid() < 5)
+                               do_gettimeofday(&anomaly_start);
+               uart->port.icount.brk++;
+               if (uart_handle_break(&uart->port))
+                       goto ignore_char;
+               status &= ~(PE | FE);
+       }
+       if (status & PE)
+               uart->port.icount.parity++;
+       if (status & OE)
+               uart->port.icount.overrun++;
+       if (status & FE)
+               uart->port.icount.frame++;
+
+       status &= uart->port.read_status_mask;
+
+       if (status & BI)
+               flg = TTY_BREAK;
+       else if (status & PE)
+               flg = TTY_PARITY;
+       else if (status & FE)
+               flg = TTY_FRAME;
+       else
+               flg = TTY_NORMAL;
+
+       if (uart_handle_sysrq_char(&uart->port, ch))
+               goto ignore_char;
+
+       uart_insert_char(&uart->port, status, OE, ch, flg);
+
+ ignore_char:
+       tty_flip_buffer_push(tty);
+}
+
+static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
+{
+       struct circ_buf *xmit = &uart->port.state->xmit;
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
+#ifdef CONFIG_BF54x
+               /* Clear TFI bit */
+               UART_PUT_LSR(uart, TFI);
+#endif
+               /* Anomaly notes:
+                *  05000215 -  we always clear ETBEI within last UART TX
+                *              interrupt to end a string. It is always set
+                *              when start a new tx.
+                */
+               UART_CLEAR_IER(uart, ETBEI);
+               return;
+       }
+
+       if (uart->port.x_char) {
+               UART_PUT_CHAR(uart, uart->port.x_char);
+               uart->port.icount.tx++;
+               uart->port.x_char = 0;
+       }
+
+       while ((UART_GET_LSR(uart) & THRE) && xmit->tail != xmit->head) {
+               UART_PUT_CHAR(uart, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               uart->port.icount.tx++;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&uart->port);
+}
+
+static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id)
+{
+       struct bfin_serial_port *uart = dev_id;
+
+       spin_lock(&uart->port.lock);
+       while (UART_GET_LSR(uart) & DR)
+               bfin_serial_rx_chars(uart);
+       spin_unlock(&uart->port.lock);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id)
+{
+       struct bfin_serial_port *uart = dev_id;
+
+#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
+       if (uart->scts && !(bfin_serial_get_mctrl(&uart->port) & TIOCM_CTS)) {
+               uart->scts = 0;
+               uart_handle_cts_change(&uart->port, uart->scts);
+       }
+#endif
+       spin_lock(&uart->port.lock);
+       if (UART_GET_LSR(uart) & THRE)
+               bfin_serial_tx_chars(uart);
+       spin_unlock(&uart->port.lock);
+
+       return IRQ_HANDLED;
+}
+#endif
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
+{
+       struct circ_buf *xmit = &uart->port.state->xmit;
+
+       uart->tx_done = 0;
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
+               uart->tx_count = 0;
+               uart->tx_done = 1;
+               return;
+       }
+
+       if (uart->port.x_char) {
+               UART_PUT_CHAR(uart, uart->port.x_char);
+               uart->port.icount.tx++;
+               uart->port.x_char = 0;
+       }
+
+       uart->tx_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);
+       if (uart->tx_count > (UART_XMIT_SIZE - xmit->tail))
+               uart->tx_count = UART_XMIT_SIZE - xmit->tail;
+       blackfin_dcache_flush_range((unsigned long)(xmit->buf+xmit->tail),
+                                       (unsigned long)(xmit->buf+xmit->tail+uart->tx_count));
+       set_dma_config(uart->tx_dma_channel,
+               set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP,
+                       INTR_ON_BUF,
+                       DIMENSION_LINEAR,
+                       DATA_SIZE_8,
+                       DMA_SYNC_RESTART));
+       set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail));
+       set_dma_x_count(uart->tx_dma_channel, uart->tx_count);
+       set_dma_x_modify(uart->tx_dma_channel, 1);
+       SSYNC();
+       enable_dma(uart->tx_dma_channel);
+
+       UART_SET_IER(uart, ETBEI);
+}
+
+static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
+{
+       struct tty_struct *tty = uart->port.state->port.tty;
+       int i, flg, status;
+
+       status = UART_GET_LSR(uart);
+       UART_CLEAR_LSR(uart);
+
+       uart->port.icount.rx +=
+               CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail,
+               UART_XMIT_SIZE);
+
+       if (status & BI) {
+               uart->port.icount.brk++;
+               if (uart_handle_break(&uart->port))
+                       goto dma_ignore_char;
+               status &= ~(PE | FE);
+       }
+       if (status & PE)
+               uart->port.icount.parity++;
+       if (status & OE)
+               uart->port.icount.overrun++;
+       if (status & FE)
+               uart->port.icount.frame++;
+
+       status &= uart->port.read_status_mask;
+
+       if (status & BI)
+               flg = TTY_BREAK;
+       else if (status & PE)
+               flg = TTY_PARITY;
+       else if (status & FE)
+               flg = TTY_FRAME;
+       else
+               flg = TTY_NORMAL;
+
+       for (i = uart->rx_dma_buf.tail; ; i++) {
+               if (i >= UART_XMIT_SIZE)
+                       i = 0;
+               if (i == uart->rx_dma_buf.head)
+                       break;
+               if (!uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i]))
+                       uart_insert_char(&uart->port, status, OE,
+                               uart->rx_dma_buf.buf[i], flg);
+       }
+
+ dma_ignore_char:
+       tty_flip_buffer_push(tty);
+}
+
+void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
+{
+       int x_pos, pos;
+
+       dma_disable_irq(uart->tx_dma_channel);
+       dma_disable_irq(uart->rx_dma_channel);
+       spin_lock_bh(&uart->port.lock);
+
+       /* 2D DMA RX buffer ring is used. Because curr_y_count and
+        * curr_x_count can't be read as an atomic operation,
+        * curr_y_count should be read before curr_x_count. When
+        * curr_x_count is read, curr_y_count may already indicate
+        * next buffer line. But, the position calculated here is
+        * still indicate the old line. The wrong position data may
+        * be smaller than current buffer tail, which cause garbages
+        * are received if it is not prohibit.
+        */
+       uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel);
+       x_pos = get_dma_curr_xcount(uart->rx_dma_channel);
+       uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows;
+       if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0)
+               uart->rx_dma_nrows = 0;
+       x_pos = DMA_RX_XCOUNT - x_pos;
+       if (x_pos == DMA_RX_XCOUNT)
+               x_pos = 0;
+
+       pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos;
+       /* Ignore receiving data if new position is in the same line of
+        * current buffer tail and small.
+        */
+       if (pos > uart->rx_dma_buf.tail ||
+               uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) {
+               uart->rx_dma_buf.head = pos;
+               bfin_serial_dma_rx_chars(uart);
+               uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
+       }
+
+       spin_unlock_bh(&uart->port.lock);
+       dma_enable_irq(uart->tx_dma_channel);
+       dma_enable_irq(uart->rx_dma_channel);
+
+       mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES);
+}
+
+static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
+{
+       struct bfin_serial_port *uart = dev_id;
+       struct circ_buf *xmit = &uart->port.state->xmit;
+
+#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
+       if (uart->scts && !(bfin_serial_get_mctrl(&uart->port)&TIOCM_CTS)) {
+               uart->scts = 0;
+               uart_handle_cts_change(&uart->port, uart->scts);
+       }
+#endif
+
+       spin_lock(&uart->port.lock);
+       if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) {
+               disable_dma(uart->tx_dma_channel);
+               clear_dma_irqstat(uart->tx_dma_channel);
+               /* Anomaly notes:
+                *  05000215 -  we always clear ETBEI within last UART TX
+                *              interrupt to end a string. It is always set
+                *              when start a new tx.
+                */
+               UART_CLEAR_IER(uart, ETBEI);
+               xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
+               uart->port.icount.tx += uart->tx_count;
+
+               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+                       uart_write_wakeup(&uart->port);
+
+               bfin_serial_dma_tx_chars(uart);
+       }
+
+       spin_unlock(&uart->port.lock);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
+{
+       struct bfin_serial_port *uart = dev_id;
+       unsigned short irqstat;
+       int x_pos, pos;
+
+       spin_lock(&uart->port.lock);
+       irqstat = get_dma_curr_irqstat(uart->rx_dma_channel);
+       clear_dma_irqstat(uart->rx_dma_channel);
+
+       uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel);
+       x_pos = get_dma_curr_xcount(uart->rx_dma_channel);
+       uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows;
+       if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0)
+               uart->rx_dma_nrows = 0;
+
+       pos = uart->rx_dma_nrows * DMA_RX_XCOUNT;
+       if (pos > uart->rx_dma_buf.tail ||
+               uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) {
+               uart->rx_dma_buf.head = pos;
+               bfin_serial_dma_rx_chars(uart);
+               uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
+       }
+
+       spin_unlock(&uart->port.lock);
+
+       return IRQ_HANDLED;
+}
+#endif
+
+/*
+ * Return TIOCSER_TEMT when transmitter is not busy.
+ */
+static unsigned int bfin_serial_tx_empty(struct uart_port *port)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       unsigned short lsr;
+
+       lsr = UART_GET_LSR(uart);
+       if (lsr & TEMT)
+               return TIOCSER_TEMT;
+       else
+               return 0;
+}
+
+static void bfin_serial_break_ctl(struct uart_port *port, int break_state)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       u16 lcr = UART_GET_LCR(uart);
+       if (break_state)
+               lcr |= SB;
+       else
+               lcr &= ~SB;
+       UART_PUT_LCR(uart, lcr);
+       SSYNC();
+}
+
+static int bfin_serial_startup(struct uart_port *port)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+       dma_addr_t dma_handle;
+
+       if (request_dma(uart->rx_dma_channel, "BFIN_UART_RX") < 0) {
+               printk(KERN_NOTICE "Unable to attach Blackfin UART RX DMA channel\n");
+               return -EBUSY;
+       }
+
+       if (request_dma(uart->tx_dma_channel, "BFIN_UART_TX") < 0) {
+               printk(KERN_NOTICE "Unable to attach Blackfin UART TX DMA channel\n");
+               free_dma(uart->rx_dma_channel);
+               return -EBUSY;
+       }
+
+       set_dma_callback(uart->rx_dma_channel, bfin_serial_dma_rx_int, uart);
+       set_dma_callback(uart->tx_dma_channel, bfin_serial_dma_tx_int, uart);
+
+       uart->rx_dma_buf.buf = (unsigned char *)dma_alloc_coherent(NULL, PAGE_SIZE, &dma_handle, GFP_DMA);
+       uart->rx_dma_buf.head = 0;
+       uart->rx_dma_buf.tail = 0;
+       uart->rx_dma_nrows = 0;
+
+       set_dma_config(uart->rx_dma_channel,
+               set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO,
+                               INTR_ON_ROW, DIMENSION_2D,
+                               DATA_SIZE_8,
+                               DMA_SYNC_RESTART));
+       set_dma_x_count(uart->rx_dma_channel, DMA_RX_XCOUNT);
+       set_dma_x_modify(uart->rx_dma_channel, 1);
+       set_dma_y_count(uart->rx_dma_channel, DMA_RX_YCOUNT);
+       set_dma_y_modify(uart->rx_dma_channel, 1);
+       set_dma_start_addr(uart->rx_dma_channel, (unsigned long)uart->rx_dma_buf.buf);
+       enable_dma(uart->rx_dma_channel);
+
+       uart->rx_dma_timer.data = (unsigned long)(uart);
+       uart->rx_dma_timer.function = (void *)bfin_serial_rx_dma_timeout;
+       uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES;
+       add_timer(&(uart->rx_dma_timer));
+#else
+# if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+       if (kgdboc_port_line == uart->port.line && kgdboc_break_enabled)
+               kgdboc_break_enabled = 0;
+       else {
+# endif
+       if (request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED,
+            "BFIN_UART_RX", uart)) {
+               printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n");
+               return -EBUSY;
+       }
+
+       if (request_irq
+           (uart->port.irq+1, bfin_serial_tx_int, IRQF_DISABLED,
+            "BFIN_UART_TX", uart)) {
+               printk(KERN_NOTICE "Unable to attach BlackFin UART TX interrupt\n");
+               free_irq(uart->port.irq, uart);
+               return -EBUSY;
+       }
+
+# ifdef CONFIG_BF54x
+       {
+               /*
+                * UART2 and UART3 on BF548 share interrupt PINs and DMA
+                * controllers with SPORT2 and SPORT3. UART rx and tx
+                * interrupts are generated in PIO mode only when configure
+                * their peripheral mapping registers properly, which means
+                * request corresponding DMA channels in PIO mode as well.
+                */
+               unsigned uart_dma_ch_rx, uart_dma_ch_tx;
+
+               switch (uart->port.irq) {
+               case IRQ_UART3_RX:
+                       uart_dma_ch_rx = CH_UART3_RX;
+                       uart_dma_ch_tx = CH_UART3_TX;
+                       break;
+               case IRQ_UART2_RX:
+                       uart_dma_ch_rx = CH_UART2_RX;
+                       uart_dma_ch_tx = CH_UART2_TX;
+                       break;
+               default:
+                       uart_dma_ch_rx = uart_dma_ch_tx = 0;
+                       break;
+               };
+
+               if (uart_dma_ch_rx &&
+                       request_dma(uart_dma_ch_rx, "BFIN_UART_RX") < 0) {
+                       printk(KERN_NOTICE"Fail to attach UART interrupt\n");
+                       free_irq(uart->port.irq, uart);
+                       free_irq(uart->port.irq + 1, uart);
+                       return -EBUSY;
+               }
+               if (uart_dma_ch_tx &&
+                       request_dma(uart_dma_ch_tx, "BFIN_UART_TX") < 0) {
+                       printk(KERN_NOTICE "Fail to attach UART interrupt\n");
+                       free_dma(uart_dma_ch_rx);
+                       free_irq(uart->port.irq, uart);
+                       free_irq(uart->port.irq + 1, uart);
+                       return -EBUSY;
+               }
+       }
+# endif
+# if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+       }
+# endif
+#endif
+
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+       if (uart->cts_pin >= 0) {
+               if (request_irq(gpio_to_irq(uart->cts_pin),
+                       bfin_serial_mctrl_cts_int,
+                       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+                       IRQF_DISABLED, "BFIN_UART_CTS", uart)) {
+                       uart->cts_pin = -1;
+                       pr_info("Unable to attach BlackFin UART CTS interrupt. So, disable it.\n");
+               }
+       }
+       if (uart->rts_pin >= 0) {
+               gpio_direction_output(uart->rts_pin, 0);
+       }
+#endif
+#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
+       if (uart->cts_pin >= 0 && request_irq(uart->status_irq,
+               bfin_serial_mctrl_cts_int,
+               IRQF_DISABLED, "BFIN_UART_MODEM_STATUS", uart)) {
+               uart->cts_pin = -1;
+               pr_info("Unable to attach BlackFin UART Modem Status interrupt.\n");
+       }
+
+       /* CTS RTS PINs are negative assertive. */
+       UART_PUT_MCR(uart, ACTS);
+       UART_SET_IER(uart, EDSSI);
+#endif
+
+       UART_SET_IER(uart, ERBFI);
+       return 0;
+}
+
+static void bfin_serial_shutdown(struct uart_port *port)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+       disable_dma(uart->tx_dma_channel);
+       free_dma(uart->tx_dma_channel);
+       disable_dma(uart->rx_dma_channel);
+       free_dma(uart->rx_dma_channel);
+       del_timer(&(uart->rx_dma_timer));
+       dma_free_coherent(NULL, PAGE_SIZE, uart->rx_dma_buf.buf, 0);
+#else
+#ifdef CONFIG_BF54x
+       switch (uart->port.irq) {
+       case IRQ_UART3_RX:
+               free_dma(CH_UART3_RX);
+               free_dma(CH_UART3_TX);
+               break;
+       case IRQ_UART2_RX:
+               free_dma(CH_UART2_RX);
+               free_dma(CH_UART2_TX);
+               break;
+       default:
+               break;
+       };
+#endif
+       free_irq(uart->port.irq, uart);
+       free_irq(uart->port.irq+1, uart);
+#endif
+
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+       if (uart->cts_pin >= 0)
+               free_irq(gpio_to_irq(uart->cts_pin), uart);
+#endif
+#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
+       if (uart->cts_pin >= 0)
+               free_irq(uart->status_irq, uart);
+#endif
+}
+
+static void
+bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
+                  struct ktermios *old)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       unsigned long flags;
+       unsigned int baud, quot;
+       unsigned short val, ier, lcr = 0;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS8:
+               lcr = WLS(8);
+               break;
+       case CS7:
+               lcr = WLS(7);
+               break;
+       case CS6:
+               lcr = WLS(6);
+               break;
+       case CS5:
+               lcr = WLS(5);
+               break;
+       default:
+               printk(KERN_ERR "%s: word lengh not supported\n",
+                       __func__);
+       }
+
+       /* Anomaly notes:
+        *  05000231 -  STOP bit is always set to 1 whatever the user is set.
+        */
+       if (termios->c_cflag & CSTOPB) {
+               if (ANOMALY_05000231)
+                       printk(KERN_WARNING "STOP bits other than 1 is not "
+                               "supported in case of anomaly 05000231.\n");
+               else
+                       lcr |= STB;
+       }
+       if (termios->c_cflag & PARENB)
+               lcr |= PEN;
+       if (!(termios->c_cflag & PARODD))
+               lcr |= EPS;
+       if (termios->c_cflag & CMSPAR)
+               lcr |= STP;
+
+       spin_lock_irqsave(&uart->port.lock, flags);
+
+       port->read_status_mask = OE;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= (FE | PE);
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               port->read_status_mask |= BI;
+
+       /*
+        * Characters to ignore
+        */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= FE | PE;
+       if (termios->c_iflag & IGNBRK) {
+               port->ignore_status_mask |= BI;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       port->ignore_status_mask |= OE;
+       }
+
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+       quot = uart_get_divisor(port, baud);
+
+       /* If discipline is not IRDA, apply ANOMALY_05000230 */
+       if (termios->c_line != N_IRDA)
+               quot -= ANOMALY_05000230;
+
+       UART_SET_ANOMALY_THRESHOLD(uart, USEC_PER_SEC / baud * 15);
+
+       /* Disable UART */
+       ier = UART_GET_IER(uart);
+       UART_DISABLE_INTS(uart);
+
+       /* Set DLAB in LCR to Access DLL and DLH */
+       UART_SET_DLAB(uart);
+
+       UART_PUT_DLL(uart, quot & 0xFF);
+       UART_PUT_DLH(uart, (quot >> 8) & 0xFF);
+       SSYNC();
+
+       /* Clear DLAB in LCR to Access THR RBR IER */
+       UART_CLEAR_DLAB(uart);
+
+       UART_PUT_LCR(uart, lcr);
+
+       /* Enable UART */
+       UART_ENABLE_INTS(uart, ier);
+
+       val = UART_GET_GCTL(uart);
+       val |= UCEN;
+       UART_PUT_GCTL(uart, val);
+
+       /* Port speed changed, update the per-port timeout. */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       spin_unlock_irqrestore(&uart->port.lock, flags);
+}
+
+static const char *bfin_serial_type(struct uart_port *port)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+       return uart->port.type == PORT_BFIN ? "BFIN-UART" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'.
+ */
+static void bfin_serial_release_port(struct uart_port *port)
+{
+}
+
+/*
+ * Request the memory region(s) being used by 'port'.
+ */
+static int bfin_serial_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void bfin_serial_config_port(struct uart_port *port, int flags)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+       if (flags & UART_CONFIG_TYPE &&
+           bfin_serial_request_port(&uart->port) == 0)
+               uart->port.type = PORT_BFIN;
+}
+
+/*
+ * Verify the new serial_struct (for TIOCSSERIAL).
+ * The only change we allow are to the flags and type, and
+ * even then only between PORT_BFIN and PORT_UNKNOWN
+ */
+static int
+bfin_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       return 0;
+}
+
+/*
+ * Enable the IrDA function if tty->ldisc.num is N_IRDA.
+ * In other cases, disable IrDA function.
+ */
+static void bfin_serial_set_ldisc(struct uart_port *port, int ld)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       unsigned short val;
+
+       switch (ld) {
+       case N_IRDA:
+               val = UART_GET_GCTL(uart);
+               val |= (IREN | RPOLC);
+               UART_PUT_GCTL(uart, val);
+               break;
+       default:
+               val = UART_GET_GCTL(uart);
+               val &= ~(IREN | RPOLC);
+               UART_PUT_GCTL(uart, val);
+       }
+}
+
+static void bfin_serial_reset_irda(struct uart_port *port)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       unsigned short val;
+
+       val = UART_GET_GCTL(uart);
+       val &= ~(IREN | RPOLC);
+       UART_PUT_GCTL(uart, val);
+       SSYNC();
+       val |= (IREN | RPOLC);
+       UART_PUT_GCTL(uart, val);
+       SSYNC();
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+/* Anomaly notes:
+ *  05000099 -  Because we only use THRE in poll_put and DR in poll_get,
+ *             losing other bits of UART_LSR is not a problem here.
+ */
+static void bfin_serial_poll_put_char(struct uart_port *port, unsigned char chr)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+       while (!(UART_GET_LSR(uart) & THRE))
+               cpu_relax();
+
+       UART_CLEAR_DLAB(uart);
+       UART_PUT_CHAR(uart, (unsigned char)chr);
+}
+
+static int bfin_serial_poll_get_char(struct uart_port *port)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       unsigned char chr;
+
+       while (!(UART_GET_LSR(uart) & DR))
+               cpu_relax();
+
+       UART_CLEAR_DLAB(uart);
+       chr = UART_GET_CHAR(uart);
+
+       return chr;
+}
+#endif
+
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+static void bfin_kgdboc_port_shutdown(struct uart_port *port)
+{
+       if (kgdboc_break_enabled) {
+               kgdboc_break_enabled = 0;
+               bfin_serial_shutdown(port);
+       }
+}
+
+static int bfin_kgdboc_port_startup(struct uart_port *port)
+{
+       kgdboc_port_line = port->line;
+       kgdboc_break_enabled = !bfin_serial_startup(port);
+       return 0;
+}
+#endif
+
+static struct uart_ops bfin_serial_pops = {
+       .tx_empty       = bfin_serial_tx_empty,
+       .set_mctrl      = bfin_serial_set_mctrl,
+       .get_mctrl      = bfin_serial_get_mctrl,
+       .stop_tx        = bfin_serial_stop_tx,
+       .start_tx       = bfin_serial_start_tx,
+       .stop_rx        = bfin_serial_stop_rx,
+       .enable_ms      = bfin_serial_enable_ms,
+       .break_ctl      = bfin_serial_break_ctl,
+       .startup        = bfin_serial_startup,
+       .shutdown       = bfin_serial_shutdown,
+       .set_termios    = bfin_serial_set_termios,
+       .set_ldisc      = bfin_serial_set_ldisc,
+       .type           = bfin_serial_type,
+       .release_port   = bfin_serial_release_port,
+       .request_port   = bfin_serial_request_port,
+       .config_port    = bfin_serial_config_port,
+       .verify_port    = bfin_serial_verify_port,
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+       .kgdboc_port_startup    = bfin_kgdboc_port_startup,
+       .kgdboc_port_shutdown   = bfin_kgdboc_port_shutdown,
+#endif
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_put_char  = bfin_serial_poll_put_char,
+       .poll_get_char  = bfin_serial_poll_get_char,
+#endif
+};
+
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+/*
+ * If the port was already initialised (eg, by a boot loader),
+ * try to determine the current setup.
+ */
+static void __init
+bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
+                          int *parity, int *bits)
+{
+       unsigned short status;
+
+       status = UART_GET_IER(uart) & (ERBFI | ETBEI);
+       if (status == (ERBFI | ETBEI)) {
+               /* ok, the port was enabled */
+               u16 lcr, dlh, dll;
+
+               lcr = UART_GET_LCR(uart);
+
+               *parity = 'n';
+               if (lcr & PEN) {
+                       if (lcr & EPS)
+                               *parity = 'e';
+                       else
+                               *parity = 'o';
+               }
+               switch (lcr & 0x03) {
+                       case 0: *bits = 5; break;
+                       case 1: *bits = 6; break;
+                       case 2: *bits = 7; break;
+                       case 3: *bits = 8; break;
+               }
+               /* Set DLAB in LCR to Access DLL and DLH */
+               UART_SET_DLAB(uart);
+
+               dll = UART_GET_DLL(uart);
+               dlh = UART_GET_DLH(uart);
+
+               /* Clear DLAB in LCR to Access THR RBR IER */
+               UART_CLEAR_DLAB(uart);
+
+               *baud = get_sclk() / (16*(dll | dlh << 8));
+       }
+       pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __func__, *baud, *parity, *bits);
+}
+
+static struct uart_driver bfin_serial_reg;
+
+static void bfin_serial_console_putchar(struct uart_port *port, int ch)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       while (!(UART_GET_LSR(uart) & THRE))
+               barrier();
+       UART_PUT_CHAR(uart, ch);
+}
+
+#endif /* defined (CONFIG_SERIAL_BFIN_CONSOLE) ||
+                defined (CONFIG_EARLY_PRINTK) */
+
+#ifdef CONFIG_SERIAL_BFIN_CONSOLE
+#define CLASS_BFIN_CONSOLE     "bfin-console"
+/*
+ * Interrupts are disabled on entering
+ */
+static void
+bfin_serial_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct bfin_serial_port *uart = bfin_serial_ports[co->index];
+       unsigned long flags;
+
+       spin_lock_irqsave(&uart->port.lock, flags);
+       uart_console_write(&uart->port, s, count, bfin_serial_console_putchar);
+       spin_unlock_irqrestore(&uart->port.lock, flags);
+
+}
+
+static int __init
+bfin_serial_console_setup(struct console *co, char *options)
+{
+       struct bfin_serial_port *uart;
+       int baud = 57600;
+       int bits = 8;
+       int parity = 'n';
+# if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
+       defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
+       int flow = 'r';
+# else
+       int flow = 'n';
+# endif
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index < 0 || co->index >= BFIN_UART_NR_PORTS)
+               return -ENODEV;
+
+       uart = bfin_serial_ports[co->index];
+       if (!uart)
+               return -ENODEV;
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               bfin_serial_console_get_options(uart, &baud, &parity, &bits);
+
+       return uart_set_options(&uart->port, co, baud, parity, bits, flow);
+}
+
+static struct console bfin_serial_console = {
+       .name           = BFIN_SERIAL_DEV_NAME,
+       .write          = bfin_serial_console_write,
+       .device         = uart_console_device,
+       .setup          = bfin_serial_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &bfin_serial_reg,
+};
+#define BFIN_SERIAL_CONSOLE    &bfin_serial_console
+#else
+#define BFIN_SERIAL_CONSOLE    NULL
+#endif /* CONFIG_SERIAL_BFIN_CONSOLE */
+
+#ifdef CONFIG_EARLY_PRINTK
+static struct bfin_serial_port bfin_earlyprintk_port;
+#define CLASS_BFIN_EARLYPRINTK "bfin-earlyprintk"
+
+/*
+ * Interrupts are disabled on entering
+ */
+static void
+bfin_earlyprintk_console_write(struct console *co, const char *s, unsigned int count)
+{
+       unsigned long flags;
+
+       if (bfin_earlyprintk_port.port.line != co->index)
+               return;
+
+       spin_lock_irqsave(&bfin_earlyprintk_port.port.lock, flags);
+       uart_console_write(&bfin_earlyprintk_port.port, s, count,
+               bfin_serial_console_putchar);
+       spin_unlock_irqrestore(&bfin_earlyprintk_port.port.lock, flags);
+}
+
+/*
+ * This should have a .setup or .early_setup in it, but then things get called
+ * without the command line options, and the baud rate gets messed up - so
+ * don't let the common infrastructure play with things. (see calls to setup
+ * & earlysetup in ./kernel/printk.c:register_console()
+ */
+static struct __initdata console bfin_early_serial_console = {
+       .name = "early_BFuart",
+       .write = bfin_earlyprintk_console_write,
+       .device = uart_console_device,
+       .flags = CON_PRINTBUFFER,
+       .index = -1,
+       .data  = &bfin_serial_reg,
+};
+#endif
+
+static struct uart_driver bfin_serial_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = DRIVER_NAME,
+       .dev_name               = BFIN_SERIAL_DEV_NAME,
+       .major                  = BFIN_SERIAL_MAJOR,
+       .minor                  = BFIN_SERIAL_MINOR,
+       .nr                     = BFIN_UART_NR_PORTS,
+       .cons                   = BFIN_SERIAL_CONSOLE,
+};
+
+static int bfin_serial_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct bfin_serial_port *uart = platform_get_drvdata(pdev);
+
+       return uart_suspend_port(&bfin_serial_reg, &uart->port);
+}
+
+static int bfin_serial_resume(struct platform_device *pdev)
+{
+       struct bfin_serial_port *uart = platform_get_drvdata(pdev);
+
+       return uart_resume_port(&bfin_serial_reg, &uart->port);
+}
+
+static int bfin_serial_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       struct bfin_serial_port *uart = NULL;
+       int ret = 0;
+
+       if (pdev->id < 0 || pdev->id >= BFIN_UART_NR_PORTS) {
+               dev_err(&pdev->dev, "Wrong bfin uart platform device id.\n");
+               return -ENOENT;
+       }
+
+       if (bfin_serial_ports[pdev->id] == NULL) {
+
+               uart = kzalloc(sizeof(*uart), GFP_KERNEL);
+               if (!uart) {
+                       dev_err(&pdev->dev,
+                               "fail to malloc bfin_serial_port\n");
+                       return -ENOMEM;
+               }
+               bfin_serial_ports[pdev->id] = uart;
+
+#ifdef CONFIG_EARLY_PRINTK
+               if (!(bfin_earlyprintk_port.port.membase
+                       && bfin_earlyprintk_port.port.line == pdev->id)) {
+                       /*
+                        * If the peripheral PINs of current port is allocated
+                        * in earlyprintk probe stage, don't do it again.
+                        */
+#endif
+               ret = peripheral_request_list(
+                       (unsigned short *)pdev->dev.platform_data, DRIVER_NAME);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "fail to request bfin serial peripherals\n");
+                       goto out_error_free_mem;
+               }
+#ifdef CONFIG_EARLY_PRINTK
+               }
+#endif
+
+               spin_lock_init(&uart->port.lock);
+               uart->port.uartclk   = get_sclk();
+               uart->port.fifosize  = BFIN_UART_TX_FIFO_SIZE;
+               uart->port.ops       = &bfin_serial_pops;
+               uart->port.line      = pdev->id;
+               uart->port.iotype    = UPIO_MEM;
+               uart->port.flags     = UPF_BOOT_AUTOCONF;
+
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+               if (res == NULL) {
+                       dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
+                       ret = -ENOENT;
+                       goto out_error_free_peripherals;
+               }
+
+               uart->port.membase = ioremap(res->start,
+                       res->end - res->start);
+               if (!uart->port.membase) {
+                       dev_err(&pdev->dev, "Cannot map uart IO\n");
+                       ret = -ENXIO;
+                       goto out_error_free_peripherals;
+               }
+               uart->port.mapbase = res->start;
+
+               uart->port.irq = platform_get_irq(pdev, 0);
+               if (uart->port.irq < 0) {
+                       dev_err(&pdev->dev, "No uart RX/TX IRQ specified\n");
+                       ret = -ENOENT;
+                       goto out_error_unmap;
+               }
+
+               uart->status_irq = platform_get_irq(pdev, 1);
+               if (uart->status_irq < 0) {
+                       dev_err(&pdev->dev, "No uart status IRQ specified\n");
+                       ret = -ENOENT;
+                       goto out_error_unmap;
+               }
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+               uart->tx_done       = 1;
+               uart->tx_count      = 0;
+
+               res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+               if (res == NULL) {
+                       dev_err(&pdev->dev, "No uart TX DMA channel specified\n");
+                       ret = -ENOENT;
+                       goto out_error_unmap;
+               }
+               uart->tx_dma_channel = res->start;
+
+               res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+               if (res == NULL) {
+                       dev_err(&pdev->dev, "No uart RX DMA channel specified\n");
+                       ret = -ENOENT;
+                       goto out_error_unmap;
+               }
+               uart->rx_dma_channel = res->start;
+
+               init_timer(&(uart->rx_dma_timer));
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
+       defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
+               res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+               if (res == NULL)
+                       uart->cts_pin = -1;
+               else
+                       uart->cts_pin = res->start;
+
+               res = platform_get_resource(pdev, IORESOURCE_IO, 1);
+               if (res == NULL)
+                       uart->rts_pin = -1;
+               else
+                       uart->rts_pin = res->start;
+# if defined(CONFIG_SERIAL_BFIN_CTSRTS)
+               if (uart->rts_pin >= 0)
+                       gpio_request(uart->rts_pin, DRIVER_NAME);
+# endif
+#endif
+       }
+
+#ifdef CONFIG_SERIAL_BFIN_CONSOLE
+       if (!is_early_platform_device(pdev)) {
+#endif
+               uart = bfin_serial_ports[pdev->id];
+               uart->port.dev = &pdev->dev;
+               dev_set_drvdata(&pdev->dev, uart);
+               ret = uart_add_one_port(&bfin_serial_reg, &uart->port);
+#ifdef CONFIG_SERIAL_BFIN_CONSOLE
+       }
+#endif
+
+       if (!ret)
+               return 0;
+
+       if (uart) {
+out_error_unmap:
+               iounmap(uart->port.membase);
+out_error_free_peripherals:
+               peripheral_free_list(
+                       (unsigned short *)pdev->dev.platform_data);
+out_error_free_mem:
+               kfree(uart);
+               bfin_serial_ports[pdev->id] = NULL;
+       }
+
+       return ret;
+}
+
+static int __devexit bfin_serial_remove(struct platform_device *pdev)
+{
+       struct bfin_serial_port *uart = platform_get_drvdata(pdev);
+
+       dev_set_drvdata(&pdev->dev, NULL);
+
+       if (uart) {
+               uart_remove_one_port(&bfin_serial_reg, &uart->port);
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+               if (uart->rts_pin >= 0)
+                       gpio_free(uart->rts_pin);
+#endif
+               iounmap(uart->port.membase);
+               peripheral_free_list(
+                       (unsigned short *)pdev->dev.platform_data);
+               kfree(uart);
+               bfin_serial_ports[pdev->id] = NULL;
+       }
+
+       return 0;
+}
+
+static struct platform_driver bfin_serial_driver = {
+       .probe          = bfin_serial_probe,
+       .remove         = __devexit_p(bfin_serial_remove),
+       .suspend        = bfin_serial_suspend,
+       .resume         = bfin_serial_resume,
+       .driver         = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE)
+static __initdata struct early_platform_driver early_bfin_serial_driver = {
+       .class_str = CLASS_BFIN_CONSOLE,
+       .pdrv = &bfin_serial_driver,
+       .requested_id = EARLY_PLATFORM_ID_UNSET,
+};
+
+static int __init bfin_serial_rs_console_init(void)
+{
+       early_platform_driver_register(&early_bfin_serial_driver, DRIVER_NAME);
+
+       early_platform_driver_probe(CLASS_BFIN_CONSOLE, BFIN_UART_NR_PORTS, 0);
+
+       register_console(&bfin_serial_console);
+
+       return 0;
+}
+console_initcall(bfin_serial_rs_console_init);
+#endif
+
+#ifdef CONFIG_EARLY_PRINTK
+/*
+ * Memory can't be allocated dynamically during earlyprink init stage.
+ * So, do individual probe for earlyprink with a static uart port variable.
+ */
+static int bfin_earlyprintk_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       int ret;
+
+       if (pdev->id < 0 || pdev->id >= BFIN_UART_NR_PORTS) {
+               dev_err(&pdev->dev, "Wrong earlyprintk platform device id.\n");
+               return -ENOENT;
+       }
+
+       ret = peripheral_request_list(
+               (unsigned short *)pdev->dev.platform_data, DRIVER_NAME);
+       if (ret) {
+               dev_err(&pdev->dev,
+                               "fail to request bfin serial peripherals\n");
+                       return ret;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
+               ret = -ENOENT;
+               goto out_error_free_peripherals;
+       }
+
+       bfin_earlyprintk_port.port.membase = ioremap(res->start,
+                       res->end - res->start);
+       if (!bfin_earlyprintk_port.port.membase) {
+               dev_err(&pdev->dev, "Cannot map uart IO\n");
+               ret = -ENXIO;
+               goto out_error_free_peripherals;
+       }
+       bfin_earlyprintk_port.port.mapbase = res->start;
+       bfin_earlyprintk_port.port.line = pdev->id;
+       bfin_earlyprintk_port.port.uartclk = get_sclk();
+       bfin_earlyprintk_port.port.fifosize  = BFIN_UART_TX_FIFO_SIZE;
+       spin_lock_init(&bfin_earlyprintk_port.port.lock);
+
+       return 0;
+
+out_error_free_peripherals:
+       peripheral_free_list(
+               (unsigned short *)pdev->dev.platform_data);
+
+       return ret;
+}
+
+static struct platform_driver bfin_earlyprintk_driver = {
+       .probe          = bfin_earlyprintk_probe,
+       .driver         = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static __initdata struct early_platform_driver early_bfin_earlyprintk_driver = {
+       .class_str = CLASS_BFIN_EARLYPRINTK,
+       .pdrv = &bfin_earlyprintk_driver,
+       .requested_id = EARLY_PLATFORM_ID_UNSET,
+};
+
+struct console __init *bfin_earlyserial_init(unsigned int port,
+                                               unsigned int cflag)
+{
+       struct ktermios t;
+       char port_name[20];
+
+       if (port < 0 || port >= BFIN_UART_NR_PORTS)
+               return NULL;
+
+       /*
+        * Only probe resource of the given port in earlyprintk boot arg.
+        * The expected port id should be indicated in port name string.
+        */
+       snprintf(port_name, 20, DRIVER_NAME ".%d", port);
+       early_platform_driver_register(&early_bfin_earlyprintk_driver,
+               port_name);
+       early_platform_driver_probe(CLASS_BFIN_EARLYPRINTK, 1, 0);
+
+       if (!bfin_earlyprintk_port.port.membase)
+               return NULL;
+
+#ifdef CONFIG_SERIAL_BFIN_CONSOLE
+       /*
+        * If we are using early serial, don't let the normal console rewind
+        * log buffer, since that causes things to be printed multiple times
+        */
+       bfin_serial_console.flags &= ~CON_PRINTBUFFER;
+#endif
+
+       bfin_early_serial_console.index = port;
+       t.c_cflag = cflag;
+       t.c_iflag = 0;
+       t.c_oflag = 0;
+       t.c_lflag = ICANON;
+       t.c_line = port;
+       bfin_serial_set_termios(&bfin_earlyprintk_port.port, &t, &t);
+
+       return &bfin_early_serial_console;
+}
+#endif /* CONFIG_EARLY_PRINTK */
+
+static int __init bfin_serial_init(void)
+{
+       int ret;
+
+       pr_info("Blackfin serial driver\n");
+
+       ret = uart_register_driver(&bfin_serial_reg);
+       if (ret) {
+               pr_err("failed to register %s:%d\n",
+                       bfin_serial_reg.driver_name, ret);
+       }
+
+       ret = platform_driver_register(&bfin_serial_driver);
+       if (ret) {
+               pr_err("fail to register bfin uart\n");
+               uart_unregister_driver(&bfin_serial_reg);
+       }
+
+       return ret;
+}
+
+static void __exit bfin_serial_exit(void)
+{
+       platform_driver_unregister(&bfin_serial_driver);
+       uart_unregister_driver(&bfin_serial_reg);
+}
+
+
+module_init(bfin_serial_init);
+module_exit(bfin_serial_exit);
+
+MODULE_AUTHOR("Sonic Zhang, Aubrey Li");
+MODULE_DESCRIPTION("Blackfin generic serial port driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(BFIN_SERIAL_MAJOR);
+MODULE_ALIAS("platform:bfin-uart");
diff --git a/drivers/tty/serial/bfin_sport_uart.c b/drivers/tty/serial/bfin_sport_uart.c
new file mode 100644 (file)
index 0000000..e95c524
--- /dev/null
@@ -0,0 +1,935 @@
+/*
+ * Blackfin On-Chip Sport Emulated UART Driver
+ *
+ * Copyright 2006-2009 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+/*
+ * This driver and the hardware supported are in term of EE-191 of ADI.
+ * http://www.analog.com/static/imported-files/application_notes/EE191.pdf 
+ * This application note describe how to implement a UART on a Sharc DSP,
+ * but this driver is implemented on Blackfin Processor.
+ * Transmit Frame Sync is not used by this driver to transfer data out.
+ */
+
+/* #define DEBUG */
+
+#define DRV_NAME "bfin-sport-uart"
+#define DEVICE_NAME    "ttySS"
+#define pr_fmt(fmt) DRV_NAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+
+#include <asm/bfin_sport.h>
+#include <asm/delay.h>
+#include <asm/portmux.h>
+
+#include "bfin_sport_uart.h"
+
+struct sport_uart_port {
+       struct uart_port        port;
+       int                     err_irq;
+       unsigned short          csize;
+       unsigned short          rxmask;
+       unsigned short          txmask1;
+       unsigned short          txmask2;
+       unsigned char           stopb;
+/*     unsigned char           parib; */
+#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
+       int cts_pin;
+       int rts_pin;
+#endif
+};
+
+static int sport_uart_tx_chars(struct sport_uart_port *up);
+static void sport_stop_tx(struct uart_port *port);
+
+static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value)
+{
+       pr_debug("%s value:%x, mask1=0x%x, mask2=0x%x\n", __func__, value,
+               up->txmask1, up->txmask2);
+
+       /* Place Start and Stop bits */
+       __asm__ __volatile__ (
+               "%[val] <<= 1;"
+               "%[val] = %[val] & %[mask1];"
+               "%[val] = %[val] | %[mask2];"
+               : [val]"+d"(value)
+               : [mask1]"d"(up->txmask1), [mask2]"d"(up->txmask2)
+               : "ASTAT"
+       );
+       pr_debug("%s value:%x\n", __func__, value);
+
+       SPORT_PUT_TX(up, value);
+}
+
+static inline unsigned char rx_one_byte(struct sport_uart_port *up)
+{
+       unsigned int value;
+       unsigned char extract;
+       u32 tmp_mask1, tmp_mask2, tmp_shift, tmp;
+
+       if ((up->csize + up->stopb) > 7)
+               value = SPORT_GET_RX32(up);
+       else
+               value = SPORT_GET_RX(up);
+
+       pr_debug("%s value:%x, cs=%d, mask=0x%x\n", __func__, value,
+               up->csize, up->rxmask);
+
+       /* Extract data */
+       __asm__ __volatile__ (
+               "%[extr] = 0;"
+               "%[mask1] = %[rxmask];"
+               "%[mask2] = 0x0200(Z);"
+               "%[shift] = 0;"
+               "LSETUP(.Lloop_s, .Lloop_e) LC0 = %[lc];"
+               ".Lloop_s:"
+               "%[tmp] = extract(%[val], %[mask1].L)(Z);"
+               "%[tmp] <<= %[shift];"
+               "%[extr] = %[extr] | %[tmp];"
+               "%[mask1] = %[mask1] - %[mask2];"
+               ".Lloop_e:"
+               "%[shift] += 1;"
+               : [extr]"=&d"(extract), [shift]"=&d"(tmp_shift), [tmp]"=&d"(tmp),
+                 [mask1]"=&d"(tmp_mask1), [mask2]"=&d"(tmp_mask2)
+               : [val]"d"(value), [rxmask]"d"(up->rxmask), [lc]"a"(up->csize)
+               : "ASTAT", "LB0", "LC0", "LT0"
+       );
+
+       pr_debug("      extract:%x\n", extract);
+       return extract;
+}
+
+static int sport_uart_setup(struct sport_uart_port *up, int size, int baud_rate)
+{
+       int tclkdiv, rclkdiv;
+       unsigned int sclk = get_sclk();
+
+       /* Set TCR1 and TCR2, TFSR is not enabled for uart */
+       SPORT_PUT_TCR1(up, (LATFS | ITFS | TFSR | TLSBIT | ITCLK));
+       SPORT_PUT_TCR2(up, size + 1);
+       pr_debug("%s TCR1:%x, TCR2:%x\n", __func__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up));
+
+       /* Set RCR1 and RCR2 */
+       SPORT_PUT_RCR1(up, (RCKFE | LARFS | LRFS | RFSR | IRCLK));
+       SPORT_PUT_RCR2(up, (size + 1) * 2 - 1);
+       pr_debug("%s RCR1:%x, RCR2:%x\n", __func__, SPORT_GET_RCR1(up), SPORT_GET_RCR2(up));
+
+       tclkdiv = sclk / (2 * baud_rate) - 1;
+       /* The actual uart baud rate of devices vary between +/-2%. The sport
+        * RX sample rate should be faster than the double of the worst case,
+        * otherwise, wrong data are received. So, set sport RX clock to be
+        * 3% faster.
+        */
+       rclkdiv = sclk / (2 * baud_rate * 2 * 97 / 100) - 1;
+       SPORT_PUT_TCLKDIV(up, tclkdiv);
+       SPORT_PUT_RCLKDIV(up, rclkdiv);
+       SSYNC();
+       pr_debug("%s sclk:%d, baud_rate:%d, tclkdiv:%d, rclkdiv:%d\n",
+                       __func__, sclk, baud_rate, tclkdiv, rclkdiv);
+
+       return 0;
+}
+
+static irqreturn_t sport_uart_rx_irq(int irq, void *dev_id)
+{
+       struct sport_uart_port *up = dev_id;
+       struct tty_struct *tty = up->port.state->port.tty;
+       unsigned int ch;
+
+       spin_lock(&up->port.lock);
+
+       while (SPORT_GET_STAT(up) & RXNE) {
+               ch = rx_one_byte(up);
+               up->port.icount.rx++;
+
+               if (!uart_handle_sysrq_char(&up->port, ch))
+                       tty_insert_flip_char(tty, ch, TTY_NORMAL);
+       }
+       tty_flip_buffer_push(tty);
+
+       spin_unlock(&up->port.lock);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t sport_uart_tx_irq(int irq, void *dev_id)
+{
+       struct sport_uart_port *up = dev_id;
+
+       spin_lock(&up->port.lock);
+       sport_uart_tx_chars(up);
+       spin_unlock(&up->port.lock);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t sport_uart_err_irq(int irq, void *dev_id)
+{
+       struct sport_uart_port *up = dev_id;
+       struct tty_struct *tty = up->port.state->port.tty;
+       unsigned int stat = SPORT_GET_STAT(up);
+
+       spin_lock(&up->port.lock);
+
+       /* Overflow in RX FIFO */
+       if (stat & ROVF) {
+               up->port.icount.overrun++;
+               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+               SPORT_PUT_STAT(up, ROVF); /* Clear ROVF bit */
+       }
+       /* These should not happen */
+       if (stat & (TOVF | TUVF | RUVF)) {
+               pr_err("SPORT Error:%s %s %s\n",
+                      (stat & TOVF) ? "TX overflow" : "",
+                      (stat & TUVF) ? "TX underflow" : "",
+                      (stat & RUVF) ? "RX underflow" : "");
+               SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN);
+               SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) & ~RSPEN);
+       }
+       SSYNC();
+
+       spin_unlock(&up->port.lock);
+       return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
+static unsigned int sport_get_mctrl(struct uart_port *port)
+{
+       struct sport_uart_port *up = (struct sport_uart_port *)port;
+       if (up->cts_pin < 0)
+               return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+
+       /* CTS PIN is negative assertive. */
+       if (SPORT_UART_GET_CTS(up))
+               return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+       else
+               return TIOCM_DSR | TIOCM_CAR;
+}
+
+static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct sport_uart_port *up = (struct sport_uart_port *)port;
+       if (up->rts_pin < 0)
+               return;
+
+       /* RTS PIN is negative assertive. */
+       if (mctrl & TIOCM_RTS)
+               SPORT_UART_ENABLE_RTS(up);
+       else
+               SPORT_UART_DISABLE_RTS(up);
+}
+
+/*
+ * Handle any change of modem status signal.
+ */
+static irqreturn_t sport_mctrl_cts_int(int irq, void *dev_id)
+{
+       struct sport_uart_port *up = (struct sport_uart_port *)dev_id;
+       unsigned int status;
+
+       status = sport_get_mctrl(&up->port);
+       uart_handle_cts_change(&up->port, status & TIOCM_CTS);
+
+       return IRQ_HANDLED;
+}
+#else
+static unsigned int sport_get_mctrl(struct uart_port *port)
+{
+       pr_debug("%s enter\n", __func__);
+       return TIOCM_CTS | TIOCM_CD | TIOCM_DSR;
+}
+
+static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       pr_debug("%s enter\n", __func__);
+}
+#endif
+
+/* Reqeust IRQ, Setup clock */
+static int sport_startup(struct uart_port *port)
+{
+       struct sport_uart_port *up = (struct sport_uart_port *)port;
+       int ret;
+
+       pr_debug("%s enter\n", __func__);
+       ret = request_irq(up->port.irq, sport_uart_rx_irq, 0,
+               "SPORT_UART_RX", up);
+       if (ret) {
+               dev_err(port->dev, "unable to request SPORT RX interrupt\n");
+               return ret;
+       }
+
+       ret = request_irq(up->port.irq+1, sport_uart_tx_irq, 0,
+               "SPORT_UART_TX", up);
+       if (ret) {
+               dev_err(port->dev, "unable to request SPORT TX interrupt\n");
+               goto fail1;
+       }
+
+       ret = request_irq(up->err_irq, sport_uart_err_irq, 0,
+               "SPORT_UART_STATUS", up);
+       if (ret) {
+               dev_err(port->dev, "unable to request SPORT status interrupt\n");
+               goto fail2;
+       }
+
+#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
+       if (up->cts_pin >= 0) {
+               if (request_irq(gpio_to_irq(up->cts_pin),
+                       sport_mctrl_cts_int,
+                       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+                       IRQF_DISABLED, "BFIN_SPORT_UART_CTS", up)) {
+                       up->cts_pin = -1;
+                       dev_info(port->dev, "Unable to attach BlackFin UART \
+                               over SPORT CTS interrupt. So, disable it.\n");
+               }
+       }
+       if (up->rts_pin >= 0)
+               gpio_direction_output(up->rts_pin, 0);
+#endif
+
+       return 0;
+ fail2:
+       free_irq(up->port.irq+1, up);
+ fail1:
+       free_irq(up->port.irq, up);
+
+       return ret;
+}
+
+/*
+ * sport_uart_tx_chars
+ *
+ * ret 1 means need to enable sport.
+ * ret 0 means do nothing.
+ */
+static int sport_uart_tx_chars(struct sport_uart_port *up)
+{
+       struct circ_buf *xmit = &up->port.state->xmit;
+
+       if (SPORT_GET_STAT(up) & TXF)
+               return 0;
+
+       if (up->port.x_char) {
+               tx_one_byte(up, up->port.x_char);
+               up->port.icount.tx++;
+               up->port.x_char = 0;
+               return 1;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+               /* The waiting loop to stop SPORT TX from TX interrupt is
+                * too long. This may block SPORT RX interrupts and cause
+                * RX FIFO overflow. So, do stop sport TX only after the last
+                * char in TX FIFO is moved into the shift register.
+                */
+               if (SPORT_GET_STAT(up) & TXHRE)
+                       sport_stop_tx(&up->port);
+               return 0;
+       }
+
+       while(!(SPORT_GET_STAT(up) & TXF) && !uart_circ_empty(xmit)) {
+               tx_one_byte(up, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1);
+               up->port.icount.tx++;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+       return 1;
+}
+
+static unsigned int sport_tx_empty(struct uart_port *port)
+{
+       struct sport_uart_port *up = (struct sport_uart_port *)port;
+       unsigned int stat;
+
+       stat = SPORT_GET_STAT(up);
+       pr_debug("%s stat:%04x\n", __func__, stat);
+       if (stat & TXHRE) {
+               return TIOCSER_TEMT;
+       } else
+               return 0;
+}
+
+static void sport_stop_tx(struct uart_port *port)
+{
+       struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+       pr_debug("%s enter\n", __func__);
+
+       if (!(SPORT_GET_TCR1(up) & TSPEN))
+               return;
+
+       /* Although the hold register is empty, last byte is still in shift
+        * register and not sent out yet. So, put a dummy data into TX FIFO.
+        * Then, sport tx stops when last byte is shift out and the dummy
+        * data is moved into the shift register.
+        */
+       SPORT_PUT_TX(up, 0xffff);
+       while (!(SPORT_GET_STAT(up) & TXHRE))
+               cpu_relax();
+
+       SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN));
+       SSYNC();
+
+       return;
+}
+
+static void sport_start_tx(struct uart_port *port)
+{
+       struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+       pr_debug("%s enter\n", __func__);
+
+       /* Write data into SPORT FIFO before enable SPROT to transmit */
+       if (sport_uart_tx_chars(up)) {
+               /* Enable transmit, then an interrupt will generated */
+               SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN));
+               SSYNC();
+       }
+
+       pr_debug("%s exit\n", __func__);
+}
+
+static void sport_stop_rx(struct uart_port *port)
+{
+       struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+       pr_debug("%s enter\n", __func__);
+       /* Disable sport to stop rx */
+       SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) & ~RSPEN));
+       SSYNC();
+}
+
+static void sport_enable_ms(struct uart_port *port)
+{
+       pr_debug("%s enter\n", __func__);
+}
+
+static void sport_break_ctl(struct uart_port *port, int break_state)
+{
+       pr_debug("%s enter\n", __func__);
+}
+
+static void sport_shutdown(struct uart_port *port)
+{
+       struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+       dev_dbg(port->dev, "%s enter\n", __func__);
+
+       /* Disable sport */
+       SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN));
+       SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) & ~RSPEN));
+       SSYNC();
+
+       free_irq(up->port.irq, up);
+       free_irq(up->port.irq+1, up);
+       free_irq(up->err_irq, up);
+#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
+       if (up->cts_pin >= 0)
+               free_irq(gpio_to_irq(up->cts_pin), up);
+#endif
+}
+
+static const char *sport_type(struct uart_port *port)
+{
+       struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+       pr_debug("%s enter\n", __func__);
+       return up->port.type == PORT_BFIN_SPORT ? "BFIN-SPORT-UART" : NULL;
+}
+
+static void sport_release_port(struct uart_port *port)
+{
+       pr_debug("%s enter\n", __func__);
+}
+
+static int sport_request_port(struct uart_port *port)
+{
+       pr_debug("%s enter\n", __func__);
+       return 0;
+}
+
+static void sport_config_port(struct uart_port *port, int flags)
+{
+       struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+       pr_debug("%s enter\n", __func__);
+       up->port.type = PORT_BFIN_SPORT;
+}
+
+static int sport_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       pr_debug("%s enter\n", __func__);
+       return 0;
+}
+
+static void sport_set_termios(struct uart_port *port,
+               struct ktermios *termios, struct ktermios *old)
+{
+       struct sport_uart_port *up = (struct sport_uart_port *)port;
+       unsigned long flags;
+       int i;
+
+       pr_debug("%s enter, c_cflag:%08x\n", __func__, termios->c_cflag);
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS8:
+               up->csize = 8;
+               break;
+       case CS7:
+               up->csize = 7;
+               break;
+       case CS6:
+               up->csize = 6;
+               break;
+       case CS5:
+               up->csize = 5;
+               break;
+       default:
+               pr_warning("requested word length not supported\n");
+       }
+
+       if (termios->c_cflag & CSTOPB) {
+               up->stopb = 1;
+       }
+       if (termios->c_cflag & PARENB) {
+               pr_warning("PAREN bits is not supported yet\n");
+               /* up->parib = 1; */
+       }
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       port->read_status_mask = 0;
+
+       /*
+        * Characters to ignore
+        */
+       port->ignore_status_mask = 0;
+
+       /* RX extract mask */
+       up->rxmask = 0x01 | (((up->csize + up->stopb) * 2 - 1) << 0x8);
+       /* TX masks, 8 bit data and 1 bit stop for example:
+        * mask1 = b#0111111110
+        * mask2 = b#1000000000
+        */
+       for (i = 0, up->txmask1 = 0; i < up->csize; i++)
+               up->txmask1 |= (1<<i);
+       up->txmask2 = (1<<i);
+       if (up->stopb) {
+               ++i;
+               up->txmask2 |= (1<<i);
+       }
+       up->txmask1 <<= 1;
+       up->txmask2 <<= 1;
+       /* uart baud rate */
+       port->uartclk = uart_get_baud_rate(port, termios, old, 0, get_sclk()/16);
+
+       /* Disable UART */
+       SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN);
+       SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) & ~RSPEN);
+
+       sport_uart_setup(up, up->csize + up->stopb, port->uartclk);
+
+       /* driver TX line high after config, one dummy data is
+        * necessary to stop sport after shift one byte
+        */
+       SPORT_PUT_TX(up, 0xffff);
+       SPORT_PUT_TX(up, 0xffff);
+       SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN));
+       SSYNC();
+       while (!(SPORT_GET_STAT(up) & TXHRE))
+               cpu_relax();
+       SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN);
+       SSYNC();
+
+       /* Port speed changed, update the per-port timeout. */
+       uart_update_timeout(port, termios->c_cflag, port->uartclk);
+
+       /* Enable sport rx */
+       SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) | RSPEN);
+       SSYNC();
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+struct uart_ops sport_uart_ops = {
+       .tx_empty       = sport_tx_empty,
+       .set_mctrl      = sport_set_mctrl,
+       .get_mctrl      = sport_get_mctrl,
+       .stop_tx        = sport_stop_tx,
+       .start_tx       = sport_start_tx,
+       .stop_rx        = sport_stop_rx,
+       .enable_ms      = sport_enable_ms,
+       .break_ctl      = sport_break_ctl,
+       .startup        = sport_startup,
+       .shutdown       = sport_shutdown,
+       .set_termios    = sport_set_termios,
+       .type           = sport_type,
+       .release_port   = sport_release_port,
+       .request_port   = sport_request_port,
+       .config_port    = sport_config_port,
+       .verify_port    = sport_verify_port,
+};
+
+#define BFIN_SPORT_UART_MAX_PORTS 4
+
+static struct sport_uart_port *bfin_sport_uart_ports[BFIN_SPORT_UART_MAX_PORTS];
+
+#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
+#define CLASS_BFIN_SPORT_CONSOLE       "bfin-sport-console"
+
+static int __init
+sport_uart_console_setup(struct console *co, char *options)
+{
+       struct sport_uart_port *up;
+       int baud = 57600;
+       int bits = 8;
+       int parity = 'n';
+# ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
+       int flow = 'r';
+# else
+       int flow = 'n';
+# endif
+
+       /* Check whether an invalid uart number has been specified */
+       if (co->index < 0 || co->index >= BFIN_SPORT_UART_MAX_PORTS)
+               return -ENODEV;
+
+       up = bfin_sport_uart_ports[co->index];
+       if (!up)
+               return -ENODEV;
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(&up->port, co, baud, parity, bits, flow);
+}
+
+static void sport_uart_console_putchar(struct uart_port *port, int ch)
+{
+       struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+       while (SPORT_GET_STAT(up) & TXF)
+               barrier();
+
+       tx_one_byte(up, ch);
+}
+
+/*
+ * Interrupts are disabled on entering
+ */
+static void
+sport_uart_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct sport_uart_port *up = bfin_sport_uart_ports[co->index];
+       unsigned long flags;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       if (SPORT_GET_TCR1(up) & TSPEN)
+               uart_console_write(&up->port, s, count, sport_uart_console_putchar);
+       else {
+               /* dummy data to start sport */
+               while (SPORT_GET_STAT(up) & TXF)
+                       barrier();
+               SPORT_PUT_TX(up, 0xffff);
+               /* Enable transmit, then an interrupt will generated */
+               SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN));
+               SSYNC();
+
+               uart_console_write(&up->port, s, count, sport_uart_console_putchar);
+
+               /* Although the hold register is empty, last byte is still in shift
+                * register and not sent out yet. So, put a dummy data into TX FIFO.
+                * Then, sport tx stops when last byte is shift out and the dummy
+                * data is moved into the shift register.
+                */
+               while (SPORT_GET_STAT(up) & TXF)
+                       barrier();
+               SPORT_PUT_TX(up, 0xffff);
+               while (!(SPORT_GET_STAT(up) & TXHRE))
+                       barrier();
+
+               /* Stop sport tx transfer */
+               SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN));
+               SSYNC();
+       }
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static struct uart_driver sport_uart_reg;
+
+static struct console sport_uart_console = {
+       .name           = DEVICE_NAME,
+       .write          = sport_uart_console_write,
+       .device         = uart_console_device,
+       .setup          = sport_uart_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &sport_uart_reg,
+};
+
+#define SPORT_UART_CONSOLE     (&sport_uart_console)
+#else
+#define SPORT_UART_CONSOLE     NULL
+#endif /* CONFIG_SERIAL_BFIN_SPORT_CONSOLE */
+
+
+static struct uart_driver sport_uart_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = DRV_NAME,
+       .dev_name       = DEVICE_NAME,
+       .major          = 204,
+       .minor          = 84,
+       .nr             = BFIN_SPORT_UART_MAX_PORTS,
+       .cons           = SPORT_UART_CONSOLE,
+};
+
+#ifdef CONFIG_PM
+static int sport_uart_suspend(struct device *dev)
+{
+       struct sport_uart_port *sport = dev_get_drvdata(dev);
+
+       dev_dbg(dev, "%s enter\n", __func__);
+       if (sport)
+               uart_suspend_port(&sport_uart_reg, &sport->port);
+
+       return 0;
+}
+
+static int sport_uart_resume(struct device *dev)
+{
+       struct sport_uart_port *sport = dev_get_drvdata(dev);
+
+       dev_dbg(dev, "%s enter\n", __func__);
+       if (sport)
+               uart_resume_port(&sport_uart_reg, &sport->port);
+
+       return 0;
+}
+
+static struct dev_pm_ops bfin_sport_uart_dev_pm_ops = {
+       .suspend        = sport_uart_suspend,
+       .resume         = sport_uart_resume,
+};
+#endif
+
+static int __devinit sport_uart_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       struct sport_uart_port *sport;
+       int ret = 0;
+
+       dev_dbg(&pdev->dev, "%s enter\n", __func__);
+
+       if (pdev->id < 0 || pdev->id >= BFIN_SPORT_UART_MAX_PORTS) {
+               dev_err(&pdev->dev, "Wrong sport uart platform device id.\n");
+               return -ENOENT;
+       }
+
+       if (bfin_sport_uart_ports[pdev->id] == NULL) {
+               bfin_sport_uart_ports[pdev->id] =
+                       kzalloc(sizeof(struct sport_uart_port), GFP_KERNEL);
+               sport = bfin_sport_uart_ports[pdev->id];
+               if (!sport) {
+                       dev_err(&pdev->dev,
+                               "Fail to malloc sport_uart_port\n");
+                       return -ENOMEM;
+               }
+
+               ret = peripheral_request_list(
+                       (unsigned short *)pdev->dev.platform_data, DRV_NAME);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "Fail to request SPORT peripherals\n");
+                       goto out_error_free_mem;
+               }
+
+               spin_lock_init(&sport->port.lock);
+               sport->port.fifosize  = SPORT_TX_FIFO_SIZE,
+               sport->port.ops       = &sport_uart_ops;
+               sport->port.line      = pdev->id;
+               sport->port.iotype    = UPIO_MEM;
+               sport->port.flags     = UPF_BOOT_AUTOCONF;
+
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+               if (res == NULL) {
+                       dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
+                       ret = -ENOENT;
+                       goto out_error_free_peripherals;
+               }
+
+               sport->port.membase = ioremap(res->start, resource_size(res));
+               if (!sport->port.membase) {
+                       dev_err(&pdev->dev, "Cannot map sport IO\n");
+                       ret = -ENXIO;
+                       goto out_error_free_peripherals;
+               }
+               sport->port.mapbase = res->start;
+
+               sport->port.irq = platform_get_irq(pdev, 0);
+               if (sport->port.irq < 0) {
+                       dev_err(&pdev->dev, "No sport RX/TX IRQ specified\n");
+                       ret = -ENOENT;
+                       goto out_error_unmap;
+               }
+
+               sport->err_irq = platform_get_irq(pdev, 1);
+               if (sport->err_irq < 0) {
+                       dev_err(&pdev->dev, "No sport status IRQ specified\n");
+                       ret = -ENOENT;
+                       goto out_error_unmap;
+               }
+#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
+               res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+               if (res == NULL)
+                       sport->cts_pin = -1;
+               else
+                       sport->cts_pin = res->start;
+
+               res = platform_get_resource(pdev, IORESOURCE_IO, 1);
+               if (res == NULL)
+                       sport->rts_pin = -1;
+               else
+                       sport->rts_pin = res->start;
+
+               if (sport->rts_pin >= 0)
+                       gpio_request(sport->rts_pin, DRV_NAME);
+#endif
+       }
+
+#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
+       if (!is_early_platform_device(pdev)) {
+#endif
+               sport = bfin_sport_uart_ports[pdev->id];
+               sport->port.dev = &pdev->dev;
+               dev_set_drvdata(&pdev->dev, sport);
+               ret = uart_add_one_port(&sport_uart_reg, &sport->port);
+#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
+       }
+#endif
+       if (!ret)
+               return 0;
+
+       if (sport) {
+out_error_unmap:
+               iounmap(sport->port.membase);
+out_error_free_peripherals:
+               peripheral_free_list(
+                       (unsigned short *)pdev->dev.platform_data);
+out_error_free_mem:
+               kfree(sport);
+               bfin_sport_uart_ports[pdev->id] = NULL;
+       }
+
+       return ret;
+}
+
+static int __devexit sport_uart_remove(struct platform_device *pdev)
+{
+       struct sport_uart_port *sport = platform_get_drvdata(pdev);
+
+       dev_dbg(&pdev->dev, "%s enter\n", __func__);
+       dev_set_drvdata(&pdev->dev, NULL);
+
+       if (sport) {
+               uart_remove_one_port(&sport_uart_reg, &sport->port);
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+               if (sport->rts_pin >= 0)
+                       gpio_free(sport->rts_pin);
+#endif
+               iounmap(sport->port.membase);
+               peripheral_free_list(
+                       (unsigned short *)pdev->dev.platform_data);
+               kfree(sport);
+               bfin_sport_uart_ports[pdev->id] = NULL;
+       }
+
+       return 0;
+}
+
+static struct platform_driver sport_uart_driver = {
+       .probe          = sport_uart_probe,
+       .remove         = __devexit_p(sport_uart_remove),
+       .driver         = {
+               .name   = DRV_NAME,
+#ifdef CONFIG_PM
+               .pm     = &bfin_sport_uart_dev_pm_ops,
+#endif
+       },
+};
+
+#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
+static __initdata struct early_platform_driver early_sport_uart_driver = {
+       .class_str = CLASS_BFIN_SPORT_CONSOLE,
+       .pdrv = &sport_uart_driver,
+       .requested_id = EARLY_PLATFORM_ID_UNSET,
+};
+
+static int __init sport_uart_rs_console_init(void)
+{
+       early_platform_driver_register(&early_sport_uart_driver, DRV_NAME);
+
+       early_platform_driver_probe(CLASS_BFIN_SPORT_CONSOLE,
+               BFIN_SPORT_UART_MAX_PORTS, 0);
+
+       register_console(&sport_uart_console);
+
+       return 0;
+}
+console_initcall(sport_uart_rs_console_init);
+#endif
+
+static int __init sport_uart_init(void)
+{
+       int ret;
+
+       pr_info("Blackfin uart over sport driver\n");
+
+       ret = uart_register_driver(&sport_uart_reg);
+       if (ret) {
+               pr_err("failed to register %s:%d\n",
+                               sport_uart_reg.driver_name, ret);
+               return ret;
+       }
+
+       ret = platform_driver_register(&sport_uart_driver);
+       if (ret) {
+               pr_err("failed to register sport uart driver:%d\n", ret);
+               uart_unregister_driver(&sport_uart_reg);
+       }
+
+       return ret;
+}
+module_init(sport_uart_init);
+
+static void __exit sport_uart_exit(void)
+{
+       platform_driver_unregister(&sport_uart_driver);
+       uart_unregister_driver(&sport_uart_reg);
+}
+module_exit(sport_uart_exit);
+
+MODULE_AUTHOR("Sonic Zhang, Roy Huang");
+MODULE_DESCRIPTION("Blackfin serial over SPORT driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/bfin_sport_uart.h b/drivers/tty/serial/bfin_sport_uart.h
new file mode 100644 (file)
index 0000000..6d06ce1
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Blackfin On-Chip Sport Emulated UART Driver
+ *
+ * Copyright 2006-2008 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+/*
+ * This driver and the hardware supported are in term of EE-191 of ADI.
+ * http://www.analog.com/static/imported-files/application_notes/EE191.pdf 
+ * This application note describe how to implement a UART on a Sharc DSP,
+ * but this driver is implemented on Blackfin Processor.
+ * Transmit Frame Sync is not used by this driver to transfer data out.
+ */
+
+#ifndef _BFIN_SPORT_UART_H
+#define _BFIN_SPORT_UART_H
+
+#define OFFSET_TCR1            0x00    /* Transmit Configuration 1 Register */
+#define OFFSET_TCR2            0x04    /* Transmit Configuration 2 Register */
+#define OFFSET_TCLKDIV         0x08    /* Transmit Serial Clock Divider Register */
+#define OFFSET_TFSDIV          0x0C    /* Transmit Frame Sync Divider Register */
+#define OFFSET_TX              0x10    /* Transmit Data Register               */
+#define OFFSET_RX              0x18    /* Receive Data Register                */
+#define OFFSET_RCR1            0x20    /* Receive Configuration 1 Register     */
+#define OFFSET_RCR2            0x24    /* Receive Configuration 2 Register     */
+#define OFFSET_RCLKDIV         0x28    /* Receive Serial Clock Divider Register */
+#define OFFSET_RFSDIV          0x2c    /* Receive Frame Sync Divider Register */
+#define OFFSET_STAT            0x30    /* Status Register                      */
+
+#define SPORT_GET_TCR1(sport)          bfin_read16(((sport)->port.membase + OFFSET_TCR1))
+#define SPORT_GET_TCR2(sport)          bfin_read16(((sport)->port.membase + OFFSET_TCR2))
+#define SPORT_GET_TCLKDIV(sport)       bfin_read16(((sport)->port.membase + OFFSET_TCLKDIV))
+#define SPORT_GET_TFSDIV(sport)                bfin_read16(((sport)->port.membase + OFFSET_TFSDIV))
+#define SPORT_GET_TX(sport)            bfin_read16(((sport)->port.membase + OFFSET_TX))
+#define SPORT_GET_RX(sport)            bfin_read16(((sport)->port.membase + OFFSET_RX))
+/*
+ * If another interrupt fires while doing a 32-bit read from RX FIFO,
+ * a fake RX underflow error will be generated.  So disable interrupts
+ * to prevent interruption while reading the FIFO.
+ */
+#define SPORT_GET_RX32(sport) \
+({ \
+       unsigned int __ret; \
+       if (ANOMALY_05000473) \
+               local_irq_disable(); \
+       __ret = bfin_read32((sport)->port.membase + OFFSET_RX); \
+       if (ANOMALY_05000473) \
+               local_irq_enable(); \
+       __ret; \
+})
+#define SPORT_GET_RCR1(sport)          bfin_read16(((sport)->port.membase + OFFSET_RCR1))
+#define SPORT_GET_RCR2(sport)          bfin_read16(((sport)->port.membase + OFFSET_RCR2))
+#define SPORT_GET_RCLKDIV(sport)       bfin_read16(((sport)->port.membase + OFFSET_RCLKDIV))
+#define SPORT_GET_RFSDIV(sport)                bfin_read16(((sport)->port.membase + OFFSET_RFSDIV))
+#define SPORT_GET_STAT(sport)          bfin_read16(((sport)->port.membase + OFFSET_STAT))
+
+#define SPORT_PUT_TCR1(sport, v)       bfin_write16(((sport)->port.membase + OFFSET_TCR1), v)
+#define SPORT_PUT_TCR2(sport, v)       bfin_write16(((sport)->port.membase + OFFSET_TCR2), v)
+#define SPORT_PUT_TCLKDIV(sport, v)    bfin_write16(((sport)->port.membase + OFFSET_TCLKDIV), v)
+#define SPORT_PUT_TFSDIV(sport, v)     bfin_write16(((sport)->port.membase + OFFSET_TFSDIV), v)
+#define SPORT_PUT_TX(sport, v)         bfin_write16(((sport)->port.membase + OFFSET_TX), v)
+#define SPORT_PUT_RX(sport, v)         bfin_write16(((sport)->port.membase + OFFSET_RX), v)
+#define SPORT_PUT_RCR1(sport, v)       bfin_write16(((sport)->port.membase + OFFSET_RCR1), v)
+#define SPORT_PUT_RCR2(sport, v)       bfin_write16(((sport)->port.membase + OFFSET_RCR2), v)
+#define SPORT_PUT_RCLKDIV(sport, v)    bfin_write16(((sport)->port.membase + OFFSET_RCLKDIV), v)
+#define SPORT_PUT_RFSDIV(sport, v)     bfin_write16(((sport)->port.membase + OFFSET_RFSDIV), v)
+#define SPORT_PUT_STAT(sport, v)       bfin_write16(((sport)->port.membase + OFFSET_STAT), v)
+
+#define SPORT_TX_FIFO_SIZE     8
+
+#define SPORT_UART_GET_CTS(x)          gpio_get_value(x->cts_pin)
+#define SPORT_UART_DISABLE_RTS(x)      gpio_set_value(x->rts_pin, 1)
+#define SPORT_UART_ENABLE_RTS(x)       gpio_set_value(x->rts_pin, 0)
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT0_UART_CTSRTS) \
+       || defined(CONFIG_SERIAL_BFIN_SPORT1_UART_CTSRTS) \
+       || defined(CONFIG_SERIAL_BFIN_SPORT2_UART_CTSRTS) \
+       || defined(CONFIG_SERIAL_BFIN_SPORT3_UART_CTSRTS)
+# define CONFIG_SERIAL_BFIN_SPORT_CTSRTS
+#endif
+
+#endif /* _BFIN_SPORT_UART_H */
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
new file mode 100644 (file)
index 0000000..b6acd19
--- /dev/null
@@ -0,0 +1,579 @@
+/*
+ *  linux/drivers/char/clps711x.c
+ *
+ *  Driver for CLPS711x serial ports
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ *  Copyright 1999 ARM Limited
+ *  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
+ */
+
+#if defined(CONFIG_SERIAL_CLPS711X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/hardware/clps7111.h>
+
+#define UART_NR                2
+
+#define SERIAL_CLPS711X_MAJOR  204
+#define SERIAL_CLPS711X_MINOR  40
+#define SERIAL_CLPS711X_NR     UART_NR
+
+/*
+ * We use the relevant SYSCON register as a base address for these ports.
+ */
+#define UBRLCR(port)           ((port)->iobase + UBRLCR1 - SYSCON1)
+#define UARTDR(port)           ((port)->iobase + UARTDR1 - SYSCON1)
+#define SYSFLG(port)           ((port)->iobase + SYSFLG1 - SYSCON1)
+#define SYSCON(port)           ((port)->iobase + SYSCON1 - SYSCON1)
+
+#define TX_IRQ(port)           ((port)->irq)
+#define RX_IRQ(port)           ((port)->irq + 1)
+
+#define UART_ANY_ERR           (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR)
+
+#define tx_enabled(port)       ((port)->unused[0])
+
+static void clps711xuart_stop_tx(struct uart_port *port)
+{
+       if (tx_enabled(port)) {
+               disable_irq(TX_IRQ(port));
+               tx_enabled(port) = 0;
+       }
+}
+
+static void clps711xuart_start_tx(struct uart_port *port)
+{
+       if (!tx_enabled(port)) {
+               enable_irq(TX_IRQ(port));
+               tx_enabled(port) = 1;
+       }
+}
+
+static void clps711xuart_stop_rx(struct uart_port *port)
+{
+       disable_irq(RX_IRQ(port));
+}
+
+static void clps711xuart_enable_ms(struct uart_port *port)
+{
+}
+
+static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       struct tty_struct *tty = port->state->port.tty;
+       unsigned int status, ch, flg;
+
+       status = clps_readl(SYSFLG(port));
+       while (!(status & SYSFLG_URXFE)) {
+               ch = clps_readl(UARTDR(port));
+
+               port->icount.rx++;
+
+               flg = TTY_NORMAL;
+
+               /*
+                * Note that the error handling code is
+                * out of the main execution path
+                */
+               if (unlikely(ch & UART_ANY_ERR)) {
+                       if (ch & UARTDR_PARERR)
+                               port->icount.parity++;
+                       else if (ch & UARTDR_FRMERR)
+                               port->icount.frame++;
+                       if (ch & UARTDR_OVERR)
+                               port->icount.overrun++;
+
+                       ch &= port->read_status_mask;
+
+                       if (ch & UARTDR_PARERR)
+                               flg = TTY_PARITY;
+                       else if (ch & UARTDR_FRMERR)
+                               flg = TTY_FRAME;
+
+#ifdef SUPPORT_SYSRQ
+                       port->sysrq = 0;
+#endif
+               }
+
+               if (uart_handle_sysrq_char(port, ch))
+                       goto ignore_char;
+
+               /*
+                * CHECK: does overrun affect the current character?
+                * ASSUMPTION: it does not.
+                */
+               uart_insert_char(port, ch, UARTDR_OVERR, ch, flg);
+
+       ignore_char:
+               status = clps_readl(SYSFLG(port));
+       }
+       tty_flip_buffer_push(tty);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       struct circ_buf *xmit = &port->state->xmit;
+       int count;
+
+       if (port->x_char) {
+               clps_writel(port->x_char, UARTDR(port));
+               port->icount.tx++;
+               port->x_char = 0;
+               return IRQ_HANDLED;
+       }
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               clps711xuart_stop_tx(port);
+               return IRQ_HANDLED;
+       }
+
+       count = port->fifosize >> 1;
+       do {
+               clps_writel(xmit->buf[xmit->tail], UARTDR(port));
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (--count > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit))
+               clps711xuart_stop_tx(port);
+
+       return IRQ_HANDLED;
+}
+
+static unsigned int clps711xuart_tx_empty(struct uart_port *port)
+{
+       unsigned int status = clps_readl(SYSFLG(port));
+       return status & SYSFLG_UBUSY ? 0 : TIOCSER_TEMT;
+}
+
+static unsigned int clps711xuart_get_mctrl(struct uart_port *port)
+{
+       unsigned int port_addr;
+       unsigned int result = 0;
+       unsigned int status;
+
+       port_addr = SYSFLG(port);
+       if (port_addr == SYSFLG1) {
+               status = clps_readl(SYSFLG1);
+               if (status & SYSFLG1_DCD)
+                       result |= TIOCM_CAR;
+               if (status & SYSFLG1_DSR)
+                       result |= TIOCM_DSR;
+               if (status & SYSFLG1_CTS)
+                       result |= TIOCM_CTS;
+       }
+
+       return result;
+}
+
+static void
+clps711xuart_set_mctrl_null(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static void clps711xuart_break_ctl(struct uart_port *port, int break_state)
+{
+       unsigned long flags;
+       unsigned int ubrlcr;
+
+       spin_lock_irqsave(&port->lock, flags);
+       ubrlcr = clps_readl(UBRLCR(port));
+       if (break_state == -1)
+               ubrlcr |= UBRLCR_BREAK;
+       else
+               ubrlcr &= ~UBRLCR_BREAK;
+       clps_writel(ubrlcr, UBRLCR(port));
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int clps711xuart_startup(struct uart_port *port)
+{
+       unsigned int syscon;
+       int retval;
+
+       tx_enabled(port) = 1;
+
+       /*
+        * Allocate the IRQs
+        */
+       retval = request_irq(TX_IRQ(port), clps711xuart_int_tx, 0,
+                            "clps711xuart_tx", port);
+       if (retval)
+               return retval;
+
+       retval = request_irq(RX_IRQ(port), clps711xuart_int_rx, 0,
+                            "clps711xuart_rx", port);
+       if (retval) {
+               free_irq(TX_IRQ(port), port);
+               return retval;
+       }
+
+       /*
+        * enable the port
+        */
+       syscon = clps_readl(SYSCON(port));
+       syscon |= SYSCON_UARTEN;
+       clps_writel(syscon, SYSCON(port));
+
+       return 0;
+}
+
+static void clps711xuart_shutdown(struct uart_port *port)
+{
+       unsigned int ubrlcr, syscon;
+
+       /*
+        * Free the interrupt
+        */
+       free_irq(TX_IRQ(port), port);   /* TX interrupt */
+       free_irq(RX_IRQ(port), port);   /* RX interrupt */
+
+       /*
+        * disable the port
+        */
+       syscon = clps_readl(SYSCON(port));
+       syscon &= ~SYSCON_UARTEN;
+       clps_writel(syscon, SYSCON(port));
+
+       /*
+        * disable break condition and fifos
+        */
+       ubrlcr = clps_readl(UBRLCR(port));
+       ubrlcr &= ~(UBRLCR_FIFOEN | UBRLCR_BREAK);
+       clps_writel(ubrlcr, UBRLCR(port));
+}
+
+static void
+clps711xuart_set_termios(struct uart_port *port, struct ktermios *termios,
+                        struct ktermios *old)
+{
+       unsigned int ubrlcr, baud, quot;
+       unsigned long flags;
+
+       /*
+        * We don't implement CREAD.
+        */
+       termios->c_cflag |= CREAD;
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
+       quot = uart_get_divisor(port, baud);
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               ubrlcr = UBRLCR_WRDLEN5;
+               break;
+       case CS6:
+               ubrlcr = UBRLCR_WRDLEN6;
+               break;
+       case CS7:
+               ubrlcr = UBRLCR_WRDLEN7;
+               break;
+       default: // CS8
+               ubrlcr = UBRLCR_WRDLEN8;
+               break;
+       }
+       if (termios->c_cflag & CSTOPB)
+               ubrlcr |= UBRLCR_XSTOP;
+       if (termios->c_cflag & PARENB) {
+               ubrlcr |= UBRLCR_PRTEN;
+               if (!(termios->c_cflag & PARODD))
+                       ubrlcr |= UBRLCR_EVENPRT;
+       }
+       if (port->fifosize > 1)
+               ubrlcr |= UBRLCR_FIFOEN;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       port->read_status_mask = UARTDR_OVERR;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= UARTDR_PARERR | UARTDR_FRMERR;
+
+       /*
+        * Characters to ignore
+        */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= UARTDR_FRMERR | UARTDR_PARERR;
+       if (termios->c_iflag & IGNBRK) {
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns to (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       port->ignore_status_mask |= UARTDR_OVERR;
+       }
+
+       quot -= 1;
+
+       clps_writel(ubrlcr | quot, UBRLCR(port));
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *clps711xuart_type(struct uart_port *port)
+{
+       return port->type == PORT_CLPS711X ? "CLPS711x" : NULL;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void clps711xuart_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE)
+               port->type = PORT_CLPS711X;
+}
+
+static void clps711xuart_release_port(struct uart_port *port)
+{
+}
+
+static int clps711xuart_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static struct uart_ops clps711x_pops = {
+       .tx_empty       = clps711xuart_tx_empty,
+       .set_mctrl      = clps711xuart_set_mctrl_null,
+       .get_mctrl      = clps711xuart_get_mctrl,
+       .stop_tx        = clps711xuart_stop_tx,
+       .start_tx       = clps711xuart_start_tx,
+       .stop_rx        = clps711xuart_stop_rx,
+       .enable_ms      = clps711xuart_enable_ms,
+       .break_ctl      = clps711xuart_break_ctl,
+       .startup        = clps711xuart_startup,
+       .shutdown       = clps711xuart_shutdown,
+       .set_termios    = clps711xuart_set_termios,
+       .type           = clps711xuart_type,
+       .config_port    = clps711xuart_config_port,
+       .release_port   = clps711xuart_release_port,
+       .request_port   = clps711xuart_request_port,
+};
+
+static struct uart_port clps711x_ports[UART_NR] = {
+       {
+               .iobase         = SYSCON1,
+               .irq            = IRQ_UTXINT1, /* IRQ_URXINT1, IRQ_UMSINT */
+               .uartclk        = 3686400,
+               .fifosize       = 16,
+               .ops            = &clps711x_pops,
+               .line           = 0,
+               .flags          = UPF_BOOT_AUTOCONF,
+       },
+       {
+               .iobase         = SYSCON2,
+               .irq            = IRQ_UTXINT2, /* IRQ_URXINT2 */
+               .uartclk        = 3686400,
+               .fifosize       = 16,
+               .ops            = &clps711x_pops,
+               .line           = 1,
+               .flags          = UPF_BOOT_AUTOCONF,
+       }
+};
+
+#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
+static void clps711xuart_console_putchar(struct uart_port *port, int ch)
+{
+       while (clps_readl(SYSFLG(port)) & SYSFLG_UTXFF)
+               barrier();
+       clps_writel(ch, UARTDR(port));
+}
+
+/*
+ *     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
+clps711xuart_console_write(struct console *co, const char *s,
+                          unsigned int count)
+{
+       struct uart_port *port = clps711x_ports + co->index;
+       unsigned int status, syscon;
+
+       /*
+        *      Ensure that the port is enabled.
+        */
+       syscon = clps_readl(SYSCON(port));
+       clps_writel(syscon | SYSCON_UARTEN, SYSCON(port));
+
+       uart_console_write(port, s, count, clps711xuart_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the uart state.
+        */
+       do {
+               status = clps_readl(SYSFLG(port));
+       } while (status & SYSFLG_UBUSY);
+
+       clps_writel(syscon, SYSCON(port));
+}
+
+static void __init
+clps711xuart_console_get_options(struct uart_port *port, int *baud,
+                                int *parity, int *bits)
+{
+       if (clps_readl(SYSCON(port)) & SYSCON_UARTEN) {
+               unsigned int ubrlcr, quot;
+
+               ubrlcr = clps_readl(UBRLCR(port));
+
+               *parity = 'n';
+               if (ubrlcr & UBRLCR_PRTEN) {
+                       if (ubrlcr & UBRLCR_EVENPRT)
+                               *parity = 'e';
+                       else
+                               *parity = 'o';
+               }
+
+               if ((ubrlcr & UBRLCR_WRDLEN_MASK) == UBRLCR_WRDLEN7)
+                       *bits = 7;
+               else
+                       *bits = 8;
+
+               quot = ubrlcr & UBRLCR_BAUD_MASK;
+               *baud = port->uartclk / (16 * (quot + 1));
+       }
+}
+
+static int __init clps711xuart_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(clps711x_ports, UART_NR, co);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               clps711xuart_console_get_options(port, &baud, &parity, &bits);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver clps711x_reg;
+static struct console clps711x_console = {
+       .name           = "ttyCL",
+       .write          = clps711xuart_console_write,
+       .device         = uart_console_device,
+       .setup          = clps711xuart_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &clps711x_reg,
+};
+
+static int __init clps711xuart_console_init(void)
+{
+       register_console(&clps711x_console);
+       return 0;
+}
+console_initcall(clps711xuart_console_init);
+
+#define CLPS711X_CONSOLE       &clps711x_console
+#else
+#define CLPS711X_CONSOLE       NULL
+#endif
+
+static struct uart_driver clps711x_reg = {
+       .driver_name            = "ttyCL",
+       .dev_name               = "ttyCL",
+       .major                  = SERIAL_CLPS711X_MAJOR,
+       .minor                  = SERIAL_CLPS711X_MINOR,
+       .nr                     = UART_NR,
+
+       .cons                   = CLPS711X_CONSOLE,
+};
+
+static int __init clps711xuart_init(void)
+{
+       int ret, i;
+
+       printk(KERN_INFO "Serial: CLPS711x driver\n");
+
+       ret = uart_register_driver(&clps711x_reg);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < UART_NR; i++)
+               uart_add_one_port(&clps711x_reg, &clps711x_ports[i]);
+
+       return 0;
+}
+
+static void __exit clps711xuart_exit(void)
+{
+       int i;
+
+       for (i = 0; i < UART_NR; i++)
+               uart_remove_one_port(&clps711x_reg, &clps711x_ports[i]);
+
+       uart_unregister_driver(&clps711x_reg);
+}
+
+module_init(clps711xuart_init);
+module_exit(clps711xuart_exit);
+
+MODULE_AUTHOR("Deep Blue Solutions Ltd");
+MODULE_DESCRIPTION("CLPS-711x generic serial driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV(SERIAL_CLPS711X_MAJOR, SERIAL_CLPS711X_MINOR);
diff --git a/drivers/tty/serial/cpm_uart/Makefile b/drivers/tty/serial/cpm_uart/Makefile
new file mode 100644 (file)
index 0000000..e072724
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# Makefile for the Motorola 8xx FEC ethernet controller
+#
+
+obj-$(CONFIG_SERIAL_CPM) += cpm_uart.o
+
+# Select the correct platform objects.
+cpm_uart-objs-$(CONFIG_CPM2)   += cpm_uart_cpm2.o
+cpm_uart-objs-$(CONFIG_8xx)    += cpm_uart_cpm1.o
+
+cpm_uart-objs  := cpm_uart_core.o $(cpm_uart-objs-y)
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart.h b/drivers/tty/serial/cpm_uart/cpm_uart.h
new file mode 100644 (file)
index 0000000..b754dcf
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ *  linux/drivers/serial/cpm_uart.h
+ *
+ *  Driver for CPM (SCC/SMC) serial ports
+ *
+ *  Copyright (C) 2004 Freescale Semiconductor, Inc.
+ *
+ *  2006 (c) MontaVista Software, Inc.
+ *     Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+#ifndef CPM_UART_H
+#define CPM_UART_H
+
+#include <linux/platform_device.h>
+#include <linux/fs_uart_pd.h>
+
+#if defined(CONFIG_CPM2)
+#include "cpm_uart_cpm2.h"
+#elif defined(CONFIG_8xx)
+#include "cpm_uart_cpm1.h"
+#endif
+
+#define SERIAL_CPM_MAJOR       204
+#define SERIAL_CPM_MINOR       46
+
+#define IS_SMC(pinfo)          (pinfo->flags & FLAG_SMC)
+#define IS_DISCARDING(pinfo)   (pinfo->flags & FLAG_DISCARDING)
+#define FLAG_DISCARDING        0x00000004      /* when set, don't discard */
+#define FLAG_SMC       0x00000002
+#define FLAG_CONSOLE   0x00000001
+
+#define UART_SMC1      fsid_smc1_uart
+#define UART_SMC2      fsid_smc2_uart
+#define UART_SCC1      fsid_scc1_uart
+#define UART_SCC2      fsid_scc2_uart
+#define UART_SCC3      fsid_scc3_uart
+#define UART_SCC4      fsid_scc4_uart
+
+#define UART_NR                fs_uart_nr
+
+#define RX_NUM_FIFO    4
+#define RX_BUF_SIZE    32
+#define TX_NUM_FIFO    4
+#define TX_BUF_SIZE    32
+
+#define SCC_WAIT_CLOSING 100
+
+#define GPIO_CTS       0
+#define GPIO_RTS       1
+#define GPIO_DCD       2
+#define GPIO_DSR       3
+#define GPIO_DTR       4
+#define GPIO_RI                5
+
+#define NUM_GPIOS      (GPIO_RI+1)
+
+struct uart_cpm_port {
+       struct uart_port        port;
+       u16                     rx_nrfifos;
+       u16                     rx_fifosize;
+       u16                     tx_nrfifos;
+       u16                     tx_fifosize;
+       smc_t __iomem           *smcp;
+       smc_uart_t __iomem      *smcup;
+       scc_t __iomem           *sccp;
+       scc_uart_t __iomem      *sccup;
+       cbd_t __iomem           *rx_bd_base;
+       cbd_t __iomem           *rx_cur;
+       cbd_t __iomem           *tx_bd_base;
+       cbd_t __iomem           *tx_cur;
+       unsigned char           *tx_buf;
+       unsigned char           *rx_buf;
+       u32                     flags;
+       struct clk              *clk;
+       u8                      brg;
+       uint                     dp_addr;
+       void                    *mem_addr;
+       dma_addr_t               dma_addr;
+       u32                     mem_size;
+       /* wait on close if needed */
+       int                     wait_closing;
+       /* value to combine with opcode to form cpm command */
+       u32                     command;
+       int                     gpios[NUM_GPIOS];
+};
+
+extern int cpm_uart_nr;
+extern struct uart_cpm_port cpm_uart_ports[UART_NR];
+
+/* these are located in their respective files */
+void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd);
+void __iomem *cpm_uart_map_pram(struct uart_cpm_port *port,
+                               struct device_node *np);
+void cpm_uart_unmap_pram(struct uart_cpm_port *port, void __iomem *pram);
+int cpm_uart_init_portdesc(void);
+int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con);
+void cpm_uart_freebuf(struct uart_cpm_port *pinfo);
+
+void smc1_lineif(struct uart_cpm_port *pinfo);
+void smc2_lineif(struct uart_cpm_port *pinfo);
+void scc1_lineif(struct uart_cpm_port *pinfo);
+void scc2_lineif(struct uart_cpm_port *pinfo);
+void scc3_lineif(struct uart_cpm_port *pinfo);
+void scc4_lineif(struct uart_cpm_port *pinfo);
+
+/*
+   virtual to phys transtalion
+*/
+static inline unsigned long cpu2cpm_addr(void *addr,
+                                         struct uart_cpm_port *pinfo)
+{
+       int offset;
+       u32 val = (u32)addr;
+       u32 mem = (u32)pinfo->mem_addr;
+       /* sane check */
+       if (likely(val >= mem && val < mem + pinfo->mem_size)) {
+               offset = val - mem;
+               return pinfo->dma_addr + offset;
+       }
+       /* something nasty happened */
+       BUG();
+       return 0;
+}
+
+static inline void *cpm2cpu_addr(unsigned long addr,
+                                 struct uart_cpm_port *pinfo)
+{
+       int offset;
+       u32 val = addr;
+       u32 dma = (u32)pinfo->dma_addr;
+       /* sane check */
+       if (likely(val >= dma && val < dma + pinfo->mem_size)) {
+               offset = val - dma;
+               return pinfo->mem_addr + offset;
+       }
+       /* something nasty happened */
+       BUG();
+       return NULL;
+}
+
+
+#endif /* CPM_UART_H */
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
new file mode 100644 (file)
index 0000000..8692ff9
--- /dev/null
@@ -0,0 +1,1443 @@
+/*
+ *  linux/drivers/serial/cpm_uart.c
+ *
+ *  Driver for CPM (SCC/SMC) serial ports; core driver
+ *
+ *  Based on arch/ppc/cpm2_io/uart.c by Dan Malek
+ *  Based on ppc8xx.c by Thomas Gleixner
+ *  Based on drivers/serial/amba.c by Russell King
+ *
+ *  Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2)
+ *              Pantelis Antoniou (panto@intracom.gr) (CPM1)
+ *
+ *  Copyright (C) 2004, 2007 Freescale Semiconductor, Inc.
+ *            (C) 2004 Intracom, S.A.
+ *            (C) 2005-2006 MontaVista Software, Inc.
+ *             Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * 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/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+#include <linux/bootmem.h>
+#include <linux/dma-mapping.h>
+#include <linux/fs_uart_pd.h>
+#include <linux/of_platform.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/delay.h>
+#include <asm/fs_pd.h>
+#include <asm/udbg.h>
+
+#if defined(CONFIG_SERIAL_CPM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+#include <linux/kernel.h>
+
+#include "cpm_uart.h"
+
+
+/**************************************************************/
+
+static int  cpm_uart_tx_pump(struct uart_port *port);
+static void cpm_uart_init_smc(struct uart_cpm_port *pinfo);
+static void cpm_uart_init_scc(struct uart_cpm_port *pinfo);
+static void cpm_uart_initbd(struct uart_cpm_port *pinfo);
+
+/**************************************************************/
+
+#define HW_BUF_SPD_THRESHOLD    9600
+
+/*
+ * Check, if transmit buffers are processed
+*/
+static unsigned int cpm_uart_tx_empty(struct uart_port *port)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       cbd_t __iomem *bdp = pinfo->tx_bd_base;
+       int ret = 0;
+
+       while (1) {
+               if (in_be16(&bdp->cbd_sc) & BD_SC_READY)
+                       break;
+
+               if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) {
+                       ret = TIOCSER_TEMT;
+                       break;
+               }
+               bdp++;
+       }
+
+       pr_debug("CPM uart[%d]:tx_empty: %d\n", port->line, ret);
+
+       return ret;
+}
+
+static void cpm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+
+       if (pinfo->gpios[GPIO_RTS] >= 0)
+               gpio_set_value(pinfo->gpios[GPIO_RTS], !(mctrl & TIOCM_RTS));
+
+       if (pinfo->gpios[GPIO_DTR] >= 0)
+               gpio_set_value(pinfo->gpios[GPIO_DTR], !(mctrl & TIOCM_DTR));
+}
+
+static unsigned int cpm_uart_get_mctrl(struct uart_port *port)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       unsigned int mctrl = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+
+       if (pinfo->gpios[GPIO_CTS] >= 0) {
+               if (gpio_get_value(pinfo->gpios[GPIO_CTS]))
+                       mctrl &= ~TIOCM_CTS;
+       }
+
+       if (pinfo->gpios[GPIO_DSR] >= 0) {
+               if (gpio_get_value(pinfo->gpios[GPIO_DSR]))
+                       mctrl &= ~TIOCM_DSR;
+       }
+
+       if (pinfo->gpios[GPIO_DCD] >= 0) {
+               if (gpio_get_value(pinfo->gpios[GPIO_DCD]))
+                       mctrl &= ~TIOCM_CAR;
+       }
+
+       if (pinfo->gpios[GPIO_RI] >= 0) {
+               if (!gpio_get_value(pinfo->gpios[GPIO_RI]))
+                       mctrl |= TIOCM_RNG;
+       }
+
+       return mctrl;
+}
+
+/*
+ * Stop transmitter
+ */
+static void cpm_uart_stop_tx(struct uart_port *port)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       smc_t __iomem *smcp = pinfo->smcp;
+       scc_t __iomem *sccp = pinfo->sccp;
+
+       pr_debug("CPM uart[%d]:stop tx\n", port->line);
+
+       if (IS_SMC(pinfo))
+               clrbits8(&smcp->smc_smcm, SMCM_TX);
+       else
+               clrbits16(&sccp->scc_sccm, UART_SCCM_TX);
+}
+
+/*
+ * Start transmitter
+ */
+static void cpm_uart_start_tx(struct uart_port *port)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       smc_t __iomem *smcp = pinfo->smcp;
+       scc_t __iomem *sccp = pinfo->sccp;
+
+       pr_debug("CPM uart[%d]:start tx\n", port->line);
+
+       if (IS_SMC(pinfo)) {
+               if (in_8(&smcp->smc_smcm) & SMCM_TX)
+                       return;
+       } else {
+               if (in_be16(&sccp->scc_sccm) & UART_SCCM_TX)
+                       return;
+       }
+
+       if (cpm_uart_tx_pump(port) != 0) {
+               if (IS_SMC(pinfo)) {
+                       setbits8(&smcp->smc_smcm, SMCM_TX);
+               } else {
+                       setbits16(&sccp->scc_sccm, UART_SCCM_TX);
+               }
+       }
+}
+
+/*
+ * Stop receiver
+ */
+static void cpm_uart_stop_rx(struct uart_port *port)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       smc_t __iomem *smcp = pinfo->smcp;
+       scc_t __iomem *sccp = pinfo->sccp;
+
+       pr_debug("CPM uart[%d]:stop rx\n", port->line);
+
+       if (IS_SMC(pinfo))
+               clrbits8(&smcp->smc_smcm, SMCM_RX);
+       else
+               clrbits16(&sccp->scc_sccm, UART_SCCM_RX);
+}
+
+/*
+ * Enable Modem status interrupts
+ */
+static void cpm_uart_enable_ms(struct uart_port *port)
+{
+       pr_debug("CPM uart[%d]:enable ms\n", port->line);
+}
+
+/*
+ * Generate a break.
+ */
+static void cpm_uart_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+
+       pr_debug("CPM uart[%d]:break ctrl, break_state: %d\n", port->line,
+               break_state);
+
+       if (break_state)
+               cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX);
+       else
+               cpm_line_cr_cmd(pinfo, CPM_CR_RESTART_TX);
+}
+
+/*
+ * Transmit characters, refill buffer descriptor, if possible
+ */
+static void cpm_uart_int_tx(struct uart_port *port)
+{
+       pr_debug("CPM uart[%d]:TX INT\n", port->line);
+
+       cpm_uart_tx_pump(port);
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+static int serial_polled;
+#endif
+
+/*
+ * Receive characters
+ */
+static void cpm_uart_int_rx(struct uart_port *port)
+{
+       int i;
+       unsigned char ch;
+       u8 *cp;
+       struct tty_struct *tty = port->state->port.tty;
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       cbd_t __iomem *bdp;
+       u16 status;
+       unsigned int flg;
+
+       pr_debug("CPM uart[%d]:RX INT\n", port->line);
+
+       /* Just loop through the closed BDs and copy the characters into
+        * the buffer.
+        */
+       bdp = pinfo->rx_cur;
+       for (;;) {
+#ifdef CONFIG_CONSOLE_POLL
+               if (unlikely(serial_polled)) {
+                       serial_polled = 0;
+                       return;
+               }
+#endif
+               /* get status */
+               status = in_be16(&bdp->cbd_sc);
+               /* If this one is empty, return happy */
+               if (status & BD_SC_EMPTY)
+                       break;
+
+               /* get number of characters, and check spce in flip-buffer */
+               i = in_be16(&bdp->cbd_datlen);
+
+               /* If we have not enough room in tty flip buffer, then we try
+                * later, which will be the next rx-interrupt or a timeout
+                */
+               if(tty_buffer_request_room(tty, i) < i) {
+                       printk(KERN_WARNING "No room in flip buffer\n");
+                       return;
+               }
+
+               /* get pointer */
+               cp = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
+
+               /* loop through the buffer */
+               while (i-- > 0) {
+                       ch = *cp++;
+                       port->icount.rx++;
+                       flg = TTY_NORMAL;
+
+                       if (status &
+                           (BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV))
+                               goto handle_error;
+                       if (uart_handle_sysrq_char(port, ch))
+                               continue;
+#ifdef CONFIG_CONSOLE_POLL
+                       if (unlikely(serial_polled)) {
+                               serial_polled = 0;
+                               return;
+                       }
+#endif
+                     error_return:
+                       tty_insert_flip_char(tty, ch, flg);
+
+               }               /* End while (i--) */
+
+               /* This BD is ready to be used again. Clear status. get next */
+               clrbits16(&bdp->cbd_sc, BD_SC_BR | BD_SC_FR | BD_SC_PR |
+                                       BD_SC_OV | BD_SC_ID);
+               setbits16(&bdp->cbd_sc, BD_SC_EMPTY);
+
+               if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
+                       bdp = pinfo->rx_bd_base;
+               else
+                       bdp++;
+
+       } /* End for (;;) */
+
+       /* Write back buffer pointer */
+       pinfo->rx_cur = bdp;
+
+       /* activate BH processing */
+       tty_flip_buffer_push(tty);
+
+       return;
+
+       /* Error processing */
+
+      handle_error:
+       /* Statistics */
+       if (status & BD_SC_BR)
+               port->icount.brk++;
+       if (status & BD_SC_PR)
+               port->icount.parity++;
+       if (status & BD_SC_FR)
+               port->icount.frame++;
+       if (status & BD_SC_OV)
+               port->icount.overrun++;
+
+       /* Mask out ignored conditions */
+       status &= port->read_status_mask;
+
+       /* Handle the remaining ones */
+       if (status & BD_SC_BR)
+               flg = TTY_BREAK;
+       else if (status & BD_SC_PR)
+               flg = TTY_PARITY;
+       else if (status & BD_SC_FR)
+               flg = TTY_FRAME;
+
+       /* overrun does not affect the current character ! */
+       if (status & BD_SC_OV) {
+               ch = 0;
+               flg = TTY_OVERRUN;
+               /* We skip this buffer */
+               /* CHECK: Is really nothing senseful there */
+               /* ASSUMPTION: it contains nothing valid */
+               i = 0;
+       }
+#ifdef SUPPORT_SYSRQ
+       port->sysrq = 0;
+#endif
+       goto error_return;
+}
+
+/*
+ * Asynchron mode interrupt handler
+ */
+static irqreturn_t cpm_uart_int(int irq, void *data)
+{
+       u8 events;
+       struct uart_port *port = data;
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       smc_t __iomem *smcp = pinfo->smcp;
+       scc_t __iomem *sccp = pinfo->sccp;
+
+       pr_debug("CPM uart[%d]:IRQ\n", port->line);
+
+       if (IS_SMC(pinfo)) {
+               events = in_8(&smcp->smc_smce);
+               out_8(&smcp->smc_smce, events);
+               if (events & SMCM_BRKE)
+                       uart_handle_break(port);
+               if (events & SMCM_RX)
+                       cpm_uart_int_rx(port);
+               if (events & SMCM_TX)
+                       cpm_uart_int_tx(port);
+       } else {
+               events = in_be16(&sccp->scc_scce);
+               out_be16(&sccp->scc_scce, events);
+               if (events & UART_SCCM_BRKE)
+                       uart_handle_break(port);
+               if (events & UART_SCCM_RX)
+                       cpm_uart_int_rx(port);
+               if (events & UART_SCCM_TX)
+                       cpm_uart_int_tx(port);
+       }
+       return (events) ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int cpm_uart_startup(struct uart_port *port)
+{
+       int retval;
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+
+       pr_debug("CPM uart[%d]:startup\n", port->line);
+
+       /* If the port is not the console, make sure rx is disabled. */
+       if (!(pinfo->flags & FLAG_CONSOLE)) {
+               /* Disable UART rx */
+               if (IS_SMC(pinfo)) {
+                       clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN);
+                       clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX);
+               } else {
+                       clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR);
+                       clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_RX);
+               }
+               cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
+       }
+       /* Install interrupt handler. */
+       retval = request_irq(port->irq, cpm_uart_int, 0, "cpm_uart", port);
+       if (retval)
+               return retval;
+
+       /* Startup rx-int */
+       if (IS_SMC(pinfo)) {
+               setbits8(&pinfo->smcp->smc_smcm, SMCM_RX);
+               setbits16(&pinfo->smcp->smc_smcmr, (SMCMR_REN | SMCMR_TEN));
+       } else {
+               setbits16(&pinfo->sccp->scc_sccm, UART_SCCM_RX);
+               setbits32(&pinfo->sccp->scc_gsmrl, (SCC_GSMRL_ENR | SCC_GSMRL_ENT));
+       }
+
+       return 0;
+}
+
+inline void cpm_uart_wait_until_send(struct uart_cpm_port *pinfo)
+{
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       schedule_timeout(pinfo->wait_closing);
+}
+
+/*
+ * Shutdown the uart
+ */
+static void cpm_uart_shutdown(struct uart_port *port)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+
+       pr_debug("CPM uart[%d]:shutdown\n", port->line);
+
+       /* free interrupt handler */
+       free_irq(port->irq, port);
+
+       /* If the port is not the console, disable Rx and Tx. */
+       if (!(pinfo->flags & FLAG_CONSOLE)) {
+               /* Wait for all the BDs marked sent */
+               while(!cpm_uart_tx_empty(port)) {
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       schedule_timeout(2);
+               }
+
+               if (pinfo->wait_closing)
+                       cpm_uart_wait_until_send(pinfo);
+
+               /* Stop uarts */
+               if (IS_SMC(pinfo)) {
+                       smc_t __iomem *smcp = pinfo->smcp;
+                       clrbits16(&smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
+                       clrbits8(&smcp->smc_smcm, SMCM_RX | SMCM_TX);
+               } else {
+                       scc_t __iomem *sccp = pinfo->sccp;
+                       clrbits32(&sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+                       clrbits16(&sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX);
+               }
+
+               /* Shut them really down and reinit buffer descriptors */
+               if (IS_SMC(pinfo)) {
+                       out_be16(&pinfo->smcup->smc_brkcr, 0);
+                       cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX);
+               } else {
+                       out_be16(&pinfo->sccup->scc_brkcr, 0);
+                       cpm_line_cr_cmd(pinfo, CPM_CR_GRA_STOP_TX);
+               }
+
+               cpm_uart_initbd(pinfo);
+       }
+}
+
+static void cpm_uart_set_termios(struct uart_port *port,
+                                 struct ktermios *termios,
+                                 struct ktermios *old)
+{
+       int baud;
+       unsigned long flags;
+       u16 cval, scval, prev_mode;
+       int bits, sbits;
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       smc_t __iomem *smcp = pinfo->smcp;
+       scc_t __iomem *sccp = pinfo->sccp;
+
+       pr_debug("CPM uart[%d]:set_termios\n", port->line);
+
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
+       if (baud <= HW_BUF_SPD_THRESHOLD ||
+           (pinfo->port.state && pinfo->port.state->port.tty->low_latency))
+               pinfo->rx_fifosize = 1;
+       else
+               pinfo->rx_fifosize = RX_BUF_SIZE;
+
+       /* Character length programmed into the mode register is the
+        * sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
+        * 1 or 2 stop bits, minus 1.
+        * The value 'bits' counts this for us.
+        */
+       cval = 0;
+       scval = 0;
+
+       /* byte size */
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               bits = 5;
+               break;
+       case CS6:
+               bits = 6;
+               break;
+       case CS7:
+               bits = 7;
+               break;
+       case CS8:
+               bits = 8;
+               break;
+               /* Never happens, but GCC is too dumb to figure it out */
+       default:
+               bits = 8;
+               break;
+       }
+       sbits = bits - 5;
+
+       if (termios->c_cflag & CSTOPB) {
+               cval |= SMCMR_SL;       /* Two stops */
+               scval |= SCU_PSMR_SL;
+               bits++;
+       }
+
+       if (termios->c_cflag & PARENB) {
+               cval |= SMCMR_PEN;
+               scval |= SCU_PSMR_PEN;
+               bits++;
+               if (!(termios->c_cflag & PARODD)) {
+                       cval |= SMCMR_PM_EVEN;
+                       scval |= (SCU_PSMR_REVP | SCU_PSMR_TEVP);
+               }
+       }
+
+       /*
+        * Update the timeout
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       /*
+        * Set up parity check flag
+        */
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+       port->read_status_mask = (BD_SC_EMPTY | BD_SC_OV);
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= BD_SC_FR | BD_SC_PR;
+       if ((termios->c_iflag & BRKINT) || (termios->c_iflag & PARMRK))
+               port->read_status_mask |= BD_SC_BR;
+
+       /*
+        * Characters to ignore
+        */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= BD_SC_PR | BD_SC_FR;
+       if (termios->c_iflag & IGNBRK) {
+               port->ignore_status_mask |= BD_SC_BR;
+               /*
+                * If we're ignore parity and break indicators, ignore
+                * overruns too.  (For real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       port->ignore_status_mask |= BD_SC_OV;
+       }
+       /*
+        * !!! ignore all characters if CREAD is not set
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               port->read_status_mask &= ~BD_SC_EMPTY;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Start bit has not been added (so don't, because we would just
+        * subtract it later), and we need to add one for the number of
+        * stops bits (there is always at least one).
+        */
+       bits++;
+       if (IS_SMC(pinfo)) {
+               /*
+                * MRBLR can be changed while an SMC/SCC is operating only
+                * if it is done in a single bus cycle with one 16-bit move
+                * (not two 8-bit bus cycles back-to-back). This occurs when
+                * the cp shifts control to the next RxBD, so the change does
+                * not take effect immediately. To guarantee the exact RxBD
+                * on which the change occurs, change MRBLR only while the
+                * SMC/SCC receiver is disabled.
+                */
+               out_be16(&pinfo->smcup->smc_mrblr, pinfo->rx_fifosize);
+
+               /* Set the mode register.  We want to keep a copy of the
+                * enables, because we want to put them back if they were
+                * present.
+                */
+               prev_mode = in_be16(&smcp->smc_smcmr) & (SMCMR_REN | SMCMR_TEN);
+               /* Output in *one* operation, so we don't interrupt RX/TX if they
+                * were already enabled. */
+               out_be16(&smcp->smc_smcmr, smcr_mk_clen(bits) | cval |
+                   SMCMR_SM_UART | prev_mode);
+       } else {
+               out_be16(&pinfo->sccup->scc_genscc.scc_mrblr, pinfo->rx_fifosize);
+               out_be16(&sccp->scc_psmr, (sbits << 12) | scval);
+       }
+
+       if (pinfo->clk)
+               clk_set_rate(pinfo->clk, baud);
+       else
+               cpm_set_brg(pinfo->brg - 1, baud);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *cpm_uart_type(struct uart_port *port)
+{
+       pr_debug("CPM uart[%d]:uart_type\n", port->line);
+
+       return port->type == PORT_CPM ? "CPM UART" : NULL;
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int cpm_uart_verify_port(struct uart_port *port,
+                               struct serial_struct *ser)
+{
+       int ret = 0;
+
+       pr_debug("CPM uart[%d]:verify_port\n", port->line);
+
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_CPM)
+               ret = -EINVAL;
+       if (ser->irq < 0 || ser->irq >= nr_irqs)
+               ret = -EINVAL;
+       if (ser->baud_base < 9600)
+               ret = -EINVAL;
+       return ret;
+}
+
+/*
+ * Transmit characters, refill buffer descriptor, if possible
+ */
+static int cpm_uart_tx_pump(struct uart_port *port)
+{
+       cbd_t __iomem *bdp;
+       u8 *p;
+       int count;
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       struct circ_buf *xmit = &port->state->xmit;
+
+       /* Handle xon/xoff */
+       if (port->x_char) {
+               /* Pick next descriptor and fill from buffer */
+               bdp = pinfo->tx_cur;
+
+               p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
+
+               *p++ = port->x_char;
+
+               out_be16(&bdp->cbd_datlen, 1);
+               setbits16(&bdp->cbd_sc, BD_SC_READY);
+               /* Get next BD. */
+               if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
+                       bdp = pinfo->tx_bd_base;
+               else
+                       bdp++;
+               pinfo->tx_cur = bdp;
+
+               port->icount.tx++;
+               port->x_char = 0;
+               return 1;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               cpm_uart_stop_tx(port);
+               return 0;
+       }
+
+       /* Pick next descriptor and fill from buffer */
+       bdp = pinfo->tx_cur;
+
+       while (!(in_be16(&bdp->cbd_sc) & BD_SC_READY) &&
+              xmit->tail != xmit->head) {
+               count = 0;
+               p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
+               while (count < pinfo->tx_fifosize) {
+                       *p++ = xmit->buf[xmit->tail];
+                       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+                       port->icount.tx++;
+                       count++;
+                       if (xmit->head == xmit->tail)
+                               break;
+               }
+               out_be16(&bdp->cbd_datlen, count);
+               setbits16(&bdp->cbd_sc, BD_SC_READY);
+               /* Get next BD. */
+               if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
+                       bdp = pinfo->tx_bd_base;
+               else
+                       bdp++;
+       }
+       pinfo->tx_cur = bdp;
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit)) {
+               cpm_uart_stop_tx(port);
+               return 0;
+       }
+
+       return 1;
+}
+
+/*
+ * init buffer descriptors
+ */
+static void cpm_uart_initbd(struct uart_cpm_port *pinfo)
+{
+       int i;
+       u8 *mem_addr;
+       cbd_t __iomem *bdp;
+
+       pr_debug("CPM uart[%d]:initbd\n", pinfo->port.line);
+
+       /* Set the physical address of the host memory
+        * buffers in the buffer descriptors, and the
+        * virtual address for us to work with.
+        */
+       mem_addr = pinfo->mem_addr;
+       bdp = pinfo->rx_cur = pinfo->rx_bd_base;
+       for (i = 0; i < (pinfo->rx_nrfifos - 1); i++, bdp++) {
+               out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
+               out_be16(&bdp->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT);
+               mem_addr += pinfo->rx_fifosize;
+       }
+
+       out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
+       out_be16(&bdp->cbd_sc, BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT);
+
+       /* Set the physical address of the host memory
+        * buffers in the buffer descriptors, and the
+        * virtual address for us to work with.
+        */
+       mem_addr = pinfo->mem_addr + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize);
+       bdp = pinfo->tx_cur = pinfo->tx_bd_base;
+       for (i = 0; i < (pinfo->tx_nrfifos - 1); i++, bdp++) {
+               out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
+               out_be16(&bdp->cbd_sc, BD_SC_INTRPT);
+               mem_addr += pinfo->tx_fifosize;
+       }
+
+       out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
+       out_be16(&bdp->cbd_sc, BD_SC_WRAP | BD_SC_INTRPT);
+}
+
+static void cpm_uart_init_scc(struct uart_cpm_port *pinfo)
+{
+       scc_t __iomem *scp;
+       scc_uart_t __iomem *sup;
+
+       pr_debug("CPM uart[%d]:init_scc\n", pinfo->port.line);
+
+       scp = pinfo->sccp;
+       sup = pinfo->sccup;
+
+       /* Store address */
+       out_be16(&pinfo->sccup->scc_genscc.scc_rbase,
+                (u8 __iomem *)pinfo->rx_bd_base - DPRAM_BASE);
+       out_be16(&pinfo->sccup->scc_genscc.scc_tbase,
+                (u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE);
+
+       /* Set up the uart parameters in the
+        * parameter ram.
+        */
+
+       cpm_set_scc_fcr(sup);
+
+       out_be16(&sup->scc_genscc.scc_mrblr, pinfo->rx_fifosize);
+       out_be16(&sup->scc_maxidl, pinfo->rx_fifosize);
+       out_be16(&sup->scc_brkcr, 1);
+       out_be16(&sup->scc_parec, 0);
+       out_be16(&sup->scc_frmec, 0);
+       out_be16(&sup->scc_nosec, 0);
+       out_be16(&sup->scc_brkec, 0);
+       out_be16(&sup->scc_uaddr1, 0);
+       out_be16(&sup->scc_uaddr2, 0);
+       out_be16(&sup->scc_toseq, 0);
+       out_be16(&sup->scc_char1, 0x8000);
+       out_be16(&sup->scc_char2, 0x8000);
+       out_be16(&sup->scc_char3, 0x8000);
+       out_be16(&sup->scc_char4, 0x8000);
+       out_be16(&sup->scc_char5, 0x8000);
+       out_be16(&sup->scc_char6, 0x8000);
+       out_be16(&sup->scc_char7, 0x8000);
+       out_be16(&sup->scc_char8, 0x8000);
+       out_be16(&sup->scc_rccm, 0xc0ff);
+
+       /* Send the CPM an initialize command.
+        */
+       cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
+
+       /* Set UART mode, 8 bit, no parity, one stop.
+        * Enable receive and transmit.
+        */
+       out_be32(&scp->scc_gsmrh, 0);
+       out_be32(&scp->scc_gsmrl,
+                SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
+
+       /* Enable rx interrupts  and clear all pending events.  */
+       out_be16(&scp->scc_sccm, 0);
+       out_be16(&scp->scc_scce, 0xffff);
+       out_be16(&scp->scc_dsr, 0x7e7e);
+       out_be16(&scp->scc_psmr, 0x3000);
+
+       setbits32(&scp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+}
+
+static void cpm_uart_init_smc(struct uart_cpm_port *pinfo)
+{
+       smc_t __iomem *sp;
+       smc_uart_t __iomem *up;
+
+       pr_debug("CPM uart[%d]:init_smc\n", pinfo->port.line);
+
+       sp = pinfo->smcp;
+       up = pinfo->smcup;
+
+       /* Store address */
+       out_be16(&pinfo->smcup->smc_rbase,
+                (u8 __iomem *)pinfo->rx_bd_base - DPRAM_BASE);
+       out_be16(&pinfo->smcup->smc_tbase,
+                (u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE);
+
+/*
+ *  In case SMC1 is being relocated...
+ */
+#if defined (CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
+       out_be16(&up->smc_rbptr, in_be16(&pinfo->smcup->smc_rbase));
+       out_be16(&up->smc_tbptr, in_be16(&pinfo->smcup->smc_tbase));
+       out_be32(&up->smc_rstate, 0);
+       out_be32(&up->smc_tstate, 0);
+       out_be16(&up->smc_brkcr, 1);              /* number of break chars */
+       out_be16(&up->smc_brkec, 0);
+#endif
+
+       /* Set up the uart parameters in the
+        * parameter ram.
+        */
+       cpm_set_smc_fcr(up);
+
+       /* Using idle character time requires some additional tuning.  */
+       out_be16(&up->smc_mrblr, pinfo->rx_fifosize);
+       out_be16(&up->smc_maxidl, pinfo->rx_fifosize);
+       out_be16(&up->smc_brklen, 0);
+       out_be16(&up->smc_brkec, 0);
+       out_be16(&up->smc_brkcr, 1);
+
+       cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
+
+       /* Set UART mode, 8 bit, no parity, one stop.
+        * Enable receive and transmit.
+        */
+       out_be16(&sp->smc_smcmr, smcr_mk_clen(9) | SMCMR_SM_UART);
+
+       /* Enable only rx interrupts clear all pending events. */
+       out_8(&sp->smc_smcm, 0);
+       out_8(&sp->smc_smce, 0xff);
+
+       setbits16(&sp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
+}
+
+/*
+ * Initialize port. This is called from early_console stuff
+ * so we have to be careful here !
+ */
+static int cpm_uart_request_port(struct uart_port *port)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       int ret;
+
+       pr_debug("CPM uart[%d]:request port\n", port->line);
+
+       if (pinfo->flags & FLAG_CONSOLE)
+               return 0;
+
+       if (IS_SMC(pinfo)) {
+               clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX | SMCM_TX);
+               clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
+       } else {
+               clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX);
+               clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+       }
+
+       ret = cpm_uart_allocbuf(pinfo, 0);
+
+       if (ret)
+               return ret;
+
+       cpm_uart_initbd(pinfo);
+       if (IS_SMC(pinfo))
+               cpm_uart_init_smc(pinfo);
+       else
+               cpm_uart_init_scc(pinfo);
+
+       return 0;
+}
+
+static void cpm_uart_release_port(struct uart_port *port)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+
+       if (!(pinfo->flags & FLAG_CONSOLE))
+               cpm_uart_freebuf(pinfo);
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void cpm_uart_config_port(struct uart_port *port, int flags)
+{
+       pr_debug("CPM uart[%d]:config_port\n", port->line);
+
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = PORT_CPM;
+               cpm_uart_request_port(port);
+       }
+}
+
+#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_CPM_CONSOLE)
+/*
+ * Write a string to the serial port
+ * Note that this is called with interrupts already disabled
+ */
+static void cpm_uart_early_write(struct uart_cpm_port *pinfo,
+               const char *string, u_int count)
+{
+       unsigned int i;
+       cbd_t __iomem *bdp, *bdbase;
+       unsigned char *cpm_outp_addr;
+
+       /* Get the address of the host memory buffer.
+        */
+       bdp = pinfo->tx_cur;
+       bdbase = pinfo->tx_bd_base;
+
+       /*
+        * Now, do each character.  This is not as bad as it looks
+        * since this is a holding FIFO and not a transmitting FIFO.
+        * We could add the complexity of filling the entire transmit
+        * buffer, but we would just wait longer between accesses......
+        */
+       for (i = 0; i < count; i++, string++) {
+               /* Wait for transmitter fifo to empty.
+                * Ready indicates output is ready, and xmt is doing
+                * that, not that it is ready for us to send.
+                */
+               while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0)
+                       ;
+
+               /* Send the character out.
+                * If the buffer address is in the CPM DPRAM, don't
+                * convert it.
+                */
+               cpm_outp_addr = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr),
+                                       pinfo);
+               *cpm_outp_addr = *string;
+
+               out_be16(&bdp->cbd_datlen, 1);
+               setbits16(&bdp->cbd_sc, BD_SC_READY);
+
+               if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
+                       bdp = bdbase;
+               else
+                       bdp++;
+
+               /* if a LF, also do CR... */
+               if (*string == 10) {
+                       while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0)
+                               ;
+
+                       cpm_outp_addr = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr),
+                                               pinfo);
+                       *cpm_outp_addr = 13;
+
+                       out_be16(&bdp->cbd_datlen, 1);
+                       setbits16(&bdp->cbd_sc, BD_SC_READY);
+
+                       if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
+                               bdp = bdbase;
+                       else
+                               bdp++;
+               }
+       }
+
+       /*
+        * Finally, Wait for transmitter & holding register to empty
+        *  and restore the IER
+        */
+       while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0)
+               ;
+
+       pinfo->tx_cur = bdp;
+}
+#endif
+
+#ifdef CONFIG_CONSOLE_POLL
+/* Serial polling routines for writing and reading from the uart while
+ * in an interrupt or debug context.
+ */
+
+#define GDB_BUF_SIZE   512     /* power of 2, please */
+
+static char poll_buf[GDB_BUF_SIZE];
+static char *pollp;
+static int poll_chars;
+
+static int poll_wait_key(char *obuf, struct uart_cpm_port *pinfo)
+{
+       u_char          c, *cp;
+       volatile cbd_t  *bdp;
+       int             i;
+
+       /* Get the address of the host memory buffer.
+        */
+       bdp = pinfo->rx_cur;
+       while (bdp->cbd_sc & BD_SC_EMPTY)
+               ;
+
+       /* If the buffer address is in the CPM DPRAM, don't
+        * convert it.
+        */
+       cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
+
+       if (obuf) {
+               i = c = bdp->cbd_datlen;
+               while (i-- > 0)
+                       *obuf++ = *cp++;
+       } else
+               c = *cp;
+       bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV | BD_SC_ID);
+       bdp->cbd_sc |= BD_SC_EMPTY;
+
+       if (bdp->cbd_sc & BD_SC_WRAP)
+               bdp = pinfo->rx_bd_base;
+       else
+               bdp++;
+       pinfo->rx_cur = (cbd_t *)bdp;
+
+       return (int)c;
+}
+
+static int cpm_get_poll_char(struct uart_port *port)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+
+       if (!serial_polled) {
+               serial_polled = 1;
+               poll_chars = 0;
+       }
+       if (poll_chars <= 0) {
+               poll_chars = poll_wait_key(poll_buf, pinfo);
+               pollp = poll_buf;
+       }
+       poll_chars--;
+       return *pollp++;
+}
+
+static void cpm_put_poll_char(struct uart_port *port,
+                        unsigned char c)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       static char ch[2];
+
+       ch[0] = (char)c;
+       cpm_uart_early_write(pinfo, ch, 1);
+}
+#endif /* CONFIG_CONSOLE_POLL */
+
+static struct uart_ops cpm_uart_pops = {
+       .tx_empty       = cpm_uart_tx_empty,
+       .set_mctrl      = cpm_uart_set_mctrl,
+       .get_mctrl      = cpm_uart_get_mctrl,
+       .stop_tx        = cpm_uart_stop_tx,
+       .start_tx       = cpm_uart_start_tx,
+       .stop_rx        = cpm_uart_stop_rx,
+       .enable_ms      = cpm_uart_enable_ms,
+       .break_ctl      = cpm_uart_break_ctl,
+       .startup        = cpm_uart_startup,
+       .shutdown       = cpm_uart_shutdown,
+       .set_termios    = cpm_uart_set_termios,
+       .type           = cpm_uart_type,
+       .release_port   = cpm_uart_release_port,
+       .request_port   = cpm_uart_request_port,
+       .config_port    = cpm_uart_config_port,
+       .verify_port    = cpm_uart_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char = cpm_get_poll_char,
+       .poll_put_char = cpm_put_poll_char,
+#endif
+};
+
+struct uart_cpm_port cpm_uart_ports[UART_NR];
+
+static int cpm_uart_init_port(struct device_node *np,
+                              struct uart_cpm_port *pinfo)
+{
+       const u32 *data;
+       void __iomem *mem, *pram;
+       int len;
+       int ret;
+       int i;
+
+       data = of_get_property(np, "clock", NULL);
+       if (data) {
+               struct clk *clk = clk_get(NULL, (const char*)data);
+               if (!IS_ERR(clk))
+                       pinfo->clk = clk;
+       }
+       if (!pinfo->clk) {
+               data = of_get_property(np, "fsl,cpm-brg", &len);
+               if (!data || len != 4) {
+                       printk(KERN_ERR "CPM UART %s has no/invalid "
+                                       "fsl,cpm-brg property.\n", np->name);
+                       return -EINVAL;
+               }
+               pinfo->brg = *data;
+       }
+
+       data = of_get_property(np, "fsl,cpm-command", &len);
+       if (!data || len != 4) {
+               printk(KERN_ERR "CPM UART %s has no/invalid "
+                               "fsl,cpm-command property.\n", np->name);
+               return -EINVAL;
+       }
+       pinfo->command = *data;
+
+       mem = of_iomap(np, 0);
+       if (!mem)
+               return -ENOMEM;
+
+       if (of_device_is_compatible(np, "fsl,cpm1-scc-uart") ||
+           of_device_is_compatible(np, "fsl,cpm2-scc-uart")) {
+               pinfo->sccp = mem;
+               pinfo->sccup = pram = cpm_uart_map_pram(pinfo, np);
+       } else if (of_device_is_compatible(np, "fsl,cpm1-smc-uart") ||
+                  of_device_is_compatible(np, "fsl,cpm2-smc-uart")) {
+               pinfo->flags |= FLAG_SMC;
+               pinfo->smcp = mem;
+               pinfo->smcup = pram = cpm_uart_map_pram(pinfo, np);
+       } else {
+               ret = -ENODEV;
+               goto out_mem;
+       }
+
+       if (!pram) {
+               ret = -ENOMEM;
+               goto out_mem;
+       }
+
+       pinfo->tx_nrfifos = TX_NUM_FIFO;
+       pinfo->tx_fifosize = TX_BUF_SIZE;
+       pinfo->rx_nrfifos = RX_NUM_FIFO;
+       pinfo->rx_fifosize = RX_BUF_SIZE;
+
+       pinfo->port.uartclk = ppc_proc_freq;
+       pinfo->port.mapbase = (unsigned long)mem;
+       pinfo->port.type = PORT_CPM;
+       pinfo->port.ops = &cpm_uart_pops,
+       pinfo->port.iotype = UPIO_MEM;
+       pinfo->port.fifosize = pinfo->tx_nrfifos * pinfo->tx_fifosize;
+       spin_lock_init(&pinfo->port.lock);
+
+       pinfo->port.irq = of_irq_to_resource(np, 0, NULL);
+       if (pinfo->port.irq == NO_IRQ) {
+               ret = -EINVAL;
+               goto out_pram;
+       }
+
+       for (i = 0; i < NUM_GPIOS; i++)
+               pinfo->gpios[i] = of_get_gpio(np, i);
+
+#ifdef CONFIG_PPC_EARLY_DEBUG_CPM
+       udbg_putc = NULL;
+#endif
+
+       return cpm_uart_request_port(&pinfo->port);
+
+out_pram:
+       cpm_uart_unmap_pram(pinfo, pram);
+out_mem:
+       iounmap(mem);
+       return ret;
+}
+
+#ifdef CONFIG_SERIAL_CPM_CONSOLE
+/*
+ *     Print a string to the serial port trying not to disturb
+ *     any possible real use of the port...
+ *
+ *     Note that this is called with interrupts already disabled
+ */
+static void cpm_uart_console_write(struct console *co, const char *s,
+                                  u_int count)
+{
+       struct uart_cpm_port *pinfo = &cpm_uart_ports[co->index];
+       unsigned long flags;
+       int nolock = oops_in_progress;
+
+       if (unlikely(nolock)) {
+               local_irq_save(flags);
+       } else {
+               spin_lock_irqsave(&pinfo->port.lock, flags);
+       }
+
+       cpm_uart_early_write(pinfo, s, count);
+
+       if (unlikely(nolock)) {
+               local_irq_restore(flags);
+       } else {
+               spin_unlock_irqrestore(&pinfo->port.lock, flags);
+       }
+}
+
+
+static int __init cpm_uart_console_setup(struct console *co, char *options)
+{
+       int baud = 38400;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+       int ret;
+       struct uart_cpm_port *pinfo;
+       struct uart_port *port;
+
+       struct device_node *np = NULL;
+       int i = 0;
+
+       if (co->index >= UART_NR) {
+               printk(KERN_ERR "cpm_uart: console index %d too high\n",
+                      co->index);
+               return -ENODEV;
+       }
+
+       do {
+               np = of_find_node_by_type(np, "serial");
+               if (!np)
+                       return -ENODEV;
+
+               if (!of_device_is_compatible(np, "fsl,cpm1-smc-uart") &&
+                   !of_device_is_compatible(np, "fsl,cpm1-scc-uart") &&
+                   !of_device_is_compatible(np, "fsl,cpm2-smc-uart") &&
+                   !of_device_is_compatible(np, "fsl,cpm2-scc-uart"))
+                       i--;
+       } while (i++ != co->index);
+
+       pinfo = &cpm_uart_ports[co->index];
+
+       pinfo->flags |= FLAG_CONSOLE;
+       port = &pinfo->port;
+
+       ret = cpm_uart_init_port(np, pinfo);
+       of_node_put(np);
+       if (ret)
+               return ret;
+
+       if (options) {
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       } else {
+               if ((baud = uart_baudrate()) == -1)
+                       baud = 9600;
+       }
+
+       if (IS_SMC(pinfo)) {
+               out_be16(&pinfo->smcup->smc_brkcr, 0);
+               cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX);
+               clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX | SMCM_TX);
+               clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
+       } else {
+               out_be16(&pinfo->sccup->scc_brkcr, 0);
+               cpm_line_cr_cmd(pinfo, CPM_CR_GRA_STOP_TX);
+               clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX);
+               clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+       }
+
+       ret = cpm_uart_allocbuf(pinfo, 1);
+
+       if (ret)
+               return ret;
+
+       cpm_uart_initbd(pinfo);
+
+       if (IS_SMC(pinfo))
+               cpm_uart_init_smc(pinfo);
+       else
+               cpm_uart_init_scc(pinfo);
+
+       uart_set_options(port, co, baud, parity, bits, flow);
+       cpm_line_cr_cmd(pinfo, CPM_CR_RESTART_TX);
+
+       return 0;
+}
+
+static struct uart_driver cpm_reg;
+static struct console cpm_scc_uart_console = {
+       .name           = "ttyCPM",
+       .write          = cpm_uart_console_write,
+       .device         = uart_console_device,
+       .setup          = cpm_uart_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &cpm_reg,
+};
+
+static int __init cpm_uart_console_init(void)
+{
+       register_console(&cpm_scc_uart_console);
+       return 0;
+}
+
+console_initcall(cpm_uart_console_init);
+
+#define CPM_UART_CONSOLE       &cpm_scc_uart_console
+#else
+#define CPM_UART_CONSOLE       NULL
+#endif
+
+static struct uart_driver cpm_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "ttyCPM",
+       .dev_name       = "ttyCPM",
+       .major          = SERIAL_CPM_MAJOR,
+       .minor          = SERIAL_CPM_MINOR,
+       .cons           = CPM_UART_CONSOLE,
+       .nr             = UART_NR,
+};
+
+static int probe_index;
+
+static int __devinit cpm_uart_probe(struct platform_device *ofdev,
+                                    const struct of_device_id *match)
+{
+       int index = probe_index++;
+       struct uart_cpm_port *pinfo = &cpm_uart_ports[index];
+       int ret;
+
+       pinfo->port.line = index;
+
+       if (index >= UART_NR)
+               return -ENODEV;
+
+       dev_set_drvdata(&ofdev->dev, pinfo);
+
+       /* initialize the device pointer for the port */
+       pinfo->port.dev = &ofdev->dev;
+
+       ret = cpm_uart_init_port(ofdev->dev.of_node, pinfo);
+       if (ret)
+               return ret;
+
+       return uart_add_one_port(&cpm_reg, &pinfo->port);
+}
+
+static int __devexit cpm_uart_remove(struct platform_device *ofdev)
+{
+       struct uart_cpm_port *pinfo = dev_get_drvdata(&ofdev->dev);
+       return uart_remove_one_port(&cpm_reg, &pinfo->port);
+}
+
+static struct of_device_id cpm_uart_match[] = {
+       {
+               .compatible = "fsl,cpm1-smc-uart",
+       },
+       {
+               .compatible = "fsl,cpm1-scc-uart",
+       },
+       {
+               .compatible = "fsl,cpm2-smc-uart",
+       },
+       {
+               .compatible = "fsl,cpm2-scc-uart",
+       },
+       {}
+};
+
+static struct of_platform_driver cpm_uart_driver = {
+       .driver = {
+               .name = "cpm_uart",
+               .owner = THIS_MODULE,
+               .of_match_table = cpm_uart_match,
+       },
+       .probe = cpm_uart_probe,
+       .remove = cpm_uart_remove,
+ };
+
+static int __init cpm_uart_init(void)
+{
+       int ret = uart_register_driver(&cpm_reg);
+       if (ret)
+               return ret;
+
+       ret = of_register_platform_driver(&cpm_uart_driver);
+       if (ret)
+               uart_unregister_driver(&cpm_reg);
+
+       return ret;
+}
+
+static void __exit cpm_uart_exit(void)
+{
+       of_unregister_platform_driver(&cpm_uart_driver);
+       uart_unregister_driver(&cpm_reg);
+}
+
+module_init(cpm_uart_init);
+module_exit(cpm_uart_exit);
+
+MODULE_AUTHOR("Kumar Gala/Antoniou Pantelis");
+MODULE_DESCRIPTION("CPM SCC/SMC port driver $Revision: 0.01 $");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV(SERIAL_CPM_MAJOR, SERIAL_CPM_MINOR);
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c
new file mode 100644 (file)
index 0000000..3fc1d66
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ *  linux/drivers/serial/cpm_uart.c
+ *
+ *  Driver for CPM (SCC/SMC) serial ports; CPM1 definitions
+ *
+ *  Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2)
+ *              Pantelis Antoniou (panto@intracom.gr) (CPM1)
+ *
+ *  Copyright (C) 2004 Freescale Semiconductor, Inc.
+ *            (C) 2004 Intracom, S.A.
+ *            (C) 2006 MontaVista Software, Inc.
+ *             Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * 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/module.h>
+#include <linux/tty.h>
+#include <linux/gfp.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+#include <linux/bootmem.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/fs_pd.h>
+
+#include <linux/serial_core.h>
+#include <linux/kernel.h>
+
+#include <linux/of.h>
+
+#include "cpm_uart.h"
+
+/**************************************************************/
+
+void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd)
+{
+       cpm_command(port->command, cmd);
+}
+
+void __iomem *cpm_uart_map_pram(struct uart_cpm_port *port,
+                               struct device_node *np)
+{
+       return of_iomap(np, 1);
+}
+
+void cpm_uart_unmap_pram(struct uart_cpm_port *port, void __iomem *pram)
+{
+       iounmap(pram);
+}
+
+/*
+ * Allocate DP-Ram and memory buffers. We need to allocate a transmit and
+ * receive buffer descriptors from dual port ram, and a character
+ * buffer area from host mem. If we are allocating for the console we need
+ * to do it from bootmem
+ */
+int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
+{
+       int dpmemsz, memsz;
+       u8 *dp_mem;
+       unsigned long dp_offset;
+       u8 *mem_addr;
+       dma_addr_t dma_addr = 0;
+
+       pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line);
+
+       dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos);
+       dp_offset = cpm_dpalloc(dpmemsz, 8);
+       if (IS_ERR_VALUE(dp_offset)) {
+               printk(KERN_ERR
+                      "cpm_uart_cpm1.c: could not allocate buffer descriptors\n");
+               return -ENOMEM;
+       }
+       dp_mem = cpm_dpram_addr(dp_offset);
+
+       memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) +
+           L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize);
+       if (is_con) {
+               /* was hostalloc but changed cause it blows away the */
+               /* large tlb mapping when pinning the kernel area    */
+               mem_addr = (u8 *) cpm_dpram_addr(cpm_dpalloc(memsz, 8));
+               dma_addr = (u32)cpm_dpram_phys(mem_addr);
+       } else
+               mem_addr = dma_alloc_coherent(pinfo->port.dev, memsz, &dma_addr,
+                                             GFP_KERNEL);
+
+       if (mem_addr == NULL) {
+               cpm_dpfree(dp_offset);
+               printk(KERN_ERR
+                      "cpm_uart_cpm1.c: could not allocate coherent memory\n");
+               return -ENOMEM;
+       }
+
+       pinfo->dp_addr = dp_offset;
+       pinfo->mem_addr = mem_addr;             /*  virtual address*/
+       pinfo->dma_addr = dma_addr;             /*  physical address*/
+       pinfo->mem_size = memsz;
+
+       pinfo->rx_buf = mem_addr;
+       pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
+                                                      * pinfo->rx_fifosize);
+
+       pinfo->rx_bd_base = (cbd_t __iomem __force *)dp_mem;
+       pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos;
+
+       return 0;
+}
+
+void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
+{
+       dma_free_coherent(pinfo->port.dev, L1_CACHE_ALIGN(pinfo->rx_nrfifos *
+                                                         pinfo->rx_fifosize) +
+                         L1_CACHE_ALIGN(pinfo->tx_nrfifos *
+                                        pinfo->tx_fifosize), pinfo->mem_addr,
+                         pinfo->dma_addr);
+
+       cpm_dpfree(pinfo->dp_addr);
+}
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.h
new file mode 100644 (file)
index 0000000..10eecd6
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * linux/drivers/serial/cpm_uart/cpm_uart_cpm1.h
+ *
+ * Driver for CPM (SCC/SMC) serial ports
+ *
+ * definitions for cpm1
+ *
+ */
+
+#ifndef CPM_UART_CPM1_H
+#define CPM_UART_CPM1_H
+
+#include <asm/cpm1.h>
+
+static inline void cpm_set_brg(int brg, int baud)
+{
+       cpm_setbrg(brg, baud);
+}
+
+static inline void cpm_set_scc_fcr(scc_uart_t __iomem * sup)
+{
+       out_8(&sup->scc_genscc.scc_rfcr, SMC_EB);
+       out_8(&sup->scc_genscc.scc_tfcr, SMC_EB);
+}
+
+static inline void cpm_set_smc_fcr(smc_uart_t __iomem * up)
+{
+       out_8(&up->smc_rfcr, SMC_EB);
+       out_8(&up->smc_tfcr, SMC_EB);
+}
+
+#define DPRAM_BASE     ((u8 __iomem __force *)cpm_dpram_addr(0))
+
+#endif
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c
new file mode 100644 (file)
index 0000000..814ac00
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ *  linux/drivers/serial/cpm_uart_cpm2.c
+ *
+ *  Driver for CPM (SCC/SMC) serial ports; CPM2 definitions
+ *
+ *  Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2)
+ *              Pantelis Antoniou (panto@intracom.gr) (CPM1)
+ *
+ *  Copyright (C) 2004 Freescale Semiconductor, Inc.
+ *            (C) 2004 Intracom, S.A.
+ *            (C) 2006 MontaVista Software, Inc.
+ *             Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * 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/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+#include <linux/bootmem.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/fs_pd.h>
+#include <asm/prom.h>
+
+#include <linux/serial_core.h>
+#include <linux/kernel.h>
+
+#include "cpm_uart.h"
+
+/**************************************************************/
+
+void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd)
+{
+       cpm_command(port->command, cmd);
+}
+
+void __iomem *cpm_uart_map_pram(struct uart_cpm_port *port,
+                               struct device_node *np)
+{
+       void __iomem *pram;
+       unsigned long offset;
+       struct resource res;
+       resource_size_t len;
+
+       /* Don't remap parameter RAM if it has already been initialized
+        * during console setup.
+        */
+       if (IS_SMC(port) && port->smcup)
+               return port->smcup;
+       else if (!IS_SMC(port) && port->sccup)
+               return port->sccup;
+
+       if (of_address_to_resource(np, 1, &res))
+               return NULL;
+
+       len = resource_size(&res);
+       pram = ioremap(res.start, len);
+       if (!pram)
+               return NULL;
+
+       if (!IS_SMC(port))
+               return pram;
+
+       if (len != 2) {
+               printk(KERN_WARNING "cpm_uart[%d]: device tree references "
+                       "SMC pram, using boot loader/wrapper pram mapping. "
+                       "Please fix your device tree to reference the pram "
+                       "base register instead.\n",
+                       port->port.line);
+               return pram;
+       }
+
+       offset = cpm_dpalloc(PROFF_SMC_SIZE, 64);
+       out_be16(pram, offset);
+       iounmap(pram);
+       return cpm_muram_addr(offset);
+}
+
+void cpm_uart_unmap_pram(struct uart_cpm_port *port, void __iomem *pram)
+{
+       if (!IS_SMC(port))
+               iounmap(pram);
+}
+
+/*
+ * Allocate DP-Ram and memory buffers. We need to allocate a transmit and
+ * receive buffer descriptors from dual port ram, and a character
+ * buffer area from host mem. If we are allocating for the console we need
+ * to do it from bootmem
+ */
+int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
+{
+       int dpmemsz, memsz;
+       u8 __iomem *dp_mem;
+       unsigned long dp_offset;
+       u8 *mem_addr;
+       dma_addr_t dma_addr = 0;
+
+       pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line);
+
+       dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos);
+       dp_offset = cpm_dpalloc(dpmemsz, 8);
+       if (IS_ERR_VALUE(dp_offset)) {
+               printk(KERN_ERR
+                      "cpm_uart_cpm.c: could not allocate buffer descriptors\n");
+               return -ENOMEM;
+       }
+
+       dp_mem = cpm_dpram_addr(dp_offset);
+
+       memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) +
+           L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize);
+       if (is_con) {
+               mem_addr = kzalloc(memsz, GFP_NOWAIT);
+               dma_addr = virt_to_bus(mem_addr);
+       }
+       else
+               mem_addr = dma_alloc_coherent(pinfo->port.dev, memsz, &dma_addr,
+                                             GFP_KERNEL);
+
+       if (mem_addr == NULL) {
+               cpm_dpfree(dp_offset);
+               printk(KERN_ERR
+                      "cpm_uart_cpm.c: could not allocate coherent memory\n");
+               return -ENOMEM;
+       }
+
+       pinfo->dp_addr = dp_offset;
+       pinfo->mem_addr = mem_addr;
+       pinfo->dma_addr = dma_addr;
+       pinfo->mem_size = memsz;
+
+       pinfo->rx_buf = mem_addr;
+       pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
+                                                      * pinfo->rx_fifosize);
+
+       pinfo->rx_bd_base = (cbd_t __iomem *)dp_mem;
+       pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos;
+
+       return 0;
+}
+
+void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
+{
+       dma_free_coherent(pinfo->port.dev, L1_CACHE_ALIGN(pinfo->rx_nrfifos *
+                                                         pinfo->rx_fifosize) +
+                         L1_CACHE_ALIGN(pinfo->tx_nrfifos *
+                                        pinfo->tx_fifosize), (void __force *)pinfo->mem_addr,
+                         pinfo->dma_addr);
+
+       cpm_dpfree(pinfo->dp_addr);
+}
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.h b/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.h
new file mode 100644 (file)
index 0000000..7194c63
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * linux/drivers/serial/cpm_uart/cpm_uart_cpm2.h
+ *
+ * Driver for CPM (SCC/SMC) serial ports
+ *
+ * definitions for cpm2
+ *
+ */
+
+#ifndef CPM_UART_CPM2_H
+#define CPM_UART_CPM2_H
+
+#include <asm/cpm2.h>
+
+static inline void cpm_set_brg(int brg, int baud)
+{
+       cpm_setbrg(brg, baud);
+}
+
+static inline void cpm_set_scc_fcr(scc_uart_t __iomem *sup)
+{
+       out_8(&sup->scc_genscc.scc_rfcr, CPMFCR_GBL | CPMFCR_EB);
+       out_8(&sup->scc_genscc.scc_tfcr, CPMFCR_GBL | CPMFCR_EB);
+}
+
+static inline void cpm_set_smc_fcr(smc_uart_t __iomem *up)
+{
+       out_8(&up->smc_rfcr, CPMFCR_GBL | CPMFCR_EB);
+       out_8(&up->smc_tfcr, CPMFCR_GBL | CPMFCR_EB);
+}
+
+#define DPRAM_BASE     ((u8 __iomem __force *)cpm_dpram_addr(0))
+
+#endif
diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c
new file mode 100644 (file)
index 0000000..bcc31f2
--- /dev/null
@@ -0,0 +1,4573 @@
+/*
+ * Serial port driver for the ETRAX 100LX chip
+ *
+ *    Copyright (C) 1998-2007  Axis Communications AB
+ *
+ *    Many, many authors. Based once upon a time on serial.c for 16x50.
+ *
+ */
+
+static char *serial_version = "$Revision: 1.25 $";
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.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/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/bitops.h>
+#include <linux/seq_file.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+
+#include <arch/svinto.h>
+
+/* non-arch dependent serial structures are in linux/serial.h */
+#include <linux/serial.h>
+/* while we keep our own stuff (struct e100_serial) in a local .h file */
+#include "crisv10.h"
+#include <asm/fasttimer.h>
+#include <arch/io_interface_mux.h>
+
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+#ifndef CONFIG_ETRAX_FAST_TIMER
+#error "Enable FAST_TIMER to use SERIAL_FAST_TIMER"
+#endif
+#endif
+
+#if defined(CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS) && \
+           (CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS == 0)
+#error "RX_TIMEOUT_TICKS == 0 not allowed, use 1"
+#endif
+
+#if defined(CONFIG_ETRAX_RS485_ON_PA) && defined(CONFIG_ETRAX_RS485_ON_PORT_G)
+#error "Disable either CONFIG_ETRAX_RS485_ON_PA or CONFIG_ETRAX_RS485_ON_PORT_G"
+#endif
+
+/*
+ * All of the compatibilty code so we can compile serial.c against
+ * older kernels is hidden in serial_compat.h
+ */
+#if defined(LOCAL_HEADERS)
+#include "serial_compat.h"
+#endif
+
+struct tty_driver *serial_driver;
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+//#define SERIAL_DEBUG_INTR
+//#define SERIAL_DEBUG_OPEN
+//#define SERIAL_DEBUG_FLOW
+//#define SERIAL_DEBUG_DATA
+//#define SERIAL_DEBUG_THROTTLE
+//#define SERIAL_DEBUG_IO  /* Debug for Extra control and status pins */
+//#define SERIAL_DEBUG_LINE 0 /* What serport we want to debug */
+
+/* Enable this to use serial interrupts to handle when you
+   expect the first received event on the serial port to
+   be an error, break or similar. Used to be able to flash IRMA
+   from eLinux */
+#define SERIAL_HANDLE_EARLY_ERRORS
+
+/* Currently 16 descriptors x 128 bytes = 2048 bytes */
+#define SERIAL_DESCR_BUF_SIZE 256
+
+#define SERIAL_PRESCALE_BASE 3125000 /* 3.125MHz */
+#define DEF_BAUD_BASE SERIAL_PRESCALE_BASE
+
+/* We don't want to load the system with massive fast timer interrupt
+ * on high baudrates so limit it to 250 us (4kHz) */
+#define MIN_FLUSH_TIME_USEC 250
+
+/* Add an x here to log a lot of timer stuff */
+#define TIMERD(x)
+/* Debug details of interrupt handling */
+#define DINTR1(x)  /* irq on/off, errors */
+#define DINTR2(x)    /* tx and rx */
+/* Debug flip buffer stuff */
+#define DFLIP(x)
+/* Debug flow control and overview of data flow */
+#define DFLOW(x)
+#define DBAUD(x)
+#define DLOG_INT_TRIG(x)
+
+//#define DEBUG_LOG_INCLUDED
+#ifndef DEBUG_LOG_INCLUDED
+#define DEBUG_LOG(line, string, value)
+#else
+struct debug_log_info
+{
+       unsigned long time;
+       unsigned long timer_data;
+//  int line;
+       const char *string;
+       int value;
+};
+#define DEBUG_LOG_SIZE 4096
+
+struct debug_log_info debug_log[DEBUG_LOG_SIZE];
+int debug_log_pos = 0;
+
+#define DEBUG_LOG(_line, _string, _value) do { \
+  if ((_line) == SERIAL_DEBUG_LINE) {\
+    debug_log_func(_line, _string, _value); \
+  }\
+}while(0)
+
+void debug_log_func(int line, const char *string, int value)
+{
+       if (debug_log_pos < DEBUG_LOG_SIZE) {
+               debug_log[debug_log_pos].time = jiffies;
+               debug_log[debug_log_pos].timer_data = *R_TIMER_DATA;
+//    debug_log[debug_log_pos].line = line;
+               debug_log[debug_log_pos].string = string;
+               debug_log[debug_log_pos].value = value;
+               debug_log_pos++;
+       }
+       /*printk(string, value);*/
+}
+#endif
+
+#ifndef CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS
+/* Default number of timer ticks before flushing rx fifo
+ * When using "little data, low latency applications: use 0
+ * When using "much data applications (PPP)" use ~5
+ */
+#define CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5
+#endif
+
+unsigned long timer_data_to_ns(unsigned long timer_data);
+
+static void change_speed(struct e100_serial *info);
+static void rs_throttle(struct tty_struct * tty);
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
+static int rs_write(struct tty_struct *tty,
+               const unsigned char *buf, int count);
+#ifdef CONFIG_ETRAX_RS485
+static int e100_write_rs485(struct tty_struct *tty,
+               const unsigned char *buf, int count);
+#endif
+static int get_lsr_info(struct e100_serial *info, unsigned int *value);
+
+
+#define DEF_BAUD 115200   /* 115.2 kbit/s */
+#define STD_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+#define DEF_RX 0x20  /* or SERIAL_CTRL_W >> 8 */
+/* Default value of tx_ctrl register: has txd(bit 7)=1 (idle) as default */
+#define DEF_TX 0x80  /* or SERIAL_CTRL_B */
+
+/* offsets from R_SERIALx_CTRL */
+
+#define REG_DATA 0
+#define REG_DATA_STATUS32 0 /* this is the 32 bit register R_SERIALx_READ */
+#define REG_TR_DATA 0
+#define REG_STATUS 1
+#define REG_TR_CTRL 1
+#define REG_REC_CTRL 2
+#define REG_BAUD 3
+#define REG_XOFF 4  /* this is a 32 bit register */
+
+/* The bitfields are the same for all serial ports */
+#define SER_RXD_MASK         IO_MASK(R_SERIAL0_STATUS, rxd)
+#define SER_DATA_AVAIL_MASK  IO_MASK(R_SERIAL0_STATUS, data_avail)
+#define SER_FRAMING_ERR_MASK IO_MASK(R_SERIAL0_STATUS, framing_err)
+#define SER_PAR_ERR_MASK     IO_MASK(R_SERIAL0_STATUS, par_err)
+#define SER_OVERRUN_MASK     IO_MASK(R_SERIAL0_STATUS, overrun)
+
+#define SER_ERROR_MASK (SER_OVERRUN_MASK | SER_PAR_ERR_MASK | SER_FRAMING_ERR_MASK)
+
+/* Values for info->errorcode */
+#define ERRCODE_SET_BREAK    (TTY_BREAK)
+#define ERRCODE_INSERT        0x100
+#define ERRCODE_INSERT_BREAK (ERRCODE_INSERT | TTY_BREAK)
+
+#define FORCE_EOP(info)  *R_SET_EOP = 1U << info->iseteop;
+
+/*
+ * General note regarding the use of IO_* macros in this file:
+ *
+ * We will use the bits defined for DMA channel 6 when using various
+ * IO_* macros (e.g. IO_STATE, IO_MASK, IO_EXTRACT) and _assume_ they are
+ * the same for all channels (which of course they are).
+ *
+ * We will also use the bits defined for serial port 0 when writing commands
+ * to the different ports, as these bits too are the same for all ports.
+ */
+
+
+/* Mask for the irqs possibly enabled in R_IRQ_MASK1_RD etc. */
+static const unsigned long e100_ser_int_mask = 0
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+| IO_MASK(R_IRQ_MASK1_RD, ser0_data) | IO_MASK(R_IRQ_MASK1_RD, ser0_ready)
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT1
+| IO_MASK(R_IRQ_MASK1_RD, ser1_data) | IO_MASK(R_IRQ_MASK1_RD, ser1_ready)
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+| IO_MASK(R_IRQ_MASK1_RD, ser2_data) | IO_MASK(R_IRQ_MASK1_RD, ser2_ready)
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT3
+| IO_MASK(R_IRQ_MASK1_RD, ser3_data) | IO_MASK(R_IRQ_MASK1_RD, ser3_ready)
+#endif
+;
+unsigned long r_alt_ser_baudrate_shadow = 0;
+
+/* this is the data for the four serial ports in the etrax100 */
+/*  DMA2(ser2), DMA4(ser3), DMA6(ser0) or DMA8(ser1) */
+/* R_DMA_CHx_CLR_INTR, R_DMA_CHx_FIRST, R_DMA_CHx_CMD */
+
+static struct e100_serial rs_table[] = {
+       { .baud        = DEF_BAUD,
+         .ioport        = (unsigned char *)R_SERIAL0_CTRL,
+         .irq         = 1U << 12, /* uses DMA 6 and 7 */
+         .oclrintradr = R_DMA_CH6_CLR_INTR,
+         .ofirstadr   = R_DMA_CH6_FIRST,
+         .ocmdadr     = R_DMA_CH6_CMD,
+         .ostatusadr  = R_DMA_CH6_STATUS,
+         .iclrintradr = R_DMA_CH7_CLR_INTR,
+         .ifirstadr   = R_DMA_CH7_FIRST,
+         .icmdadr     = R_DMA_CH7_CMD,
+         .idescradr   = R_DMA_CH7_DESCR,
+         .flags       = STD_FLAGS,
+         .rx_ctrl     = DEF_RX,
+         .tx_ctrl     = DEF_TX,
+         .iseteop     = 2,
+         .dma_owner   = dma_ser0,
+         .io_if       = if_serial_0,
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+          .enabled  = 1,
+#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT
+         .dma_out_enabled = 1,
+         .dma_out_nbr = SER0_TX_DMA_NBR,
+         .dma_out_irq_nbr = SER0_DMA_TX_IRQ_NBR,
+         .dma_out_irq_flags = IRQF_DISABLED,
+         .dma_out_irq_description = "serial 0 dma tr",
+#else
+         .dma_out_enabled = 0,
+         .dma_out_nbr = UINT_MAX,
+         .dma_out_irq_nbr = 0,
+         .dma_out_irq_flags = 0,
+         .dma_out_irq_description = NULL,
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN
+         .dma_in_enabled = 1,
+         .dma_in_nbr = SER0_RX_DMA_NBR,
+         .dma_in_irq_nbr = SER0_DMA_RX_IRQ_NBR,
+         .dma_in_irq_flags = IRQF_DISABLED,
+         .dma_in_irq_description = "serial 0 dma rec",
+#else
+         .dma_in_enabled = 0,
+         .dma_in_nbr = UINT_MAX,
+         .dma_in_irq_nbr = 0,
+         .dma_in_irq_flags = 0,
+         .dma_in_irq_description = NULL,
+#endif
+#else
+          .enabled  = 0,
+         .io_if_description = NULL,
+         .dma_out_enabled = 0,
+         .dma_in_enabled = 0
+#endif
+
+},  /* ttyS0 */
+#ifndef CONFIG_SVINTO_SIM
+       { .baud        = DEF_BAUD,
+         .ioport        = (unsigned char *)R_SERIAL1_CTRL,
+         .irq         = 1U << 16, /* uses DMA 8 and 9 */
+         .oclrintradr = R_DMA_CH8_CLR_INTR,
+         .ofirstadr   = R_DMA_CH8_FIRST,
+         .ocmdadr     = R_DMA_CH8_CMD,
+         .ostatusadr  = R_DMA_CH8_STATUS,
+         .iclrintradr = R_DMA_CH9_CLR_INTR,
+         .ifirstadr   = R_DMA_CH9_FIRST,
+         .icmdadr     = R_DMA_CH9_CMD,
+         .idescradr   = R_DMA_CH9_DESCR,
+         .flags       = STD_FLAGS,
+         .rx_ctrl     = DEF_RX,
+         .tx_ctrl     = DEF_TX,
+         .iseteop     = 3,
+         .dma_owner   = dma_ser1,
+         .io_if       = if_serial_1,
+#ifdef CONFIG_ETRAX_SERIAL_PORT1
+          .enabled  = 1,
+         .io_if_description = "ser1",
+#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA8_OUT
+         .dma_out_enabled = 1,
+         .dma_out_nbr = SER1_TX_DMA_NBR,
+         .dma_out_irq_nbr = SER1_DMA_TX_IRQ_NBR,
+         .dma_out_irq_flags = IRQF_DISABLED,
+         .dma_out_irq_description = "serial 1 dma tr",
+#else
+         .dma_out_enabled = 0,
+         .dma_out_nbr = UINT_MAX,
+         .dma_out_irq_nbr = 0,
+         .dma_out_irq_flags = 0,
+         .dma_out_irq_description = NULL,
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA9_IN
+         .dma_in_enabled = 1,
+         .dma_in_nbr = SER1_RX_DMA_NBR,
+         .dma_in_irq_nbr = SER1_DMA_RX_IRQ_NBR,
+         .dma_in_irq_flags = IRQF_DISABLED,
+         .dma_in_irq_description = "serial 1 dma rec",
+#else
+         .dma_in_enabled = 0,
+         .dma_in_enabled = 0,
+         .dma_in_nbr = UINT_MAX,
+         .dma_in_irq_nbr = 0,
+         .dma_in_irq_flags = 0,
+         .dma_in_irq_description = NULL,
+#endif
+#else
+          .enabled  = 0,
+         .io_if_description = NULL,
+         .dma_in_irq_nbr = 0,
+         .dma_out_enabled = 0,
+         .dma_in_enabled = 0
+#endif
+},  /* ttyS1 */
+
+       { .baud        = DEF_BAUD,
+         .ioport        = (unsigned char *)R_SERIAL2_CTRL,
+         .irq         = 1U << 4,  /* uses DMA 2 and 3 */
+         .oclrintradr = R_DMA_CH2_CLR_INTR,
+         .ofirstadr   = R_DMA_CH2_FIRST,
+         .ocmdadr     = R_DMA_CH2_CMD,
+         .ostatusadr  = R_DMA_CH2_STATUS,
+         .iclrintradr = R_DMA_CH3_CLR_INTR,
+         .ifirstadr   = R_DMA_CH3_FIRST,
+         .icmdadr     = R_DMA_CH3_CMD,
+         .idescradr   = R_DMA_CH3_DESCR,
+         .flags       = STD_FLAGS,
+         .rx_ctrl     = DEF_RX,
+         .tx_ctrl     = DEF_TX,
+         .iseteop     = 0,
+         .dma_owner   = dma_ser2,
+         .io_if       = if_serial_2,
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+          .enabled  = 1,
+         .io_if_description = "ser2",
+#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT
+         .dma_out_enabled = 1,
+         .dma_out_nbr = SER2_TX_DMA_NBR,
+         .dma_out_irq_nbr = SER2_DMA_TX_IRQ_NBR,
+         .dma_out_irq_flags = IRQF_DISABLED,
+         .dma_out_irq_description = "serial 2 dma tr",
+#else
+         .dma_out_enabled = 0,
+         .dma_out_nbr = UINT_MAX,
+         .dma_out_irq_nbr = 0,
+         .dma_out_irq_flags = 0,
+         .dma_out_irq_description = NULL,
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN
+         .dma_in_enabled = 1,
+         .dma_in_nbr = SER2_RX_DMA_NBR,
+         .dma_in_irq_nbr = SER2_DMA_RX_IRQ_NBR,
+         .dma_in_irq_flags = IRQF_DISABLED,
+         .dma_in_irq_description = "serial 2 dma rec",
+#else
+         .dma_in_enabled = 0,
+         .dma_in_nbr = UINT_MAX,
+         .dma_in_irq_nbr = 0,
+         .dma_in_irq_flags = 0,
+         .dma_in_irq_description = NULL,
+#endif
+#else
+          .enabled  = 0,
+         .io_if_description = NULL,
+         .dma_out_enabled = 0,
+         .dma_in_enabled = 0
+#endif
+ },  /* ttyS2 */
+
+       { .baud        = DEF_BAUD,
+         .ioport        = (unsigned char *)R_SERIAL3_CTRL,
+         .irq         = 1U << 8,  /* uses DMA 4 and 5 */
+         .oclrintradr = R_DMA_CH4_CLR_INTR,
+         .ofirstadr   = R_DMA_CH4_FIRST,
+         .ocmdadr     = R_DMA_CH4_CMD,
+         .ostatusadr  = R_DMA_CH4_STATUS,
+         .iclrintradr = R_DMA_CH5_CLR_INTR,
+         .ifirstadr   = R_DMA_CH5_FIRST,
+         .icmdadr     = R_DMA_CH5_CMD,
+         .idescradr   = R_DMA_CH5_DESCR,
+         .flags       = STD_FLAGS,
+         .rx_ctrl     = DEF_RX,
+         .tx_ctrl     = DEF_TX,
+         .iseteop     = 1,
+         .dma_owner   = dma_ser3,
+         .io_if       = if_serial_3,
+#ifdef CONFIG_ETRAX_SERIAL_PORT3
+          .enabled  = 1,
+         .io_if_description = "ser3",
+#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT
+         .dma_out_enabled = 1,
+         .dma_out_nbr = SER3_TX_DMA_NBR,
+         .dma_out_irq_nbr = SER3_DMA_TX_IRQ_NBR,
+         .dma_out_irq_flags = IRQF_DISABLED,
+         .dma_out_irq_description = "serial 3 dma tr",
+#else
+         .dma_out_enabled = 0,
+         .dma_out_nbr = UINT_MAX,
+         .dma_out_irq_nbr = 0,
+         .dma_out_irq_flags = 0,
+         .dma_out_irq_description = NULL,
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN
+         .dma_in_enabled = 1,
+         .dma_in_nbr = SER3_RX_DMA_NBR,
+         .dma_in_irq_nbr = SER3_DMA_RX_IRQ_NBR,
+         .dma_in_irq_flags = IRQF_DISABLED,
+         .dma_in_irq_description = "serial 3 dma rec",
+#else
+         .dma_in_enabled = 0,
+         .dma_in_nbr = UINT_MAX,
+         .dma_in_irq_nbr = 0,
+         .dma_in_irq_flags = 0,
+         .dma_in_irq_description = NULL
+#endif
+#else
+          .enabled  = 0,
+         .io_if_description = NULL,
+         .dma_out_enabled = 0,
+         .dma_in_enabled = 0
+#endif
+ }   /* ttyS3 */
+#endif
+};
+
+
+#define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial))
+
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+static struct fast_timer fast_timers[NR_PORTS];
+#endif
+
+#ifdef CONFIG_ETRAX_SERIAL_PROC_ENTRY
+#define PROCSTAT(x) x
+struct ser_statistics_type {
+       int overrun_cnt;
+       int early_errors_cnt;
+       int ser_ints_ok_cnt;
+       int errors_cnt;
+       unsigned long int processing_flip;
+       unsigned long processing_flip_still_room;
+       unsigned long int timeout_flush_cnt;
+       int rx_dma_ints;
+       int tx_dma_ints;
+       int rx_tot;
+       int tx_tot;
+};
+
+static struct ser_statistics_type ser_stat[NR_PORTS];
+
+#else
+
+#define PROCSTAT(x)
+
+#endif /* CONFIG_ETRAX_SERIAL_PROC_ENTRY */
+
+/* RS-485 */
+#if defined(CONFIG_ETRAX_RS485)
+#ifdef CONFIG_ETRAX_FAST_TIMER
+static struct fast_timer fast_timers_rs485[NR_PORTS];
+#endif
+#if defined(CONFIG_ETRAX_RS485_ON_PA)
+static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT;
+#endif
+#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
+static int rs485_port_g_bit = CONFIG_ETRAX_RS485_ON_PORT_G_BIT;
+#endif
+#endif
+
+/* Info and macros needed for each ports extra control/status signals. */
+#define E100_STRUCT_PORT(line, pinname) \
+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
+               (R_PORT_PA_DATA): ( \
+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
+               (R_PORT_PB_DATA):&dummy_ser[line]))
+
+#define E100_STRUCT_SHADOW(line, pinname) \
+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
+               (&port_pa_data_shadow): ( \
+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
+               (&port_pb_data_shadow):&dummy_ser[line]))
+#define E100_STRUCT_MASK(line, pinname) \
+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
+               (1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT): ( \
+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
+               (1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT):DUMMY_##pinname##_MASK))
+
+#define DUMMY_DTR_MASK 1
+#define DUMMY_RI_MASK  2
+#define DUMMY_DSR_MASK 4
+#define DUMMY_CD_MASK  8
+static unsigned char dummy_ser[NR_PORTS] = {0xFF, 0xFF, 0xFF,0xFF};
+
+/* If not all status pins are used or disabled, use mixed mode */
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+
+#define SER0_PA_BITSUM (CONFIG_ETRAX_SER0_DTR_ON_PA_BIT+CONFIG_ETRAX_SER0_RI_ON_PA_BIT+CONFIG_ETRAX_SER0_DSR_ON_PA_BIT+CONFIG_ETRAX_SER0_CD_ON_PA_BIT)
+
+#if SER0_PA_BITSUM != -4
+#  if CONFIG_ETRAX_SER0_DTR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER0_RI_ON_PA_BIT == -1
+#   ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER0_DSR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER0_CD_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#define SER0_PB_BITSUM (CONFIG_ETRAX_SER0_DTR_ON_PB_BIT+CONFIG_ETRAX_SER0_RI_ON_PB_BIT+CONFIG_ETRAX_SER0_DSR_ON_PB_BIT+CONFIG_ETRAX_SER0_CD_ON_PB_BIT)
+
+#if SER0_PB_BITSUM != -4
+#  if CONFIG_ETRAX_SER0_DTR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER0_RI_ON_PB_BIT == -1
+#   ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER0_DSR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER0_CD_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#endif /* PORT0 */
+
+
+#ifdef CONFIG_ETRAX_SERIAL_PORT1
+
+#define SER1_PA_BITSUM (CONFIG_ETRAX_SER1_DTR_ON_PA_BIT+CONFIG_ETRAX_SER1_RI_ON_PA_BIT+CONFIG_ETRAX_SER1_DSR_ON_PA_BIT+CONFIG_ETRAX_SER1_CD_ON_PA_BIT)
+
+#if SER1_PA_BITSUM != -4
+#  if CONFIG_ETRAX_SER1_DTR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER1_RI_ON_PA_BIT == -1
+#   ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER1_DSR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER1_CD_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#define SER1_PB_BITSUM (CONFIG_ETRAX_SER1_DTR_ON_PB_BIT+CONFIG_ETRAX_SER1_RI_ON_PB_BIT+CONFIG_ETRAX_SER1_DSR_ON_PB_BIT+CONFIG_ETRAX_SER1_CD_ON_PB_BIT)
+
+#if SER1_PB_BITSUM != -4
+#  if CONFIG_ETRAX_SER1_DTR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER1_RI_ON_PB_BIT == -1
+#   ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER1_DSR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER1_CD_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#endif /* PORT1 */
+
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+
+#define SER2_PA_BITSUM (CONFIG_ETRAX_SER2_DTR_ON_PA_BIT+CONFIG_ETRAX_SER2_RI_ON_PA_BIT+CONFIG_ETRAX_SER2_DSR_ON_PA_BIT+CONFIG_ETRAX_SER2_CD_ON_PA_BIT)
+
+#if SER2_PA_BITSUM != -4
+#  if CONFIG_ETRAX_SER2_DTR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER2_RI_ON_PA_BIT == -1
+#   ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER2_DSR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER2_CD_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#define SER2_PB_BITSUM (CONFIG_ETRAX_SER2_DTR_ON_PB_BIT+CONFIG_ETRAX_SER2_RI_ON_PB_BIT+CONFIG_ETRAX_SER2_DSR_ON_PB_BIT+CONFIG_ETRAX_SER2_CD_ON_PB_BIT)
+
+#if SER2_PB_BITSUM != -4
+#  if CONFIG_ETRAX_SER2_DTR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER2_RI_ON_PB_BIT == -1
+#   ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER2_DSR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER2_CD_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#endif /* PORT2 */
+
+#ifdef CONFIG_ETRAX_SERIAL_PORT3
+
+#define SER3_PA_BITSUM (CONFIG_ETRAX_SER3_DTR_ON_PA_BIT+CONFIG_ETRAX_SER3_RI_ON_PA_BIT+CONFIG_ETRAX_SER3_DSR_ON_PA_BIT+CONFIG_ETRAX_SER3_CD_ON_PA_BIT)
+
+#if SER3_PA_BITSUM != -4
+#  if CONFIG_ETRAX_SER3_DTR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER3_RI_ON_PA_BIT == -1
+#   ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER3_DSR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER3_CD_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#define SER3_PB_BITSUM (CONFIG_ETRAX_SER3_DTR_ON_PB_BIT+CONFIG_ETRAX_SER3_RI_ON_PB_BIT+CONFIG_ETRAX_SER3_DSR_ON_PB_BIT+CONFIG_ETRAX_SER3_CD_ON_PB_BIT)
+
+#if SER3_PB_BITSUM != -4
+#  if CONFIG_ETRAX_SER3_DTR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER3_RI_ON_PB_BIT == -1
+#   ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER3_DSR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER3_CD_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#endif /* PORT3 */
+
+
+#if defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED) || \
+    defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED) || \
+    defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED) || \
+    defined(CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED)
+#define CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
+#endif
+
+#ifdef CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
+/* The pins can be mixed on PA and PB */
+#define CONTROL_PINS_PORT_NOT_USED(line) \
+  &dummy_ser[line], &dummy_ser[line], \
+  &dummy_ser[line], &dummy_ser[line], \
+  &dummy_ser[line], &dummy_ser[line], \
+  &dummy_ser[line], &dummy_ser[line], \
+  DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK
+
+
+struct control_pins
+{
+       volatile unsigned char *dtr_port;
+       unsigned char          *dtr_shadow;
+       volatile unsigned char *ri_port;
+       unsigned char          *ri_shadow;
+       volatile unsigned char *dsr_port;
+       unsigned char          *dsr_shadow;
+       volatile unsigned char *cd_port;
+       unsigned char          *cd_shadow;
+
+       unsigned char dtr_mask;
+       unsigned char ri_mask;
+       unsigned char dsr_mask;
+       unsigned char cd_mask;
+};
+
+static const struct control_pins e100_modem_pins[NR_PORTS] =
+{
+       /* Ser 0 */
+       {
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+       E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR),
+       E100_STRUCT_PORT(0,RI),  E100_STRUCT_SHADOW(0,RI),
+       E100_STRUCT_PORT(0,DSR), E100_STRUCT_SHADOW(0,DSR),
+       E100_STRUCT_PORT(0,CD),  E100_STRUCT_SHADOW(0,CD),
+       E100_STRUCT_MASK(0,DTR),
+       E100_STRUCT_MASK(0,RI),
+       E100_STRUCT_MASK(0,DSR),
+       E100_STRUCT_MASK(0,CD)
+#else
+       CONTROL_PINS_PORT_NOT_USED(0)
+#endif
+       },
+
+       /* Ser 1 */
+       {
+#ifdef CONFIG_ETRAX_SERIAL_PORT1
+       E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR),
+       E100_STRUCT_PORT(1,RI),  E100_STRUCT_SHADOW(1,RI),
+       E100_STRUCT_PORT(1,DSR), E100_STRUCT_SHADOW(1,DSR),
+       E100_STRUCT_PORT(1,CD),  E100_STRUCT_SHADOW(1,CD),
+       E100_STRUCT_MASK(1,DTR),
+       E100_STRUCT_MASK(1,RI),
+       E100_STRUCT_MASK(1,DSR),
+       E100_STRUCT_MASK(1,CD)
+#else
+       CONTROL_PINS_PORT_NOT_USED(1)
+#endif
+       },
+
+       /* Ser 2 */
+       {
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+       E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR),
+       E100_STRUCT_PORT(2,RI),  E100_STRUCT_SHADOW(2,RI),
+       E100_STRUCT_PORT(2,DSR), E100_STRUCT_SHADOW(2,DSR),
+       E100_STRUCT_PORT(2,CD),  E100_STRUCT_SHADOW(2,CD),
+       E100_STRUCT_MASK(2,DTR),
+       E100_STRUCT_MASK(2,RI),
+       E100_STRUCT_MASK(2,DSR),
+       E100_STRUCT_MASK(2,CD)
+#else
+       CONTROL_PINS_PORT_NOT_USED(2)
+#endif
+       },
+
+       /* Ser 3 */
+       {
+#ifdef CONFIG_ETRAX_SERIAL_PORT3
+       E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR),
+       E100_STRUCT_PORT(3,RI),  E100_STRUCT_SHADOW(3,RI),
+       E100_STRUCT_PORT(3,DSR), E100_STRUCT_SHADOW(3,DSR),
+       E100_STRUCT_PORT(3,CD),  E100_STRUCT_SHADOW(3,CD),
+       E100_STRUCT_MASK(3,DTR),
+       E100_STRUCT_MASK(3,RI),
+       E100_STRUCT_MASK(3,DSR),
+       E100_STRUCT_MASK(3,CD)
+#else
+       CONTROL_PINS_PORT_NOT_USED(3)
+#endif
+       }
+};
+#else  /* CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
+
+/* All pins are on either PA or PB for each serial port */
+#define CONTROL_PINS_PORT_NOT_USED(line) \
+  &dummy_ser[line], &dummy_ser[line], \
+  DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK
+
+
+struct control_pins
+{
+       volatile unsigned char *port;
+       unsigned char          *shadow;
+
+       unsigned char dtr_mask;
+       unsigned char ri_mask;
+       unsigned char dsr_mask;
+       unsigned char cd_mask;
+};
+
+#define dtr_port port
+#define dtr_shadow shadow
+#define ri_port port
+#define ri_shadow shadow
+#define dsr_port port
+#define dsr_shadow shadow
+#define cd_port port
+#define cd_shadow shadow
+
+static const struct control_pins e100_modem_pins[NR_PORTS] =
+{
+       /* Ser 0 */
+       {
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+       E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR),
+       E100_STRUCT_MASK(0,DTR),
+       E100_STRUCT_MASK(0,RI),
+       E100_STRUCT_MASK(0,DSR),
+       E100_STRUCT_MASK(0,CD)
+#else
+       CONTROL_PINS_PORT_NOT_USED(0)
+#endif
+       },
+
+       /* Ser 1 */
+       {
+#ifdef CONFIG_ETRAX_SERIAL_PORT1
+       E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR),
+       E100_STRUCT_MASK(1,DTR),
+       E100_STRUCT_MASK(1,RI),
+       E100_STRUCT_MASK(1,DSR),
+       E100_STRUCT_MASK(1,CD)
+#else
+       CONTROL_PINS_PORT_NOT_USED(1)
+#endif
+       },
+
+       /* Ser 2 */
+       {
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+       E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR),
+       E100_STRUCT_MASK(2,DTR),
+       E100_STRUCT_MASK(2,RI),
+       E100_STRUCT_MASK(2,DSR),
+       E100_STRUCT_MASK(2,CD)
+#else
+       CONTROL_PINS_PORT_NOT_USED(2)
+#endif
+       },
+
+       /* Ser 3 */
+       {
+#ifdef CONFIG_ETRAX_SERIAL_PORT3
+       E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR),
+       E100_STRUCT_MASK(3,DTR),
+       E100_STRUCT_MASK(3,RI),
+       E100_STRUCT_MASK(3,DSR),
+       E100_STRUCT_MASK(3,CD)
+#else
+       CONTROL_PINS_PORT_NOT_USED(3)
+#endif
+       }
+};
+#endif /* !CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
+
+#define E100_RTS_MASK 0x20
+#define E100_CTS_MASK 0x40
+
+/* All serial port signals are active low:
+ * active   = 0 -> 3.3V to RS-232 driver -> -12V on RS-232 level
+ * inactive = 1 -> 0V   to RS-232 driver -> +12V on RS-232 level
+ *
+ * These macros returns the pin value: 0=0V, >=1 = 3.3V on ETRAX chip
+ */
+
+/* Output */
+#define E100_RTS_GET(info) ((info)->rx_ctrl & E100_RTS_MASK)
+/* Input */
+#define E100_CTS_GET(info) ((info)->ioport[REG_STATUS] & E100_CTS_MASK)
+
+/* These are typically PA or PB and 0 means 0V, 1 means 3.3V */
+/* Is an output */
+#define E100_DTR_GET(info) ((*e100_modem_pins[(info)->line].dtr_shadow) & e100_modem_pins[(info)->line].dtr_mask)
+
+/* Normally inputs */
+#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].ri_port) & e100_modem_pins[(info)->line].ri_mask)
+#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].cd_port) & e100_modem_pins[(info)->line].cd_mask)
+
+/* Input */
+#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask)
+
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write.  We need to
+ * lock it in case the memcpy_fromfs blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char *tmp_buf;
+static DEFINE_MUTEX(tmp_buf_mutex);
+
+/* Calculate the chartime depending on baudrate, numbor of bits etc. */
+static void update_char_time(struct e100_serial * info)
+{
+       tcflag_t cflags = info->port.tty->termios->c_cflag;
+       int bits;
+
+       /* calc. number of bits / data byte */
+       /* databits + startbit and 1 stopbit */
+       if ((cflags & CSIZE) == CS7)
+               bits = 9;
+       else
+               bits = 10;
+
+       if (cflags & CSTOPB)     /* 2 stopbits ? */
+               bits++;
+
+       if (cflags & PARENB)     /* parity bit ? */
+               bits++;
+
+       /* calc timeout */
+       info->char_time_usec = ((bits * 1000000) / info->baud) + 1;
+       info->flush_time_usec = 4*info->char_time_usec;
+       if (info->flush_time_usec < MIN_FLUSH_TIME_USEC)
+               info->flush_time_usec = MIN_FLUSH_TIME_USEC;
+
+}
+
+/*
+ * This function maps from the Bxxxx defines in asm/termbits.h into real
+ * baud rates.
+ */
+
+static int
+cflag_to_baud(unsigned int cflag)
+{
+       static int baud_table[] = {
+               0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400,
+               4800, 9600, 19200, 38400 };
+
+       static int ext_baud_table[] = {
+               0, 57600, 115200, 230400, 460800, 921600, 1843200, 6250000,
+                0, 0, 0, 0, 0, 0, 0, 0 };
+
+       if (cflag & CBAUDEX)
+               return ext_baud_table[(cflag & CBAUD) & ~CBAUDEX];
+       else
+               return baud_table[cflag & CBAUD];
+}
+
+/* and this maps to an etrax100 hardware baud constant */
+
+static unsigned char
+cflag_to_etrax_baud(unsigned int cflag)
+{
+       char retval;
+
+       static char baud_table[] = {
+               -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, -1, 3, 4, 5, 6, 7 };
+
+       static char ext_baud_table[] = {
+               -1, 8, 9, 10, 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, -1, -1 };
+
+       if (cflag & CBAUDEX)
+               retval = ext_baud_table[(cflag & CBAUD) & ~CBAUDEX];
+       else
+               retval = baud_table[cflag & CBAUD];
+
+       if (retval < 0) {
+               printk(KERN_WARNING "serdriver tried setting invalid baud rate, flags %x.\n", cflag);
+               retval = 5; /* choose default 9600 instead */
+       }
+
+       return retval | (retval << 4); /* choose same for both TX and RX */
+}
+
+
+/* Various static support functions */
+
+/* Functions to set or clear DTR/RTS on the requested line */
+/* It is complicated by the fact that RTS is a serial port register, while
+ * DTR might not be implemented in the HW at all, and if it is, it can be on
+ * any general port.
+ */
+
+
+static inline void
+e100_dtr(struct e100_serial *info, int set)
+{
+#ifndef CONFIG_SVINTO_SIM
+       unsigned char mask = e100_modem_pins[info->line].dtr_mask;
+
+#ifdef SERIAL_DEBUG_IO
+       printk("ser%i dtr %i mask: 0x%02X\n", info->line, set, mask);
+       printk("ser%i shadow before 0x%02X get: %i\n",
+              info->line, *e100_modem_pins[info->line].dtr_shadow,
+              E100_DTR_GET(info));
+#endif
+       /* DTR is active low */
+       {
+               unsigned long flags;
+
+               local_irq_save(flags);
+               *e100_modem_pins[info->line].dtr_shadow &= ~mask;
+               *e100_modem_pins[info->line].dtr_shadow |= (set ? 0 : mask);
+               *e100_modem_pins[info->line].dtr_port = *e100_modem_pins[info->line].dtr_shadow;
+               local_irq_restore(flags);
+       }
+
+#ifdef SERIAL_DEBUG_IO
+       printk("ser%i shadow after 0x%02X get: %i\n",
+              info->line, *e100_modem_pins[info->line].dtr_shadow,
+              E100_DTR_GET(info));
+#endif
+#endif
+}
+
+/* set = 0 means 3.3V on the pin, bitvalue: 0=active, 1=inactive
+ *                                          0=0V    , 1=3.3V
+ */
+static inline void
+e100_rts(struct e100_serial *info, int set)
+{
+#ifndef CONFIG_SVINTO_SIM
+       unsigned long flags;
+       local_irq_save(flags);
+       info->rx_ctrl &= ~E100_RTS_MASK;
+       info->rx_ctrl |= (set ? 0 : E100_RTS_MASK);  /* RTS is active low */
+       info->ioport[REG_REC_CTRL] = info->rx_ctrl;
+       local_irq_restore(flags);
+#ifdef SERIAL_DEBUG_IO
+       printk("ser%i rts %i\n", info->line, set);
+#endif
+#endif
+}
+
+
+/* If this behaves as a modem, RI and CD is an output */
+static inline void
+e100_ri_out(struct e100_serial *info, int set)
+{
+#ifndef CONFIG_SVINTO_SIM
+       /* RI is active low */
+       {
+               unsigned char mask = e100_modem_pins[info->line].ri_mask;
+               unsigned long flags;
+
+               local_irq_save(flags);
+               *e100_modem_pins[info->line].ri_shadow &= ~mask;
+               *e100_modem_pins[info->line].ri_shadow |= (set ? 0 : mask);
+               *e100_modem_pins[info->line].ri_port = *e100_modem_pins[info->line].ri_shadow;
+               local_irq_restore(flags);
+       }
+#endif
+}
+static inline void
+e100_cd_out(struct e100_serial *info, int set)
+{
+#ifndef CONFIG_SVINTO_SIM
+       /* CD is active low */
+       {
+               unsigned char mask = e100_modem_pins[info->line].cd_mask;
+               unsigned long flags;
+
+               local_irq_save(flags);
+               *e100_modem_pins[info->line].cd_shadow &= ~mask;
+               *e100_modem_pins[info->line].cd_shadow |= (set ? 0 : mask);
+               *e100_modem_pins[info->line].cd_port = *e100_modem_pins[info->line].cd_shadow;
+               local_irq_restore(flags);
+       }
+#endif
+}
+
+static inline void
+e100_disable_rx(struct e100_serial *info)
+{
+#ifndef CONFIG_SVINTO_SIM
+       /* disable the receiver */
+       info->ioport[REG_REC_CTRL] =
+               (info->rx_ctrl &= ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable));
+#endif
+}
+
+static inline void
+e100_enable_rx(struct e100_serial *info)
+{
+#ifndef CONFIG_SVINTO_SIM
+       /* enable the receiver */
+       info->ioport[REG_REC_CTRL] =
+               (info->rx_ctrl |= IO_MASK(R_SERIAL0_REC_CTRL, rec_enable));
+#endif
+}
+
+/* the rx DMA uses both the dma_descr and the dma_eop interrupts */
+
+static inline void
+e100_disable_rxdma_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+       printk("rxdma_irq(%d): 0\n",info->line);
+#endif
+       DINTR1(DEBUG_LOG(info->line,"IRQ disable_rxdma_irq %i\n", info->line));
+       *R_IRQ_MASK2_CLR = (info->irq << 2) | (info->irq << 3);
+}
+
+static inline void
+e100_enable_rxdma_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+       printk("rxdma_irq(%d): 1\n",info->line);
+#endif
+       DINTR1(DEBUG_LOG(info->line,"IRQ enable_rxdma_irq %i\n", info->line));
+       *R_IRQ_MASK2_SET = (info->irq << 2) | (info->irq << 3);
+}
+
+/* the tx DMA uses only dma_descr interrupt */
+
+static void e100_disable_txdma_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+       printk("txdma_irq(%d): 0\n",info->line);
+#endif
+       DINTR1(DEBUG_LOG(info->line,"IRQ disable_txdma_irq %i\n", info->line));
+       *R_IRQ_MASK2_CLR = info->irq;
+}
+
+static void e100_enable_txdma_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+       printk("txdma_irq(%d): 1\n",info->line);
+#endif
+       DINTR1(DEBUG_LOG(info->line,"IRQ enable_txdma_irq %i\n", info->line));
+       *R_IRQ_MASK2_SET = info->irq;
+}
+
+static void e100_disable_txdma_channel(struct e100_serial *info)
+{
+       unsigned long flags;
+
+       /* Disable output DMA channel for the serial port in question
+        * ( set to something other than serialX)
+        */
+       local_irq_save(flags);
+       DFLOW(DEBUG_LOG(info->line, "disable_txdma_channel %i\n", info->line));
+       if (info->line == 0) {
+               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma6)) ==
+                   IO_STATE(R_GEN_CONFIG, dma6, serial0)) {
+                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma6);
+                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused);
+               }
+       } else if (info->line == 1) {
+               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma8)) ==
+                   IO_STATE(R_GEN_CONFIG, dma8, serial1)) {
+                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma8);
+                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb);
+               }
+       } else if (info->line == 2) {
+               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma2)) ==
+                   IO_STATE(R_GEN_CONFIG, dma2, serial2)) {
+                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma2);
+                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0);
+               }
+       } else if (info->line == 3) {
+               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma4)) ==
+                   IO_STATE(R_GEN_CONFIG, dma4, serial3)) {
+                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma4);
+                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, par1);
+               }
+       }
+       *R_GEN_CONFIG = genconfig_shadow;
+       local_irq_restore(flags);
+}
+
+
+static void e100_enable_txdma_channel(struct e100_serial *info)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       DFLOW(DEBUG_LOG(info->line, "enable_txdma_channel %i\n", info->line));
+       /* Enable output DMA channel for the serial port in question */
+       if (info->line == 0) {
+               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma6);
+               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, serial0);
+       } else if (info->line == 1) {
+               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma8);
+               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, serial1);
+       } else if (info->line == 2) {
+               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma2);
+               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, serial2);
+       } else if (info->line == 3) {
+               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma4);
+               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, serial3);
+       }
+       *R_GEN_CONFIG = genconfig_shadow;
+       local_irq_restore(flags);
+}
+
+static void e100_disable_rxdma_channel(struct e100_serial *info)
+{
+       unsigned long flags;
+
+       /* Disable input DMA channel for the serial port in question
+        * ( set to something other than serialX)
+        */
+       local_irq_save(flags);
+       if (info->line == 0) {
+               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma7)) ==
+                   IO_STATE(R_GEN_CONFIG, dma7, serial0)) {
+                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma7);
+                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma7, unused);
+               }
+       } else if (info->line == 1) {
+               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma9)) ==
+                   IO_STATE(R_GEN_CONFIG, dma9, serial1)) {
+                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma9);
+                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, usb);
+               }
+       } else if (info->line == 2) {
+               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma3)) ==
+                   IO_STATE(R_GEN_CONFIG, dma3, serial2)) {
+                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma3);
+                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, par0);
+               }
+       } else if (info->line == 3) {
+               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma5)) ==
+                   IO_STATE(R_GEN_CONFIG, dma5, serial3)) {
+                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma5);
+                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, par1);
+               }
+       }
+       *R_GEN_CONFIG = genconfig_shadow;
+       local_irq_restore(flags);
+}
+
+
+static void e100_enable_rxdma_channel(struct e100_serial *info)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       /* Enable input DMA channel for the serial port in question */
+       if (info->line == 0) {
+               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma7);
+               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma7, serial0);
+       } else if (info->line == 1) {
+               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma9);
+               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, serial1);
+       } else if (info->line == 2) {
+               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma3);
+               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, serial2);
+       } else if (info->line == 3) {
+               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma5);
+               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, serial3);
+       }
+       *R_GEN_CONFIG = genconfig_shadow;
+       local_irq_restore(flags);
+}
+
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+/* in order to detect and fix errors on the first byte
+   we have to use the serial interrupts as well. */
+
+static inline void
+e100_disable_serial_data_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+       printk("ser_irq(%d): 0\n",info->line);
+#endif
+       DINTR1(DEBUG_LOG(info->line,"IRQ disable data_irq %i\n", info->line));
+       *R_IRQ_MASK1_CLR = (1U << (8+2*info->line));
+}
+
+static inline void
+e100_enable_serial_data_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+       printk("ser_irq(%d): 1\n",info->line);
+       printk("**** %d = %d\n",
+              (8+2*info->line),
+              (1U << (8+2*info->line)));
+#endif
+       DINTR1(DEBUG_LOG(info->line,"IRQ enable data_irq %i\n", info->line));
+       *R_IRQ_MASK1_SET = (1U << (8+2*info->line));
+}
+#endif
+
+static inline void
+e100_disable_serial_tx_ready_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+       printk("ser_tx_irq(%d): 0\n",info->line);
+#endif
+       DINTR1(DEBUG_LOG(info->line,"IRQ disable ready_irq %i\n", info->line));
+       *R_IRQ_MASK1_CLR = (1U << (8+1+2*info->line));
+}
+
+static inline void
+e100_enable_serial_tx_ready_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+       printk("ser_tx_irq(%d): 1\n",info->line);
+       printk("**** %d = %d\n",
+              (8+1+2*info->line),
+              (1U << (8+1+2*info->line)));
+#endif
+       DINTR2(DEBUG_LOG(info->line,"IRQ enable ready_irq %i\n", info->line));
+       *R_IRQ_MASK1_SET = (1U << (8+1+2*info->line));
+}
+
+static inline void e100_enable_rx_irq(struct e100_serial *info)
+{
+       if (info->uses_dma_in)
+               e100_enable_rxdma_irq(info);
+       else
+               e100_enable_serial_data_irq(info);
+}
+static inline void e100_disable_rx_irq(struct e100_serial *info)
+{
+       if (info->uses_dma_in)
+               e100_disable_rxdma_irq(info);
+       else
+               e100_disable_serial_data_irq(info);
+}
+
+#if defined(CONFIG_ETRAX_RS485)
+/* Enable RS-485 mode on selected port. This is UGLY. */
+static int
+e100_enable_rs485(struct tty_struct *tty, struct serial_rs485 *r)
+{
+       struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+
+#if defined(CONFIG_ETRAX_RS485_ON_PA)
+       *R_PORT_PA_DATA = port_pa_data_shadow |= (1 << rs485_pa_bit);
+#endif
+#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
+       REG_SHADOW_SET(R_PORT_G_DATA,  port_g_data_shadow,
+                      rs485_port_g_bit, 1);
+#endif
+#if defined(CONFIG_ETRAX_RS485_LTC1387)
+       REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
+                      CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 1);
+       REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
+                      CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 1);
+#endif
+
+       info->rs485 = *r;
+
+       /* Maximum delay before RTS equal to 1000 */
+       if (info->rs485.delay_rts_before_send >= 1000)
+               info->rs485.delay_rts_before_send = 1000;
+
+/*     printk("rts: on send = %i, after = %i, enabled = %i",
+                   info->rs485.rts_on_send,
+                   info->rs485.rts_after_sent,
+                   info->rs485.enabled
+       );
+*/
+       return 0;
+}
+
+static int
+e100_write_rs485(struct tty_struct *tty,
+                 const unsigned char *buf, int count)
+{
+       struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+       int old_value = (info->rs485.flags) & SER_RS485_ENABLED;
+
+       /* rs485 is always implicitly enabled if we're using the ioctl()
+        * but it doesn't have to be set in the serial_rs485
+        * (to be backward compatible with old apps)
+        * So we store, set and restore it.
+        */
+       info->rs485.flags |= SER_RS485_ENABLED;
+       /* rs_write now deals with RS485 if enabled */
+       count = rs_write(tty, buf, count);
+       if (!old_value)
+               info->rs485.flags &= ~(SER_RS485_ENABLED);
+       return count;
+}
+
+#ifdef CONFIG_ETRAX_FAST_TIMER
+/* Timer function to toggle RTS when using FAST_TIMER */
+static void rs485_toggle_rts_timer_function(unsigned long data)
+{
+       struct e100_serial *info = (struct e100_serial *)data;
+
+       fast_timers_rs485[info->line].function = NULL;
+       e100_rts(info, (info->rs485.flags & SER_RS485_RTS_AFTER_SEND));
+#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
+       e100_enable_rx(info);
+       e100_enable_rx_irq(info);
+#endif
+}
+#endif
+#endif /* CONFIG_ETRAX_RS485 */
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter using the XOFF registers, as necessary.
+ * ------------------------------------------------------------
+ */
+
+static void
+rs_stop(struct tty_struct *tty)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       if (info) {
+               unsigned long flags;
+               unsigned long xoff;
+
+               local_irq_save(flags);
+               DFLOW(DEBUG_LOG(info->line, "XOFF rs_stop xmit %i\n",
+                               CIRC_CNT(info->xmit.head,
+                                        info->xmit.tail,SERIAL_XMIT_SIZE)));
+
+               xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char,
+                               STOP_CHAR(info->port.tty));
+               xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop);
+               if (tty->termios->c_iflag & IXON ) {
+                       xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
+               }
+
+               *((unsigned long *)&info->ioport[REG_XOFF]) = xoff;
+               local_irq_restore(flags);
+       }
+}
+
+static void
+rs_start(struct tty_struct *tty)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       if (info) {
+               unsigned long flags;
+               unsigned long xoff;
+
+               local_irq_save(flags);
+               DFLOW(DEBUG_LOG(info->line, "XOFF rs_start xmit %i\n",
+                               CIRC_CNT(info->xmit.head,
+                                        info->xmit.tail,SERIAL_XMIT_SIZE)));
+               xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty));
+               xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
+               if (tty->termios->c_iflag & IXON ) {
+                       xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
+               }
+
+               *((unsigned long *)&info->ioport[REG_XOFF]) = xoff;
+               if (!info->uses_dma_out &&
+                   info->xmit.head != info->xmit.tail && info->xmit.buf)
+                       e100_enable_serial_tx_ready_irq(info);
+
+               local_irq_restore(flags);
+       }
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines.  All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt().  They were separated out for readability's sake.
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off.  People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible.  After you are done making modifications, it is not a bad
+ * idea to do:
+ *
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ *                             - Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static void rs_sched_event(struct e100_serial *info, int event)
+{
+       if (info->event & (1 << event))
+               return;
+       info->event |= 1 << event;
+       schedule_work(&info->work);
+}
+
+/* The output DMA channel is free - use it to send as many chars as possible
+ * NOTES:
+ *   We don't pay attention to info->x_char, which means if the TTY wants to
+ *   use XON/XOFF it will set info->x_char but we won't send any X char!
+ *
+ *   To implement this, we'd just start a DMA send of 1 byte pointing at a
+ *   buffer containing the X char, and skip updating xmit. We'd also have to
+ *   check if the last sent char was the X char when we enter this function
+ *   the next time, to avoid updating xmit with the sent X value.
+ */
+
+static void
+transmit_chars_dma(struct e100_serial *info)
+{
+       unsigned int c, sentl;
+       struct etrax_dma_descr *descr;
+
+#ifdef CONFIG_SVINTO_SIM
+       /* This will output too little if tail is not 0 always since
+        * we don't reloop to send the other part. Anyway this SHOULD be a
+        * no-op - transmit_chars_dma would never really be called during sim
+        * since rs_write does not write into the xmit buffer then.
+        */
+       if (info->xmit.tail)
+               printk("Error in serial.c:transmit_chars-dma(), tail!=0\n");
+       if (info->xmit.head != info->xmit.tail) {
+               SIMCOUT(info->xmit.buf + info->xmit.tail,
+                       CIRC_CNT(info->xmit.head,
+                                info->xmit.tail,
+                                SERIAL_XMIT_SIZE));
+               info->xmit.head = info->xmit.tail;  /* move back head */
+               info->tr_running = 0;
+       }
+       return;
+#endif
+       /* acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */
+       *info->oclrintradr =
+               IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
+               IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
+
+#ifdef SERIAL_DEBUG_INTR
+       if (info->line == SERIAL_DEBUG_LINE)
+               printk("tc\n");
+#endif
+       if (!info->tr_running) {
+               /* weirdo... we shouldn't get here! */
+               printk(KERN_WARNING "Achtung: transmit_chars_dma with !tr_running\n");
+               return;
+       }
+
+       descr = &info->tr_descr;
+
+       /* first get the amount of bytes sent during the last DMA transfer,
+          and update xmit accordingly */
+
+       /* if the stop bit was not set, all data has been sent */
+       if (!(descr->status & d_stop)) {
+               sentl = descr->sw_len;
+       } else
+               /* otherwise we find the amount of data sent here */
+               sentl = descr->hw_len;
+
+       DFLOW(DEBUG_LOG(info->line, "TX %i done\n", sentl));
+
+       /* update stats */
+       info->icount.tx += sentl;
+
+       /* update xmit buffer */
+       info->xmit.tail = (info->xmit.tail + sentl) & (SERIAL_XMIT_SIZE - 1);
+
+       /* if there is only a few chars left in the buf, wake up the blocked
+          write if any */
+       if (CIRC_CNT(info->xmit.head,
+                    info->xmit.tail,
+                    SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
+               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+
+       /* find out the largest amount of consecutive bytes we want to send now */
+
+       c = CIRC_CNT_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+
+       /* Don't send all in one DMA transfer - divide it so we wake up
+        * application before all is sent
+        */
+
+       if (c >= 4*WAKEUP_CHARS)
+               c = c/2;
+
+       if (c <= 0) {
+               /* our job here is done, don't schedule any new DMA transfer */
+               info->tr_running = 0;
+
+#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER)
+               if (info->rs485.flags & SER_RS485_ENABLED) {
+                       /* Set a short timer to toggle RTS */
+                       start_one_shot_timer(&fast_timers_rs485[info->line],
+                                            rs485_toggle_rts_timer_function,
+                                            (unsigned long)info,
+                                            info->char_time_usec*2,
+                                            "RS-485");
+               }
+#endif /* RS485 */
+               return;
+       }
+
+       /* ok we can schedule a dma send of c chars starting at info->xmit.tail */
+       /* set up the descriptor correctly for output */
+       DFLOW(DEBUG_LOG(info->line, "TX %i\n", c));
+       descr->ctrl = d_int | d_eol | d_wait; /* Wait needed for tty_wait_until_sent() */
+       descr->sw_len = c;
+       descr->buf = virt_to_phys(info->xmit.buf + info->xmit.tail);
+       descr->status = 0;
+
+       *info->ofirstadr = virt_to_phys(descr); /* write to R_DMAx_FIRST */
+       *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start);
+
+       /* DMA is now running (hopefully) */
+} /* transmit_chars_dma */
+
+static void
+start_transmit(struct e100_serial *info)
+{
+#if 0
+       if (info->line == SERIAL_DEBUG_LINE)
+               printk("x\n");
+#endif
+
+       info->tr_descr.sw_len = 0;
+       info->tr_descr.hw_len = 0;
+       info->tr_descr.status = 0;
+       info->tr_running = 1;
+       if (info->uses_dma_out)
+               transmit_chars_dma(info);
+       else
+               e100_enable_serial_tx_ready_irq(info);
+} /* start_transmit */
+
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+static int serial_fast_timer_started = 0;
+static int serial_fast_timer_expired = 0;
+static void flush_timeout_function(unsigned long data);
+#define START_FLUSH_FAST_TIMER_TIME(info, string, usec) {\
+  unsigned long timer_flags; \
+  local_irq_save(timer_flags); \
+  if (fast_timers[info->line].function == NULL) { \
+    serial_fast_timer_started++; \
+    TIMERD(DEBUG_LOG(info->line, "start_timer %i ", info->line)); \
+    TIMERD(DEBUG_LOG(info->line, "num started: %i\n", serial_fast_timer_started)); \
+    start_one_shot_timer(&fast_timers[info->line], \
+                         flush_timeout_function, \
+                         (unsigned long)info, \
+                         (usec), \
+                         string); \
+  } \
+  else { \
+    TIMERD(DEBUG_LOG(info->line, "timer %i already running\n", info->line)); \
+  } \
+  local_irq_restore(timer_flags); \
+}
+#define START_FLUSH_FAST_TIMER(info, string) START_FLUSH_FAST_TIMER_TIME(info, string, info->flush_time_usec)
+
+#else
+#define START_FLUSH_FAST_TIMER_TIME(info, string, usec)
+#define START_FLUSH_FAST_TIMER(info, string)
+#endif
+
+static struct etrax_recv_buffer *
+alloc_recv_buffer(unsigned int size)
+{
+       struct etrax_recv_buffer *buffer;
+
+       if (!(buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC)))
+               return NULL;
+
+       buffer->next = NULL;
+       buffer->length = 0;
+       buffer->error = TTY_NORMAL;
+
+       return buffer;
+}
+
+static void
+append_recv_buffer(struct e100_serial *info, struct etrax_recv_buffer *buffer)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       if (!info->first_recv_buffer)
+               info->first_recv_buffer = buffer;
+       else
+               info->last_recv_buffer->next = buffer;
+
+       info->last_recv_buffer = buffer;
+
+       info->recv_cnt += buffer->length;
+       if (info->recv_cnt > info->max_recv_cnt)
+               info->max_recv_cnt = info->recv_cnt;
+
+       local_irq_restore(flags);
+}
+
+static int
+add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char flag)
+{
+       struct etrax_recv_buffer *buffer;
+       if (info->uses_dma_in) {
+               if (!(buffer = alloc_recv_buffer(4)))
+                       return 0;
+
+               buffer->length = 1;
+               buffer->error = flag;
+               buffer->buffer[0] = data;
+
+               append_recv_buffer(info, buffer);
+
+               info->icount.rx++;
+       } else {
+               struct tty_struct *tty = info->port.tty;
+               tty_insert_flip_char(tty, data, flag);
+               info->icount.rx++;
+       }
+
+       return 1;
+}
+
+static unsigned int handle_descr_data(struct e100_serial *info,
+                                     struct etrax_dma_descr *descr,
+                                     unsigned int recvl)
+{
+       struct etrax_recv_buffer *buffer = phys_to_virt(descr->buf) - sizeof *buffer;
+
+       if (info->recv_cnt + recvl > 65536) {
+               printk(KERN_CRIT
+                      "%s: Too much pending incoming serial data! Dropping %u bytes.\n", __func__, recvl);
+               return 0;
+       }
+
+       buffer->length = recvl;
+
+       if (info->errorcode == ERRCODE_SET_BREAK)
+               buffer->error = TTY_BREAK;
+       info->errorcode = 0;
+
+       append_recv_buffer(info, buffer);
+
+       if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))
+               panic("%s: Failed to allocate memory for receive buffer!\n", __func__);
+
+       descr->buf = virt_to_phys(buffer->buffer);
+
+       return recvl;
+}
+
+static unsigned int handle_all_descr_data(struct e100_serial *info)
+{
+       struct etrax_dma_descr *descr;
+       unsigned int recvl;
+       unsigned int ret = 0;
+
+       while (1)
+       {
+               descr = &info->rec_descr[info->cur_rec_descr];
+
+               if (descr == phys_to_virt(*info->idescradr))
+                       break;
+
+               if (++info->cur_rec_descr == SERIAL_RECV_DESCRIPTORS)
+                       info->cur_rec_descr = 0;
+
+               /* find out how many bytes were read */
+
+               /* if the eop bit was not set, all data has been received */
+               if (!(descr->status & d_eop)) {
+                       recvl = descr->sw_len;
+               } else {
+                       /* otherwise we find the amount of data received here */
+                       recvl = descr->hw_len;
+               }
+
+               /* Reset the status information */
+               descr->status = 0;
+
+               DFLOW(  DEBUG_LOG(info->line, "RX %lu\n", recvl);
+                       if (info->port.tty->stopped) {
+                               unsigned char *buf = phys_to_virt(descr->buf);
+                               DEBUG_LOG(info->line, "rx 0x%02X\n", buf[0]);
+                               DEBUG_LOG(info->line, "rx 0x%02X\n", buf[1]);
+                               DEBUG_LOG(info->line, "rx 0x%02X\n", buf[2]);
+                       }
+                       );
+
+               /* update stats */
+               info->icount.rx += recvl;
+
+               ret += handle_descr_data(info, descr, recvl);
+       }
+
+       return ret;
+}
+
+static void receive_chars_dma(struct e100_serial *info)
+{
+       struct tty_struct *tty;
+       unsigned char rstat;
+
+#ifdef CONFIG_SVINTO_SIM
+       /* No receive in the simulator.  Will probably be when the rest of
+        * the serial interface works, and this piece will just be removed.
+        */
+       return;
+#endif
+
+       /* Acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */
+       *info->iclrintradr =
+               IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
+               IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
+
+       tty = info->port.tty;
+       if (!tty) /* Something wrong... */
+               return;
+
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+       if (info->uses_dma_in)
+               e100_enable_serial_data_irq(info);
+#endif
+
+       if (info->errorcode == ERRCODE_INSERT_BREAK)
+               add_char_and_flag(info, '\0', TTY_BREAK);
+
+       handle_all_descr_data(info);
+
+       /* Read the status register to detect errors */
+       rstat = info->ioport[REG_STATUS];
+       if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) {
+               DFLOW(DEBUG_LOG(info->line, "XOFF detect stat %x\n", rstat));
+       }
+
+       if (rstat & SER_ERROR_MASK) {
+               /* If we got an error, we must reset it by reading the
+                * data_in field
+                */
+               unsigned char data = info->ioport[REG_DATA];
+
+               PROCSTAT(ser_stat[info->line].errors_cnt++);
+               DEBUG_LOG(info->line, "#dERR: s d 0x%04X\n",
+                         ((rstat & SER_ERROR_MASK) << 8) | data);
+
+               if (rstat & SER_PAR_ERR_MASK)
+                       add_char_and_flag(info, data, TTY_PARITY);
+               else if (rstat & SER_OVERRUN_MASK)
+                       add_char_and_flag(info, data, TTY_OVERRUN);
+               else if (rstat & SER_FRAMING_ERR_MASK)
+                       add_char_and_flag(info, data, TTY_FRAME);
+       }
+
+       START_FLUSH_FAST_TIMER(info, "receive_chars");
+
+       /* Restart the receiving DMA */
+       *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
+}
+
+static int start_recv_dma(struct e100_serial *info)
+{
+       struct etrax_dma_descr *descr = info->rec_descr;
+       struct etrax_recv_buffer *buffer;
+        int i;
+
+       /* Set up the receiving descriptors */
+       for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) {
+               if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))
+                       panic("%s: Failed to allocate memory for receive buffer!\n", __func__);
+
+               descr[i].ctrl = d_int;
+               descr[i].buf = virt_to_phys(buffer->buffer);
+               descr[i].sw_len = SERIAL_DESCR_BUF_SIZE;
+               descr[i].hw_len = 0;
+               descr[i].status = 0;
+               descr[i].next = virt_to_phys(&descr[i+1]);
+       }
+
+       /* Link the last descriptor to the first */
+       descr[i-1].next = virt_to_phys(&descr[0]);
+
+       /* Start with the first descriptor in the list */
+       info->cur_rec_descr = 0;
+
+       /* Start the DMA */
+       *info->ifirstadr = virt_to_phys(&descr[info->cur_rec_descr]);
+       *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start);
+
+       /* Input DMA should be running now */
+       return 1;
+}
+
+static void
+start_receive(struct e100_serial *info)
+{
+#ifdef CONFIG_SVINTO_SIM
+       /* No receive in the simulator.  Will probably be when the rest of
+        * the serial interface works, and this piece will just be removed.
+        */
+       return;
+#endif
+       if (info->uses_dma_in) {
+               /* reset the input dma channel to be sure it works */
+
+               *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
+               while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
+                      IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
+
+               start_recv_dma(info);
+       }
+}
+
+
+/* the bits in the MASK2 register are laid out like this:
+   DMAI_EOP DMAI_DESCR DMAO_EOP DMAO_DESCR
+   where I is the input channel and O is the output channel for the port.
+   info->irq is the bit number for the DMAO_DESCR so to check the others we
+   shift info->irq to the left.
+*/
+
+/* dma output channel interrupt handler
+   this interrupt is called from DMA2(ser2), DMA4(ser3), DMA6(ser0) or
+   DMA8(ser1) when they have finished a descriptor with the intr flag set.
+*/
+
+static irqreturn_t
+tr_interrupt(int irq, void *dev_id)
+{
+       struct e100_serial *info;
+       unsigned long ireg;
+       int i;
+       int handled = 0;
+
+#ifdef CONFIG_SVINTO_SIM
+       /* No receive in the simulator.  Will probably be when the rest of
+        * the serial interface works, and this piece will just be removed.
+        */
+       {
+               const char *s = "What? tr_interrupt in simulator??\n";
+               SIMCOUT(s,strlen(s));
+       }
+       return IRQ_HANDLED;
+#endif
+
+       /* find out the line that caused this irq and get it from rs_table */
+
+       ireg = *R_IRQ_MASK2_RD;  /* get the active irq bits for the dma channels */
+
+       for (i = 0; i < NR_PORTS; i++) {
+               info = rs_table + i;
+               if (!info->enabled || !info->uses_dma_out)
+                       continue;
+               /* check for dma_descr (don't need to check for dma_eop in output dma for serial */
+               if (ireg & info->irq) {
+                       handled = 1;
+                       /* we can send a new dma bunch. make it so. */
+                       DINTR2(DEBUG_LOG(info->line, "tr_interrupt %i\n", i));
+                       /* Read jiffies_usec first,
+                        * we want this time to be as late as possible
+                        */
+                       PROCSTAT(ser_stat[info->line].tx_dma_ints++);
+                       info->last_tx_active_usec = GET_JIFFIES_USEC();
+                       info->last_tx_active = jiffies;
+                       transmit_chars_dma(info);
+               }
+
+               /* FIXME: here we should really check for a change in the
+                  status lines and if so call status_handle(info) */
+       }
+       return IRQ_RETVAL(handled);
+} /* tr_interrupt */
+
+/* dma input channel interrupt handler */
+
+static irqreturn_t
+rec_interrupt(int irq, void *dev_id)
+{
+       struct e100_serial *info;
+       unsigned long ireg;
+       int i;
+       int handled = 0;
+
+#ifdef CONFIG_SVINTO_SIM
+       /* No receive in the simulator.  Will probably be when the rest of
+        * the serial interface works, and this piece will just be removed.
+        */
+       {
+               const char *s = "What? rec_interrupt in simulator??\n";
+               SIMCOUT(s,strlen(s));
+       }
+       return IRQ_HANDLED;
+#endif
+
+       /* find out the line that caused this irq and get it from rs_table */
+
+       ireg = *R_IRQ_MASK2_RD;  /* get the active irq bits for the dma channels */
+
+       for (i = 0; i < NR_PORTS; i++) {
+               info = rs_table + i;
+               if (!info->enabled || !info->uses_dma_in)
+                       continue;
+               /* check for both dma_eop and dma_descr for the input dma channel */
+               if (ireg & ((info->irq << 2) | (info->irq << 3))) {
+                       handled = 1;
+                       /* we have received something */
+                       receive_chars_dma(info);
+               }
+
+               /* FIXME: here we should really check for a change in the
+                  status lines and if so call status_handle(info) */
+       }
+       return IRQ_RETVAL(handled);
+} /* rec_interrupt */
+
+static int force_eop_if_needed(struct e100_serial *info)
+{
+       /* We check data_avail bit to determine if data has
+        * arrived since last time
+        */
+       unsigned char rstat = info->ioport[REG_STATUS];
+
+       /* error or datavail? */
+       if (rstat & SER_ERROR_MASK) {
+               /* Some error has occurred. If there has been valid data, an
+                * EOP interrupt will be made automatically. If no data, the
+                * normal ser_interrupt should be enabled and handle it.
+                * So do nothing!
+                */
+               DEBUG_LOG(info->line, "timeout err: rstat 0x%03X\n",
+                         rstat | (info->line << 8));
+               return 0;
+       }
+
+       if (rstat & SER_DATA_AVAIL_MASK) {
+               /* Ok data, no error, count it */
+               TIMERD(DEBUG_LOG(info->line, "timeout: rstat 0x%03X\n",
+                         rstat | (info->line << 8)));
+               /* Read data to clear status flags */
+               (void)info->ioport[REG_DATA];
+
+               info->forced_eop = 0;
+               START_FLUSH_FAST_TIMER(info, "magic");
+               return 0;
+       }
+
+       /* hit the timeout, force an EOP for the input
+        * dma channel if we haven't already
+        */
+       if (!info->forced_eop) {
+               info->forced_eop = 1;
+               PROCSTAT(ser_stat[info->line].timeout_flush_cnt++);
+               TIMERD(DEBUG_LOG(info->line, "timeout EOP %i\n", info->line));
+               FORCE_EOP(info);
+       }
+
+       return 1;
+}
+
+static void flush_to_flip_buffer(struct e100_serial *info)
+{
+       struct tty_struct *tty;
+       struct etrax_recv_buffer *buffer;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       tty = info->port.tty;
+
+       if (!tty) {
+               local_irq_restore(flags);
+               return;
+       }
+
+       while ((buffer = info->first_recv_buffer) != NULL) {
+               unsigned int count = buffer->length;
+
+               tty_insert_flip_string(tty, buffer->buffer, count);
+               info->recv_cnt -= count;
+
+               if (count == buffer->length) {
+                       info->first_recv_buffer = buffer->next;
+                       kfree(buffer);
+               } else {
+                       buffer->length -= count;
+                       memmove(buffer->buffer, buffer->buffer + count, buffer->length);
+                       buffer->error = TTY_NORMAL;
+               }
+       }
+
+       if (!info->first_recv_buffer)
+               info->last_recv_buffer = NULL;
+
+       local_irq_restore(flags);
+
+       /* This includes a check for low-latency */
+       tty_flip_buffer_push(tty);
+}
+
+static void check_flush_timeout(struct e100_serial *info)
+{
+       /* Flip what we've got (if we can) */
+       flush_to_flip_buffer(info);
+
+       /* We might need to flip later, but not to fast
+        * since the system is busy processing input... */
+       if (info->first_recv_buffer)
+               START_FLUSH_FAST_TIMER_TIME(info, "flip", 2000);
+
+       /* Force eop last, since data might have come while we're processing
+        * and if we started the slow timer above, we won't start a fast
+        * below.
+        */
+       force_eop_if_needed(info);
+}
+
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+static void flush_timeout_function(unsigned long data)
+{
+       struct e100_serial *info = (struct e100_serial *)data;
+
+       fast_timers[info->line].function = NULL;
+       serial_fast_timer_expired++;
+       TIMERD(DEBUG_LOG(info->line, "flush_timout %i ", info->line));
+       TIMERD(DEBUG_LOG(info->line, "num expired: %i\n", serial_fast_timer_expired));
+       check_flush_timeout(info);
+}
+
+#else
+
+/* dma fifo/buffer timeout handler
+   forces an end-of-packet for the dma input channel if no chars
+   have been received for CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS/100 s.
+*/
+
+static struct timer_list flush_timer;
+
+static void
+timed_flush_handler(unsigned long ptr)
+{
+       struct e100_serial *info;
+       int i;
+
+#ifdef CONFIG_SVINTO_SIM
+       return;
+#endif
+
+       for (i = 0; i < NR_PORTS; i++) {
+               info = rs_table + i;
+               if (info->uses_dma_in)
+                       check_flush_timeout(info);
+       }
+
+       /* restart flush timer */
+       mod_timer(&flush_timer, jiffies + CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS);
+}
+#endif
+
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+
+/* If there is an error (ie break) when the DMA is running and
+ * there are no bytes in the fifo the DMA is stopped and we get no
+ * eop interrupt. Thus we have to monitor the first bytes on a DMA
+ * transfer, and if it is without error we can turn the serial
+ * interrupts off.
+ */
+
+/*
+BREAK handling on ETRAX 100:
+ETRAX will generate interrupt although there is no stop bit between the
+characters.
+
+Depending on how long the break sequence is, the end of the breaksequence
+will look differently:
+| indicates start/end of a character.
+
+B= Break character (0x00) with framing error.
+E= Error byte with parity error received after B characters.
+F= "Faked" valid byte received immediately after B characters.
+V= Valid byte
+
+1.
+    B          BL         ___________________________ V
+.._|__________|__________|                           |valid data |
+
+Multiple frame errors with data == 0x00 (B),
+the timing matches up "perfectly" so no extra ending char is detected.
+The RXD pin is 1 in the last interrupt, in that case
+we set info->errorcode = ERRCODE_INSERT_BREAK, but we can't really
+know if another byte will come and this really is case 2. below
+(e.g F=0xFF or 0xFE)
+If RXD pin is 0 we can expect another character (see 2. below).
+
+
+2.
+
+    B          B          E or F__________________..__ V
+.._|__________|__________|______    |                 |valid data
+                          "valid" or
+                          parity error
+
+Multiple frame errors with data == 0x00 (B),
+but the part of the break trigs is interpreted as a start bit (and possibly
+some 0 bits followed by a number of 1 bits and a stop bit).
+Depending on parity settings etc. this last character can be either
+a fake "valid" char (F) or have a parity error (E).
+
+If the character is valid it will be put in the buffer,
+we set info->errorcode = ERRCODE_SET_BREAK so the receive interrupt
+will set the flags so the tty will handle it,
+if it's an error byte it will not be put in the buffer
+and we set info->errorcode = ERRCODE_INSERT_BREAK.
+
+To distinguish a V byte in 1. from an F byte in 2. we keep a timestamp
+of the last faulty char (B) and compares it with the current time:
+If the time elapsed time is less then 2*char_time_usec we will assume
+it's a faked F char and not a Valid char and set
+info->errorcode = ERRCODE_SET_BREAK.
+
+Flaws in the above solution:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+We use the timer to distinguish a F character from a V character,
+if a V character is to close after the break we might make the wrong decision.
+
+TODO: The break will be delayed until an F or V character is received.
+
+*/
+
+static
+struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info)
+{
+       unsigned long data_read;
+       struct tty_struct *tty = info->port.tty;
+
+       if (!tty) {
+               printk("!NO TTY!\n");
+               return info;
+       }
+
+       /* Read data and status at the same time */
+       data_read = *((unsigned long *)&info->ioport[REG_DATA_STATUS32]);
+more_data:
+       if (data_read & IO_MASK(R_SERIAL0_READ, xoff_detect) ) {
+               DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0));
+       }
+       DINTR2(DEBUG_LOG(info->line, "ser_rx   %c\n", IO_EXTRACT(R_SERIAL0_READ, data_in, data_read)));
+
+       if (data_read & ( IO_MASK(R_SERIAL0_READ, framing_err) |
+                         IO_MASK(R_SERIAL0_READ, par_err) |
+                         IO_MASK(R_SERIAL0_READ, overrun) )) {
+               /* An error */
+               info->last_rx_active_usec = GET_JIFFIES_USEC();
+               info->last_rx_active = jiffies;
+               DINTR1(DEBUG_LOG(info->line, "ser_rx err stat_data %04X\n", data_read));
+               DLOG_INT_TRIG(
+               if (!log_int_trig1_pos) {
+                       log_int_trig1_pos = log_int_pos;
+                       log_int(rdpc(), 0, 0);
+               }
+               );
+
+
+               if ( ((data_read & IO_MASK(R_SERIAL0_READ, data_in)) == 0) &&
+                    (data_read & IO_MASK(R_SERIAL0_READ, framing_err)) ) {
+                       /* Most likely a break, but we get interrupts over and
+                        * over again.
+                        */
+
+                       if (!info->break_detected_cnt) {
+                               DEBUG_LOG(info->line, "#BRK start\n", 0);
+                       }
+                       if (data_read & IO_MASK(R_SERIAL0_READ, rxd)) {
+                               /* The RX pin is high now, so the break
+                                * must be over, but....
+                                * we can't really know if we will get another
+                                * last byte ending the break or not.
+                                * And we don't know if the byte (if any) will
+                                * have an error or look valid.
+                                */
+                               DEBUG_LOG(info->line, "# BL BRK\n", 0);
+                               info->errorcode = ERRCODE_INSERT_BREAK;
+                       }
+                       info->break_detected_cnt++;
+               } else {
+                       /* The error does not look like a break, but could be
+                        * the end of one
+                        */
+                       if (info->break_detected_cnt) {
+                               DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt);
+                               info->errorcode = ERRCODE_INSERT_BREAK;
+                       } else {
+                               unsigned char data = IO_EXTRACT(R_SERIAL0_READ,
+                                       data_in, data_read);
+                               char flag = TTY_NORMAL;
+                               if (info->errorcode == ERRCODE_INSERT_BREAK) {
+                                       struct tty_struct *tty = info->port.tty;
+                                       tty_insert_flip_char(tty, 0, flag);
+                                       info->icount.rx++;
+                               }
+
+                               if (data_read & IO_MASK(R_SERIAL0_READ, par_err)) {
+                                       info->icount.parity++;
+                                       flag = TTY_PARITY;
+                               } else if (data_read & IO_MASK(R_SERIAL0_READ, overrun)) {
+                                       info->icount.overrun++;
+                                       flag = TTY_OVERRUN;
+                               } else if (data_read & IO_MASK(R_SERIAL0_READ, framing_err)) {
+                                       info->icount.frame++;
+                                       flag = TTY_FRAME;
+                               }
+                               tty_insert_flip_char(tty, data, flag);
+                               info->errorcode = 0;
+                       }
+                       info->break_detected_cnt = 0;
+               }
+       } else if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) {
+               /* No error */
+               DLOG_INT_TRIG(
+               if (!log_int_trig1_pos) {
+                       if (log_int_pos >= log_int_size) {
+                               log_int_pos = 0;
+                       }
+                       log_int_trig0_pos = log_int_pos;
+                       log_int(rdpc(), 0, 0);
+               }
+               );
+               tty_insert_flip_char(tty,
+                       IO_EXTRACT(R_SERIAL0_READ, data_in, data_read),
+                       TTY_NORMAL);
+       } else {
+               DEBUG_LOG(info->line, "ser_rx int but no data_avail  %08lX\n", data_read);
+       }
+
+
+       info->icount.rx++;
+       data_read = *((unsigned long *)&info->ioport[REG_DATA_STATUS32]);
+       if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) {
+               DEBUG_LOG(info->line, "ser_rx   %c in loop\n", IO_EXTRACT(R_SERIAL0_READ, data_in, data_read));
+               goto more_data;
+       }
+
+       tty_flip_buffer_push(info->port.tty);
+       return info;
+}
+
+static struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info)
+{
+       unsigned char rstat;
+
+#ifdef SERIAL_DEBUG_INTR
+       printk("Interrupt from serport %d\n", i);
+#endif
+/*     DEBUG_LOG(info->line, "ser_interrupt stat %03X\n", rstat | (i << 8)); */
+       if (!info->uses_dma_in) {
+               return handle_ser_rx_interrupt_no_dma(info);
+       }
+       /* DMA is used */
+       rstat = info->ioport[REG_STATUS];
+       if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) {
+               DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0));
+       }
+
+       if (rstat & SER_ERROR_MASK) {
+               unsigned char data;
+
+               info->last_rx_active_usec = GET_JIFFIES_USEC();
+               info->last_rx_active = jiffies;
+               /* If we got an error, we must reset it by reading the
+                * data_in field
+                */
+               data = info->ioport[REG_DATA];
+               DINTR1(DEBUG_LOG(info->line, "ser_rx!  %c\n", data));
+               DINTR1(DEBUG_LOG(info->line, "ser_rx err stat %02X\n", rstat));
+               if (!data && (rstat & SER_FRAMING_ERR_MASK)) {
+                       /* Most likely a break, but we get interrupts over and
+                        * over again.
+                        */
+
+                       if (!info->break_detected_cnt) {
+                               DEBUG_LOG(info->line, "#BRK start\n", 0);
+                       }
+                       if (rstat & SER_RXD_MASK) {
+                               /* The RX pin is high now, so the break
+                                * must be over, but....
+                                * we can't really know if we will get another
+                                * last byte ending the break or not.
+                                * And we don't know if the byte (if any) will
+                                * have an error or look valid.
+                                */
+                               DEBUG_LOG(info->line, "# BL BRK\n", 0);
+                               info->errorcode = ERRCODE_INSERT_BREAK;
+                       }
+                       info->break_detected_cnt++;
+               } else {
+                       /* The error does not look like a break, but could be
+                        * the end of one
+                        */
+                       if (info->break_detected_cnt) {
+                               DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt);
+                               info->errorcode = ERRCODE_INSERT_BREAK;
+                       } else {
+                               if (info->errorcode == ERRCODE_INSERT_BREAK) {
+                                       info->icount.brk++;
+                                       add_char_and_flag(info, '\0', TTY_BREAK);
+                               }
+
+                               if (rstat & SER_PAR_ERR_MASK) {
+                                       info->icount.parity++;
+                                       add_char_and_flag(info, data, TTY_PARITY);
+                               } else if (rstat & SER_OVERRUN_MASK) {
+                                       info->icount.overrun++;
+                                       add_char_and_flag(info, data, TTY_OVERRUN);
+                               } else if (rstat & SER_FRAMING_ERR_MASK) {
+                                       info->icount.frame++;
+                                       add_char_and_flag(info, data, TTY_FRAME);
+                               }
+
+                               info->errorcode = 0;
+                       }
+                       info->break_detected_cnt = 0;
+                       DEBUG_LOG(info->line, "#iERR s d %04X\n",
+                                 ((rstat & SER_ERROR_MASK) << 8) | data);
+               }
+               PROCSTAT(ser_stat[info->line].early_errors_cnt++);
+       } else { /* It was a valid byte, now let the DMA do the rest */
+               unsigned long curr_time_u = GET_JIFFIES_USEC();
+               unsigned long curr_time = jiffies;
+
+               if (info->break_detected_cnt) {
+                       /* Detect if this character is a new valid char or the
+                        * last char in a break sequence: If LSBits are 0 and
+                        * MSBits are high AND the time is close to the
+                        * previous interrupt we should discard it.
+                        */
+                       long elapsed_usec =
+                         (curr_time - info->last_rx_active) * (1000000/HZ) +
+                         curr_time_u - info->last_rx_active_usec;
+                       if (elapsed_usec < 2*info->char_time_usec) {
+                               DEBUG_LOG(info->line, "FBRK %i\n", info->line);
+                               /* Report as BREAK (error) and let
+                                * receive_chars_dma() handle it
+                                */
+                               info->errorcode = ERRCODE_SET_BREAK;
+                       } else {
+                               DEBUG_LOG(info->line, "Not end of BRK (V)%i\n", info->line);
+                       }
+                       DEBUG_LOG(info->line, "num brk %i\n", info->break_detected_cnt);
+               }
+
+#ifdef SERIAL_DEBUG_INTR
+               printk("** OK, disabling ser_interrupts\n");
+#endif
+               e100_disable_serial_data_irq(info);
+               DINTR2(DEBUG_LOG(info->line, "ser_rx OK %d\n", info->line));
+               info->break_detected_cnt = 0;
+
+               PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++);
+       }
+       /* Restarting the DMA never hurts */
+       *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
+       START_FLUSH_FAST_TIMER(info, "ser_int");
+       return info;
+} /* handle_ser_rx_interrupt */
+
+static void handle_ser_tx_interrupt(struct e100_serial *info)
+{
+       unsigned long flags;
+
+       if (info->x_char) {
+               unsigned char rstat;
+               DFLOW(DEBUG_LOG(info->line, "tx_int: xchar 0x%02X\n", info->x_char));
+               local_irq_save(flags);
+               rstat = info->ioport[REG_STATUS];
+               DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat));
+
+               info->ioport[REG_TR_DATA] = info->x_char;
+               info->icount.tx++;
+               info->x_char = 0;
+               /* We must enable since it is disabled in ser_interrupt */
+               e100_enable_serial_tx_ready_irq(info);
+               local_irq_restore(flags);
+               return;
+       }
+       if (info->uses_dma_out) {
+               unsigned char rstat;
+               int i;
+               /* We only use normal tx interrupt when sending x_char */
+               DFLOW(DEBUG_LOG(info->line, "tx_int: xchar sent\n", 0));
+               local_irq_save(flags);
+               rstat = info->ioport[REG_STATUS];
+               DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat));
+               e100_disable_serial_tx_ready_irq(info);
+               if (info->port.tty->stopped)
+                       rs_stop(info->port.tty);
+               /* Enable the DMA channel and tell it to continue */
+               e100_enable_txdma_channel(info);
+               /* Wait 12 cycles before doing the DMA command */
+               for(i = 6;  i > 0; i--)
+                       nop();
+
+               *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, continue);
+               local_irq_restore(flags);
+               return;
+       }
+       /* Normal char-by-char interrupt */
+       if (info->xmit.head == info->xmit.tail
+           || info->port.tty->stopped
+           || info->port.tty->hw_stopped) {
+               DFLOW(DEBUG_LOG(info->line, "tx_int: stopped %i\n",
+                               info->port.tty->stopped));
+               e100_disable_serial_tx_ready_irq(info);
+               info->tr_running = 0;
+               return;
+       }
+       DINTR2(DEBUG_LOG(info->line, "tx_int %c\n", info->xmit.buf[info->xmit.tail]));
+       /* Send a byte, rs485 timing is critical so turn of ints */
+       local_irq_save(flags);
+       info->ioport[REG_TR_DATA] = info->xmit.buf[info->xmit.tail];
+       info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1);
+       info->icount.tx++;
+       if (info->xmit.head == info->xmit.tail) {
+#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER)
+               if (info->rs485.flags & SER_RS485_ENABLED) {
+                       /* Set a short timer to toggle RTS */
+                       start_one_shot_timer(&fast_timers_rs485[info->line],
+                                            rs485_toggle_rts_timer_function,
+                                            (unsigned long)info,
+                                            info->char_time_usec*2,
+                                            "RS-485");
+               }
+#endif /* RS485 */
+               info->last_tx_active_usec = GET_JIFFIES_USEC();
+               info->last_tx_active = jiffies;
+               e100_disable_serial_tx_ready_irq(info);
+               info->tr_running = 0;
+               DFLOW(DEBUG_LOG(info->line, "tx_int: stop2\n", 0));
+       } else {
+               /* We must enable since it is disabled in ser_interrupt */
+               e100_enable_serial_tx_ready_irq(info);
+       }
+       local_irq_restore(flags);
+
+       if (CIRC_CNT(info->xmit.head,
+                    info->xmit.tail,
+                    SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
+               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+
+} /* handle_ser_tx_interrupt */
+
+/* result of time measurements:
+ * RX duration 54-60 us when doing something, otherwise 6-9 us
+ * ser_int duration: just sending: 8-15 us normally, up to 73 us
+ */
+static irqreturn_t
+ser_interrupt(int irq, void *dev_id)
+{
+       static volatile int tx_started = 0;
+       struct e100_serial *info;
+       int i;
+       unsigned long flags;
+       unsigned long irq_mask1_rd;
+       unsigned long data_mask = (1 << (8+2*0)); /* ser0 data_avail */
+       int handled = 0;
+       static volatile unsigned long reentered_ready_mask = 0;
+
+       local_irq_save(flags);
+       irq_mask1_rd = *R_IRQ_MASK1_RD;
+       /* First handle all rx interrupts with ints disabled */
+       info = rs_table;
+       irq_mask1_rd &= e100_ser_int_mask;
+       for (i = 0; i < NR_PORTS; i++) {
+               /* Which line caused the data irq? */
+               if (irq_mask1_rd & data_mask) {
+                       handled = 1;
+                       handle_ser_rx_interrupt(info);
+               }
+               info += 1;
+               data_mask <<= 2;
+       }
+       /* Handle tx interrupts with interrupts enabled so we
+        * can take care of new data interrupts while transmitting
+        * We protect the tx part with the tx_started flag.
+        * We disable the tr_ready interrupts we are about to handle and
+        * unblock the serial interrupt so new serial interrupts may come.
+        *
+        * If we get a new interrupt:
+        *  - it migth be due to synchronous serial ports.
+        *  - serial irq will be blocked by general irq handler.
+        *  - async data will be handled above (sync will be ignored).
+        *  - tx_started flag will prevent us from trying to send again and
+        *    we will exit fast - no need to unblock serial irq.
+        *  - Next (sync) serial interrupt handler will be runned with
+        *    disabled interrupt due to restore_flags() at end of function,
+        *    so sync handler will not be preempted or reentered.
+        */
+       if (!tx_started) {
+               unsigned long ready_mask;
+               unsigned long
+               tx_started = 1;
+               /* Only the tr_ready interrupts left */
+               irq_mask1_rd &= (IO_MASK(R_IRQ_MASK1_RD, ser0_ready) |
+                                IO_MASK(R_IRQ_MASK1_RD, ser1_ready) |
+                                IO_MASK(R_IRQ_MASK1_RD, ser2_ready) |
+                                IO_MASK(R_IRQ_MASK1_RD, ser3_ready));
+               while (irq_mask1_rd) {
+                       /* Disable those we are about to handle */
+                       *R_IRQ_MASK1_CLR = irq_mask1_rd;
+                       /* Unblock the serial interrupt */
+                       *R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, serial, set);
+
+                       local_irq_enable();
+                       ready_mask = (1 << (8+1+2*0)); /* ser0 tr_ready */
+                       info = rs_table;
+                       for (i = 0; i < NR_PORTS; i++) {
+                               /* Which line caused the ready irq? */
+                               if (irq_mask1_rd & ready_mask) {
+                                       handled = 1;
+                                       handle_ser_tx_interrupt(info);
+                               }
+                               info += 1;
+                               ready_mask <<= 2;
+                       }
+                       /* handle_ser_tx_interrupt enables tr_ready interrupts */
+                       local_irq_disable();
+                       /* Handle reentered TX interrupt */
+                       irq_mask1_rd = reentered_ready_mask;
+               }
+               local_irq_disable();
+               tx_started = 0;
+       } else {
+               unsigned long ready_mask;
+               ready_mask = irq_mask1_rd & (IO_MASK(R_IRQ_MASK1_RD, ser0_ready) |
+                                            IO_MASK(R_IRQ_MASK1_RD, ser1_ready) |
+                                            IO_MASK(R_IRQ_MASK1_RD, ser2_ready) |
+                                            IO_MASK(R_IRQ_MASK1_RD, ser3_ready));
+               if (ready_mask) {
+                       reentered_ready_mask |= ready_mask;
+                       /* Disable those we are about to handle */
+                       *R_IRQ_MASK1_CLR = ready_mask;
+                       DFLOW(DEBUG_LOG(SERIAL_DEBUG_LINE, "ser_int reentered with TX %X\n", ready_mask));
+               }
+       }
+
+       local_irq_restore(flags);
+       return IRQ_RETVAL(handled);
+} /* ser_interrupt */
+#endif
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using rs_sched_event(), and they get done here.
+ */
+static void
+do_softint(struct work_struct *work)
+{
+       struct e100_serial      *info;
+       struct tty_struct       *tty;
+
+       info = container_of(work, struct e100_serial, work);
+
+       tty = info->port.tty;
+       if (!tty)
+               return;
+
+       if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event))
+               tty_wakeup(tty);
+}
+
+static int
+startup(struct e100_serial * info)
+{
+       unsigned long flags;
+       unsigned long xmit_page;
+       int i;
+
+       xmit_page = get_zeroed_page(GFP_KERNEL);
+       if (!xmit_page)
+               return -ENOMEM;
+
+       local_irq_save(flags);
+
+       /* if it was already initialized, skip this */
+
+       if (info->flags & ASYNC_INITIALIZED) {
+               local_irq_restore(flags);
+               free_page(xmit_page);
+               return 0;
+       }
+
+       if (info->xmit.buf)
+               free_page(xmit_page);
+       else
+               info->xmit.buf = (unsigned char *) xmit_page;
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("starting up ttyS%d (xmit_buf 0x%p)...\n", info->line, info->xmit.buf);
+#endif
+
+#ifdef CONFIG_SVINTO_SIM
+       /* Bits and pieces collected from below.  Better to have them
+          in one ifdef:ed clause than to mix in a lot of ifdefs,
+          right? */
+       if (info->port.tty)
+               clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
+
+       info->xmit.head = info->xmit.tail = 0;
+       info->first_recv_buffer = info->last_recv_buffer = NULL;
+       info->recv_cnt = info->max_recv_cnt = 0;
+
+       for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++)
+               info->rec_descr[i].buf = NULL;
+
+       /* No real action in the simulator, but may set info important
+          to ioctl. */
+       change_speed(info);
+#else
+
+       /*
+        * Clear the FIFO buffers and disable them
+        * (they will be reenabled in change_speed())
+        */
+
+       /*
+        * Reset the DMA channels and make sure their interrupts are cleared
+        */
+
+       if (info->dma_in_enabled) {
+               info->uses_dma_in = 1;
+               e100_enable_rxdma_channel(info);
+
+               *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
+
+               /* Wait until reset cycle is complete */
+               while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
+                      IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
+
+               /* Make sure the irqs are cleared */
+               *info->iclrintradr =
+                       IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
+                       IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
+       } else {
+               e100_disable_rxdma_channel(info);
+       }
+
+       if (info->dma_out_enabled) {
+               info->uses_dma_out = 1;
+               e100_enable_txdma_channel(info);
+               *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
+
+               while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) ==
+                      IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
+
+               /* Make sure the irqs are cleared */
+               *info->oclrintradr =
+                       IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
+                       IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
+       } else {
+               e100_disable_txdma_channel(info);
+       }
+
+       if (info->port.tty)
+               clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
+
+       info->xmit.head = info->xmit.tail = 0;
+       info->first_recv_buffer = info->last_recv_buffer = NULL;
+       info->recv_cnt = info->max_recv_cnt = 0;
+
+       for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++)
+               info->rec_descr[i].buf = 0;
+
+       /*
+        * and set the speed and other flags of the serial port
+        * this will start the rx/tx as well
+        */
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+       e100_enable_serial_data_irq(info);
+#endif
+       change_speed(info);
+
+       /* dummy read to reset any serial errors */
+
+       (void)info->ioport[REG_DATA];
+
+       /* enable the interrupts */
+       if (info->uses_dma_out)
+               e100_enable_txdma_irq(info);
+
+       e100_enable_rx_irq(info);
+
+       info->tr_running = 0; /* to be sure we don't lock up the transmitter */
+
+       /* setup the dma input descriptor and start dma */
+
+       start_receive(info);
+
+       /* for safety, make sure the descriptors last result is 0 bytes written */
+
+       info->tr_descr.sw_len = 0;
+       info->tr_descr.hw_len = 0;
+       info->tr_descr.status = 0;
+
+       /* enable RTS/DTR last */
+
+       e100_rts(info, 1);
+       e100_dtr(info, 1);
+
+#endif /* CONFIG_SVINTO_SIM */
+
+       info->flags |= ASYNC_INITIALIZED;
+
+       local_irq_restore(flags);
+       return 0;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void
+shutdown(struct e100_serial * info)
+{
+       unsigned long flags;
+       struct etrax_dma_descr *descr = info->rec_descr;
+       struct etrax_recv_buffer *buffer;
+       int i;
+
+#ifndef CONFIG_SVINTO_SIM
+       /* shut down the transmitter and receiver */
+       DFLOW(DEBUG_LOG(info->line, "shutdown %i\n", info->line));
+       e100_disable_rx(info);
+       info->ioport[REG_TR_CTRL] = (info->tx_ctrl &= ~0x40);
+
+       /* disable interrupts, reset dma channels */
+       if (info->uses_dma_in) {
+               e100_disable_rxdma_irq(info);
+               *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
+               info->uses_dma_in = 0;
+       } else {
+               e100_disable_serial_data_irq(info);
+       }
+
+       if (info->uses_dma_out) {
+               e100_disable_txdma_irq(info);
+               info->tr_running = 0;
+               *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
+               info->uses_dma_out = 0;
+       } else {
+               e100_disable_serial_tx_ready_irq(info);
+               info->tr_running = 0;
+       }
+
+#endif /* CONFIG_SVINTO_SIM */
+
+       if (!(info->flags & ASYNC_INITIALIZED))
+               return;
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("Shutting down serial port %d (irq %d)....\n", info->line,
+              info->irq);
+#endif
+
+       local_irq_save(flags);
+
+       if (info->xmit.buf) {
+               free_page((unsigned long)info->xmit.buf);
+               info->xmit.buf = NULL;
+       }
+
+       for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++)
+               if (descr[i].buf) {
+                       buffer = phys_to_virt(descr[i].buf) - sizeof *buffer;
+                       kfree(buffer);
+                       descr[i].buf = 0;
+               }
+
+       if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) {
+               /* hang up DTR and RTS if HUPCL is enabled */
+               e100_dtr(info, 0);
+               e100_rts(info, 0); /* could check CRTSCTS before doing this */
+       }
+
+       if (info->port.tty)
+               set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+
+       info->flags &= ~ASYNC_INITIALIZED;
+       local_irq_restore(flags);
+}
+
+
+/* change baud rate and other assorted parameters */
+
+static void
+change_speed(struct e100_serial *info)
+{
+       unsigned int cflag;
+       unsigned long xoff;
+       unsigned long flags;
+       /* first some safety checks */
+
+       if (!info->port.tty || !info->port.tty->termios)
+               return;
+       if (!info->ioport)
+               return;
+
+       cflag = info->port.tty->termios->c_cflag;
+
+       /* possibly, the tx/rx should be disabled first to do this safely */
+
+       /* change baud-rate and write it to the hardware */
+       if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) {
+               /* Special baudrate */
+               u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */
+               unsigned long alt_source =
+                               IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, normal) |
+                               IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal);
+               /* R_ALT_SER_BAUDRATE selects the source */
+               DBAUD(printk("Custom baudrate: baud_base/divisor %lu/%i\n",
+                      (unsigned long)info->baud_base, info->custom_divisor));
+               if (info->baud_base == SERIAL_PRESCALE_BASE) {
+                       /* 0, 2-65535 (0=65536) */
+                       u16 divisor = info->custom_divisor;
+                       /* R_SERIAL_PRESCALE (upper 16 bits of R_CLOCK_PRESCALE) */
+                       /* baudrate is 3.125MHz/custom_divisor */
+                       alt_source =
+                               IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, prescale) |
+                               IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, prescale);
+                       alt_source = 0x11;
+                       DBAUD(printk("Writing SERIAL_PRESCALE: divisor %i\n", divisor));
+                       *R_SERIAL_PRESCALE = divisor;
+                       info->baud = SERIAL_PRESCALE_BASE/divisor;
+               }
+#ifdef CONFIG_ETRAX_EXTERN_PB6CLK_ENABLED
+               else if ((info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8 &&
+                         info->custom_divisor == 1) ||
+                        (info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ &&
+                         info->custom_divisor == 8)) {
+                               /* ext_clk selected */
+                               alt_source =
+                                       IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, extern) |
+                                       IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, extern);
+                               DBAUD(printk("using external baudrate: %lu\n", CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8));
+                               info->baud = CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8;
+                       }
+#endif
+               else
+               {
+                       /* Bad baudbase, we don't support using timer0
+                        * for baudrate.
+                        */
+                       printk(KERN_WARNING "Bad baud_base/custom_divisor: %lu/%i\n",
+                              (unsigned long)info->baud_base, info->custom_divisor);
+               }
+               r_alt_ser_baudrate_shadow &= ~mask;
+               r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8));
+               *R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow;
+       } else {
+               /* Normal baudrate */
+               /* Make sure we use normal baudrate */
+               u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */
+               unsigned long alt_source =
+                       IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, normal) |
+                       IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal);
+               r_alt_ser_baudrate_shadow &= ~mask;
+               r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8));
+#ifndef CONFIG_SVINTO_SIM
+               *R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow;
+#endif /* CONFIG_SVINTO_SIM */
+
+               info->baud = cflag_to_baud(cflag);
+#ifndef CONFIG_SVINTO_SIM
+               info->ioport[REG_BAUD] = cflag_to_etrax_baud(cflag);
+#endif /* CONFIG_SVINTO_SIM */
+       }
+
+#ifndef CONFIG_SVINTO_SIM
+       /* start with default settings and then fill in changes */
+       local_irq_save(flags);
+       /* 8 bit, no/even parity */
+       info->rx_ctrl &= ~(IO_MASK(R_SERIAL0_REC_CTRL, rec_bitnr) |
+                          IO_MASK(R_SERIAL0_REC_CTRL, rec_par_en) |
+                          IO_MASK(R_SERIAL0_REC_CTRL, rec_par));
+
+       /* 8 bit, no/even parity, 1 stop bit, no cts */
+       info->tx_ctrl &= ~(IO_MASK(R_SERIAL0_TR_CTRL, tr_bitnr) |
+                          IO_MASK(R_SERIAL0_TR_CTRL, tr_par_en) |
+                          IO_MASK(R_SERIAL0_TR_CTRL, tr_par) |
+                          IO_MASK(R_SERIAL0_TR_CTRL, stop_bits) |
+                          IO_MASK(R_SERIAL0_TR_CTRL, auto_cts));
+
+       if ((cflag & CSIZE) == CS7) {
+               /* set 7 bit mode */
+               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_7bit);
+               info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_7bit);
+       }
+
+       if (cflag & CSTOPB) {
+               /* set 2 stop bit mode */
+               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, stop_bits, two_bits);
+       }
+
+       if (cflag & PARENB) {
+               /* enable parity */
+               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable);
+               info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable);
+       }
+
+       if (cflag & CMSPAR) {
+               /* enable stick parity, PARODD mean Mark which matches ETRAX */
+               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_stick_par, stick);
+               info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_stick_par, stick);
+       }
+       if (cflag & PARODD) {
+               /* set odd parity (or Mark if CMSPAR) */
+               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd);
+               info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd);
+       }
+
+       if (cflag & CRTSCTS) {
+               /* enable automatic CTS handling */
+               DFLOW(DEBUG_LOG(info->line, "FLOW auto_cts enabled\n", 0));
+               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, auto_cts, active);
+       }
+
+       /* make sure the tx and rx are enabled */
+
+       info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_enable, enable);
+       info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable);
+
+       /* actually write the control regs to the hardware */
+
+       info->ioport[REG_TR_CTRL] = info->tx_ctrl;
+       info->ioport[REG_REC_CTRL] = info->rx_ctrl;
+       xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->port.tty));
+       xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
+       if (info->port.tty->termios->c_iflag & IXON ) {
+               DFLOW(DEBUG_LOG(info->line, "FLOW XOFF enabled 0x%02X\n",
+                               STOP_CHAR(info->port.tty)));
+               xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
+       }
+
+       *((unsigned long *)&info->ioport[REG_XOFF]) = xoff;
+       local_irq_restore(flags);
+#endif /* !CONFIG_SVINTO_SIM */
+
+       update_char_time(info);
+
+} /* change_speed */
+
+/* start transmitting chars NOW */
+
+static void
+rs_flush_chars(struct tty_struct *tty)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       unsigned long flags;
+
+       if (info->tr_running ||
+           info->xmit.head == info->xmit.tail ||
+           tty->stopped ||
+           tty->hw_stopped ||
+           !info->xmit.buf)
+               return;
+
+#ifdef SERIAL_DEBUG_FLOW
+       printk("rs_flush_chars\n");
+#endif
+
+       /* this protection might not exactly be necessary here */
+
+       local_irq_save(flags);
+       start_transmit(info);
+       local_irq_restore(flags);
+}
+
+static int rs_raw_write(struct tty_struct *tty,
+                       const unsigned char *buf, int count)
+{
+       int     c, ret = 0;
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       unsigned long flags;
+
+       /* first some sanity checks */
+
+       if (!tty || !info->xmit.buf || !tmp_buf)
+               return 0;
+
+#ifdef SERIAL_DEBUG_DATA
+       if (info->line == SERIAL_DEBUG_LINE)
+               printk("rs_raw_write (%d), status %d\n",
+                      count, info->ioport[REG_STATUS]);
+#endif
+
+#ifdef CONFIG_SVINTO_SIM
+       /* Really simple.  The output is here and now. */
+       SIMCOUT(buf, count);
+       return count;
+#endif
+       local_save_flags(flags);
+       DFLOW(DEBUG_LOG(info->line, "write count %i ", count));
+       DFLOW(DEBUG_LOG(info->line, "ldisc %i\n", tty->ldisc.chars_in_buffer(tty)));
+
+
+       /* The local_irq_disable/restore_flags pairs below are needed
+        * because the DMA interrupt handler moves the info->xmit values.
+        * the memcpy needs to be in the critical region unfortunately,
+        * because we need to read xmit values, memcpy, write xmit values
+        * in one atomic operation... this could perhaps be avoided by
+        * more clever design.
+        */
+       local_irq_disable();
+               while (count) {
+                       c = CIRC_SPACE_TO_END(info->xmit.head,
+                                             info->xmit.tail,
+                                             SERIAL_XMIT_SIZE);
+
+                       if (count < c)
+                               c = count;
+                       if (c <= 0)
+                               break;
+
+                       memcpy(info->xmit.buf + info->xmit.head, buf, c);
+                       info->xmit.head = (info->xmit.head + c) &
+                               (SERIAL_XMIT_SIZE-1);
+                       buf += c;
+                       count -= c;
+                       ret += c;
+               }
+       local_irq_restore(flags);
+
+       /* enable transmitter if not running, unless the tty is stopped
+        * this does not need IRQ protection since if tr_running == 0
+        * the IRQ's are not running anyway for this port.
+        */
+       DFLOW(DEBUG_LOG(info->line, "write ret %i\n", ret));
+
+       if (info->xmit.head != info->xmit.tail &&
+           !tty->stopped &&
+           !tty->hw_stopped &&
+           !info->tr_running) {
+               start_transmit(info);
+       }
+
+       return ret;
+} /* raw_raw_write() */
+
+static int
+rs_write(struct tty_struct *tty,
+        const unsigned char *buf, int count)
+{
+#if defined(CONFIG_ETRAX_RS485)
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+
+       if (info->rs485.flags & SER_RS485_ENABLED)
+       {
+               /* If we are in RS-485 mode, we need to toggle RTS and disable
+                * the receiver before initiating a DMA transfer
+                */
+#ifdef CONFIG_ETRAX_FAST_TIMER
+               /* Abort any started timer */
+               fast_timers_rs485[info->line].function = NULL;
+               del_fast_timer(&fast_timers_rs485[info->line]);
+#endif
+               e100_rts(info, (info->rs485.flags & SER_RS485_RTS_ON_SEND));
+#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
+               e100_disable_rx(info);
+               e100_enable_rx_irq(info);
+#endif
+               if ((info->rs485.flags & SER_RS485_RTS_BEFORE_SEND) &&
+                       (info->rs485.delay_rts_before_send > 0))
+                               msleep(info->rs485.delay_rts_before_send);
+       }
+#endif /* CONFIG_ETRAX_RS485 */
+
+       count = rs_raw_write(tty, buf, count);
+
+#if defined(CONFIG_ETRAX_RS485)
+       if (info->rs485.flags & SER_RS485_ENABLED)
+       {
+               unsigned int val;
+               /* If we are in RS-485 mode the following has to be done:
+                * wait until DMA is ready
+                * wait on transmit shift register
+                * toggle RTS
+                * enable the receiver
+                */
+
+               /* Sleep until all sent */
+               tty_wait_until_sent(tty, 0);
+#ifdef CONFIG_ETRAX_FAST_TIMER
+               /* Now sleep a little more so that shift register is empty */
+               schedule_usleep(info->char_time_usec * 2);
+#endif
+               /* wait on transmit shift register */
+               do{
+                       get_lsr_info(info, &val);
+               }while (!(val & TIOCSER_TEMT));
+
+               e100_rts(info, (info->rs485.flags & SER_RS485_RTS_AFTER_SEND));
+
+#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
+               e100_enable_rx(info);
+               e100_enable_rxdma_irq(info);
+#endif
+       }
+#endif /* CONFIG_ETRAX_RS485 */
+
+       return count;
+} /* rs_write */
+
+
+/* how much space is available in the xmit buffer? */
+
+static int
+rs_write_room(struct tty_struct *tty)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+
+       return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+}
+
+/* How many chars are in the xmit buffer?
+ * This does not include any chars in the transmitter FIFO.
+ * Use wait_until_sent for waiting for FIFO drain.
+ */
+
+static int
+rs_chars_in_buffer(struct tty_struct *tty)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+
+       return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+}
+
+/* discard everything in the xmit buffer */
+
+static void
+rs_flush_buffer(struct tty_struct *tty)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       info->xmit.head = info->xmit.tail = 0;
+       local_irq_restore(flags);
+
+       tty_wakeup(tty);
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ *
+ * Since we use DMA we don't check for info->x_char in transmit_chars_dma(),
+ * but we do it in handle_ser_tx_interrupt().
+ * We disable DMA channel and enable tx ready interrupt and write the
+ * character when possible.
+ */
+static void rs_send_xchar(struct tty_struct *tty, char ch)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       unsigned long flags;
+       local_irq_save(flags);
+       if (info->uses_dma_out) {
+               /* Put the DMA on hold and disable the channel */
+               *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, hold);
+               while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) !=
+                      IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, hold));
+               e100_disable_txdma_channel(info);
+       }
+
+       /* Must make sure transmitter is not stopped before we can transmit */
+       if (tty->stopped)
+               rs_start(tty);
+
+       /* Enable manual transmit interrupt and send from there */
+       DFLOW(DEBUG_LOG(info->line, "rs_send_xchar 0x%02X\n", ch));
+       info->x_char = ch;
+       e100_enable_serial_tx_ready_irq(info);
+       local_irq_restore(flags);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ *
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void
+rs_throttle(struct tty_struct * tty)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+       char    buf[64];
+
+       printk("throttle %s: %lu....\n", tty_name(tty, buf),
+              (unsigned long)tty->ldisc.chars_in_buffer(tty));
+#endif
+       DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty)));
+
+       /* Do RTS before XOFF since XOFF might take some time */
+       if (tty->termios->c_cflag & CRTSCTS) {
+               /* Turn off RTS line */
+               e100_rts(info, 0);
+       }
+       if (I_IXOFF(tty))
+               rs_send_xchar(tty, STOP_CHAR(tty));
+
+}
+
+static void
+rs_unthrottle(struct tty_struct * tty)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+       char    buf[64];
+
+       printk("unthrottle %s: %lu....\n", tty_name(tty, buf),
+              (unsigned long)tty->ldisc.chars_in_buffer(tty));
+#endif
+       DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty)));
+       DFLOW(DEBUG_LOG(info->line,"rs_unthrottle flip.count: %i\n", tty->flip.count));
+       /* Do RTS before XOFF since XOFF might take some time */
+       if (tty->termios->c_cflag & CRTSCTS) {
+               /* Assert RTS line  */
+               e100_rts(info, 1);
+       }
+
+       if (I_IXOFF(tty)) {
+               if (info->x_char)
+                       info->x_char = 0;
+               else
+                       rs_send_xchar(tty, START_CHAR(tty));
+       }
+
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static int
+get_serial_info(struct e100_serial * info,
+               struct serial_struct * retinfo)
+{
+       struct serial_struct tmp;
+
+       /* this is all probably wrong, there are a lot of fields
+        * here that we don't have in e100_serial and maybe we
+        * should set them to something else than 0.
+        */
+
+       if (!retinfo)
+               return -EFAULT;
+       memset(&tmp, 0, sizeof(tmp));
+       tmp.type = info->type;
+       tmp.line = info->line;
+       tmp.port = (int)info->ioport;
+       tmp.irq = info->irq;
+       tmp.flags = info->flags;
+       tmp.baud_base = info->baud_base;
+       tmp.close_delay = info->close_delay;
+       tmp.closing_wait = info->closing_wait;
+       tmp.custom_divisor = info->custom_divisor;
+       if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+               return -EFAULT;
+       return 0;
+}
+
+static int
+set_serial_info(struct e100_serial *info,
+               struct serial_struct *new_info)
+{
+       struct serial_struct new_serial;
+       struct e100_serial old_info;
+       int retval = 0;
+
+       if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
+               return -EFAULT;
+
+       old_info = *info;
+
+       if (!capable(CAP_SYS_ADMIN)) {
+               if ((new_serial.type != info->type) ||
+                   (new_serial.close_delay != info->close_delay) ||
+                   ((new_serial.flags & ~ASYNC_USR_MASK) !=
+                    (info->flags & ~ASYNC_USR_MASK)))
+                       return -EPERM;
+               info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+                              (new_serial.flags & ASYNC_USR_MASK));
+               goto check_and_exit;
+       }
+
+       if (info->count > 1)
+               return -EBUSY;
+
+       /*
+        * OK, past this point, all the error checking has been done.
+        * At this point, we start making changes.....
+        */
+
+       info->baud_base = new_serial.baud_base;
+       info->flags = ((info->flags & ~ASYNC_FLAGS) |
+                      (new_serial.flags & ASYNC_FLAGS));
+       info->custom_divisor = new_serial.custom_divisor;
+       info->type = new_serial.type;
+       info->close_delay = new_serial.close_delay;
+       info->closing_wait = new_serial.closing_wait;
+       info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+ check_and_exit:
+       if (info->flags & ASYNC_INITIALIZED) {
+               change_speed(info);
+       } else
+               retval = startup(info);
+       return retval;
+}
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ *         is emptied.  On bus types like RS485, the transmitter must
+ *         release the bus after transmitting. This must be done when
+ *         the transmit shift register is empty, not be done when the
+ *         transmit holding register is empty.  This functionality
+ *         allows an RS485 driver to be written in user space.
+ */
+static int
+get_lsr_info(struct e100_serial * info, unsigned int *value)
+{
+       unsigned int result = TIOCSER_TEMT;
+#ifndef CONFIG_SVINTO_SIM
+       unsigned long curr_time = jiffies;
+       unsigned long curr_time_usec = GET_JIFFIES_USEC();
+       unsigned long elapsed_usec =
+               (curr_time - info->last_tx_active) * 1000000/HZ +
+               curr_time_usec - info->last_tx_active_usec;
+
+       if (info->xmit.head != info->xmit.tail ||
+           elapsed_usec < 2*info->char_time_usec) {
+               result = 0;
+       }
+#endif
+
+       if (copy_to_user(value, &result, sizeof(int)))
+               return -EFAULT;
+       return 0;
+}
+
+#ifdef SERIAL_DEBUG_IO
+struct state_str
+{
+       int state;
+       const char *str;
+};
+
+const struct state_str control_state_str[] = {
+       {TIOCM_DTR, "DTR" },
+       {TIOCM_RTS, "RTS"},
+       {TIOCM_ST, "ST?" },
+       {TIOCM_SR, "SR?" },
+       {TIOCM_CTS, "CTS" },
+       {TIOCM_CD, "CD" },
+       {TIOCM_RI, "RI" },
+       {TIOCM_DSR, "DSR" },
+       {0, NULL }
+};
+
+char *get_control_state_str(int MLines, char *s)
+{
+       int i = 0;
+
+       s[0]='\0';
+       while (control_state_str[i].str != NULL) {
+               if (MLines & control_state_str[i].state) {
+                       if (s[0] != '\0') {
+                               strcat(s, ", ");
+                       }
+                       strcat(s, control_state_str[i].str);
+               }
+               i++;
+       }
+       return s;
+}
+#endif
+
+static int
+rs_break(struct tty_struct *tty, int break_state)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       unsigned long flags;
+
+       if (!info->ioport)
+               return -EIO;
+
+       local_irq_save(flags);
+       if (break_state == -1) {
+               /* Go to manual mode and set the txd pin to 0 */
+               /* Clear bit 7 (txd) and 6 (tr_enable) */
+               info->tx_ctrl &= 0x3F;
+       } else {
+               /* Set bit 7 (txd) and 6 (tr_enable) */
+               info->tx_ctrl |= (0x80 | 0x40);
+       }
+       info->ioport[REG_TR_CTRL] = info->tx_ctrl;
+       local_irq_restore(flags);
+       return 0;
+}
+
+static int
+rs_tiocmset(struct tty_struct *tty, struct file *file,
+               unsigned int set, unsigned int clear)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       if (clear & TIOCM_RTS)
+               e100_rts(info, 0);
+       if (clear & TIOCM_DTR)
+               e100_dtr(info, 0);
+       /* Handle FEMALE behaviour */
+       if (clear & TIOCM_RI)
+               e100_ri_out(info, 0);
+       if (clear & TIOCM_CD)
+               e100_cd_out(info, 0);
+
+       if (set & TIOCM_RTS)
+               e100_rts(info, 1);
+       if (set & TIOCM_DTR)
+               e100_dtr(info, 1);
+       /* Handle FEMALE behaviour */
+       if (set & TIOCM_RI)
+               e100_ri_out(info, 1);
+       if (set & TIOCM_CD)
+               e100_cd_out(info, 1);
+
+       local_irq_restore(flags);
+       return 0;
+}
+
+static int
+rs_tiocmget(struct tty_struct *tty, struct file *file)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       unsigned int result;
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       result =
+               (!E100_RTS_GET(info) ? TIOCM_RTS : 0)
+               | (!E100_DTR_GET(info) ? TIOCM_DTR : 0)
+               | (!E100_RI_GET(info) ? TIOCM_RNG : 0)
+               | (!E100_DSR_GET(info) ? TIOCM_DSR : 0)
+               | (!E100_CD_GET(info) ? TIOCM_CAR : 0)
+               | (!E100_CTS_GET(info) ? TIOCM_CTS : 0);
+
+       local_irq_restore(flags);
+
+#ifdef SERIAL_DEBUG_IO
+       printk(KERN_DEBUG "ser%i: modem state: %i 0x%08X\n",
+               info->line, result, result);
+       {
+               char s[100];
+
+               get_control_state_str(result, s);
+               printk(KERN_DEBUG "state: %s\n", s);
+       }
+#endif
+       return result;
+
+}
+
+
+static int
+rs_ioctl(struct tty_struct *tty, struct file * file,
+        unsigned int cmd, unsigned long arg)
+{
+       struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+
+       if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+           (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
+           (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
+               if (tty->flags & (1 << TTY_IO_ERROR))
+                       return -EIO;
+       }
+
+       switch (cmd) {
+       case TIOCGSERIAL:
+               return get_serial_info(info,
+                                      (struct serial_struct *) arg);
+       case TIOCSSERIAL:
+               return set_serial_info(info,
+                                      (struct serial_struct *) arg);
+       case TIOCSERGETLSR: /* Get line status register */
+               return get_lsr_info(info, (unsigned int *) arg);
+
+       case TIOCSERGSTRUCT:
+               if (copy_to_user((struct e100_serial *) arg,
+                                info, sizeof(struct e100_serial)))
+                       return -EFAULT;
+               return 0;
+
+#if defined(CONFIG_ETRAX_RS485)
+       case TIOCSERSETRS485:
+       {
+               /* In this ioctl we still use the old structure
+                * rs485_control for backward compatibility
+                * (if we use serial_rs485, then old user-level code
+                * wouldn't work anymore...).
+                * The use of this ioctl is deprecated: use TIOCSRS485
+                * instead.*/
+               struct rs485_control rs485ctrl;
+               struct serial_rs485 rs485data;
+               printk(KERN_DEBUG "The use of this ioctl is deprecated. Use TIOCSRS485 instead\n");
+               if (copy_from_user(&rs485ctrl, (struct rs485_control *)arg,
+                               sizeof(rs485ctrl)))
+                       return -EFAULT;
+
+               rs485data.delay_rts_before_send = rs485ctrl.delay_rts_before_send;
+               rs485data.flags = 0;
+               if (rs485data.delay_rts_before_send != 0)
+                       rs485data.flags |= SER_RS485_RTS_BEFORE_SEND;
+               else
+                       rs485data.flags &= ~(SER_RS485_RTS_BEFORE_SEND);
+
+               if (rs485ctrl.enabled)
+                       rs485data.flags |= SER_RS485_ENABLED;
+               else
+                       rs485data.flags &= ~(SER_RS485_ENABLED);
+
+               if (rs485ctrl.rts_on_send)
+                       rs485data.flags |= SER_RS485_RTS_ON_SEND;
+               else
+                       rs485data.flags &= ~(SER_RS485_RTS_ON_SEND);
+
+               if (rs485ctrl.rts_after_sent)
+                       rs485data.flags |= SER_RS485_RTS_AFTER_SEND;
+               else
+                       rs485data.flags &= ~(SER_RS485_RTS_AFTER_SEND);
+
+               return e100_enable_rs485(tty, &rs485data);
+       }
+
+       case TIOCSRS485:
+       {
+               /* This is the new version of TIOCSRS485, with new
+                * data structure serial_rs485 */
+               struct serial_rs485 rs485data;
+               if (copy_from_user(&rs485data, (struct rs485_control *)arg,
+                               sizeof(rs485data)))
+                       return -EFAULT;
+
+               return e100_enable_rs485(tty, &rs485data);
+       }
+
+       case TIOCGRS485:
+       {
+               struct serial_rs485 *rs485data =
+                       &(((struct e100_serial *)tty->driver_data)->rs485);
+               /* This is the ioctl to get RS485 data from user-space */
+               if (copy_to_user((struct serial_rs485 *) arg,
+                                       rs485data,
+                                       sizeof(struct serial_rs485)))
+                       return -EFAULT;
+               break;
+       }
+
+       case TIOCSERWRRS485:
+       {
+               struct rs485_write rs485wr;
+               if (copy_from_user(&rs485wr, (struct rs485_write *)arg,
+                               sizeof(rs485wr)))
+                       return -EFAULT;
+
+               return e100_write_rs485(tty, rs485wr.outc, rs485wr.outc_size);
+       }
+#endif
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+       return 0;
+}
+
+static void
+rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+
+       change_speed(info);
+
+       /* Handle turning off CRTSCTS */
+       if ((old_termios->c_cflag & CRTSCTS) &&
+           !(tty->termios->c_cflag & CRTSCTS)) {
+               tty->hw_stopped = 0;
+               rs_start(tty);
+       }
+
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ *
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * S structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void
+rs_close(struct tty_struct *tty, struct file * filp)
+{
+       struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+       unsigned long flags;
+
+       if (!info)
+               return;
+
+       /* interrupts are disabled for this entire function */
+
+       local_irq_save(flags);
+
+       if (tty_hung_up_p(filp)) {
+               local_irq_restore(flags);
+               return;
+       }
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("[%d] rs_close ttyS%d, count = %d\n", current->pid,
+              info->line, info->count);
+#endif
+       if ((tty->count == 1) && (info->count != 1)) {
+               /*
+                * Uh, oh.  tty->count is 1, which means that the tty
+                * structure will be freed.  Info->count should always
+                * be one in these conditions.  If it's greater than
+                * one, we've got real problems, since it means the
+                * serial port won't be shutdown.
+                */
+               printk(KERN_CRIT
+                      "rs_close: bad serial port count; tty->count is 1, "
+                      "info->count is %d\n", info->count);
+               info->count = 1;
+       }
+       if (--info->count < 0) {
+               printk(KERN_CRIT "rs_close: bad serial port count for ttyS%d: %d\n",
+                      info->line, info->count);
+               info->count = 0;
+       }
+       if (info->count) {
+               local_irq_restore(flags);
+               return;
+       }
+       info->flags |= ASYNC_CLOSING;
+       /*
+        * Save the termios structure, since this port may have
+        * separate termios for callout and dialin.
+        */
+       if (info->flags & ASYNC_NORMAL_ACTIVE)
+               info->normal_termios = *tty->termios;
+       /*
+        * 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 (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+               tty_wait_until_sent(tty, info->closing_wait);
+       /*
+        * At this point we stop accepting input.  To do this, we
+        * disable the serial receiver and the DMA receive interrupt.
+        */
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+       e100_disable_serial_data_irq(info);
+#endif
+
+#ifndef CONFIG_SVINTO_SIM
+       e100_disable_rx(info);
+       e100_disable_rx_irq(info);
+
+       if (info->flags & ASYNC_INITIALIZED) {
+               /*
+                * Before we drop DTR, make sure the UART transmitter
+                * has completely drained; this is especially
+                * important as we have a transmit FIFO!
+                */
+               rs_wait_until_sent(tty, HZ);
+       }
+#endif
+
+       shutdown(info);
+       rs_flush_buffer(tty);
+       tty_ldisc_flush(tty);
+       tty->closing = 0;
+       info->event = 0;
+       info->port.tty = NULL;
+       if (info->blocked_open) {
+               if (info->close_delay)
+                       schedule_timeout_interruptible(info->close_delay);
+               wake_up_interruptible(&info->open_wait);
+       }
+       info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
+       wake_up_interruptible(&info->close_wait);
+       local_irq_restore(flags);
+
+       /* port closed */
+
+#if defined(CONFIG_ETRAX_RS485)
+       if (info->rs485.flags & SER_RS485_ENABLED) {
+               info->rs485.flags &= ~(SER_RS485_ENABLED);
+#if defined(CONFIG_ETRAX_RS485_ON_PA)
+               *R_PORT_PA_DATA = port_pa_data_shadow &= ~(1 << rs485_pa_bit);
+#endif
+#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
+               REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
+                              rs485_port_g_bit, 0);
+#endif
+#if defined(CONFIG_ETRAX_RS485_LTC1387)
+               REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
+                              CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 0);
+               REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
+                              CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 0);
+#endif
+       }
+#endif
+
+       /*
+        * Release any allocated DMA irq's.
+        */
+       if (info->dma_in_enabled) {
+               free_irq(info->dma_in_irq_nbr, info);
+               cris_free_dma(info->dma_in_nbr, info->dma_in_irq_description);
+               info->uses_dma_in = 0;
+#ifdef SERIAL_DEBUG_OPEN
+               printk(KERN_DEBUG "DMA irq '%s' freed\n",
+                       info->dma_in_irq_description);
+#endif
+       }
+       if (info->dma_out_enabled) {
+               free_irq(info->dma_out_irq_nbr, info);
+               cris_free_dma(info->dma_out_nbr, info->dma_out_irq_description);
+               info->uses_dma_out = 0;
+#ifdef SERIAL_DEBUG_OPEN
+               printk(KERN_DEBUG "DMA irq '%s' freed\n",
+                       info->dma_out_irq_description);
+#endif
+       }
+}
+
+/*
+ * rs_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+       unsigned long orig_jiffies;
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       unsigned long curr_time = jiffies;
+       unsigned long curr_time_usec = GET_JIFFIES_USEC();
+       long elapsed_usec =
+               (curr_time - info->last_tx_active) * (1000000/HZ) +
+               curr_time_usec - info->last_tx_active_usec;
+
+       /*
+        * Check R_DMA_CHx_STATUS bit 0-6=number of available bytes in FIFO
+        * R_DMA_CHx_HWSW bit 31-16=nbr of bytes left in DMA buffer (0=64k)
+        */
+       orig_jiffies = jiffies;
+       while (info->xmit.head != info->xmit.tail || /* More in send queue */
+              (*info->ostatusadr & 0x007f) ||  /* more in FIFO */
+              (elapsed_usec < 2*info->char_time_usec)) {
+               schedule_timeout_interruptible(1);
+               if (signal_pending(current))
+                       break;
+               if (timeout && time_after(jiffies, orig_jiffies + timeout))
+                       break;
+               curr_time = jiffies;
+               curr_time_usec = GET_JIFFIES_USEC();
+               elapsed_usec =
+                       (curr_time - info->last_tx_active) * (1000000/HZ) +
+                       curr_time_usec - info->last_tx_active_usec;
+       }
+       set_current_state(TASK_RUNNING);
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+void
+rs_hangup(struct tty_struct *tty)
+{
+       struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+
+       rs_flush_buffer(tty);
+       shutdown(info);
+       info->event = 0;
+       info->count = 0;
+       info->flags &= ~ASYNC_NORMAL_ACTIVE;
+       info->port.tty = NULL;
+       wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int
+block_til_ready(struct tty_struct *tty, struct file * filp,
+               struct e100_serial *info)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       unsigned long   flags;
+       int             retval;
+       int             do_clocal = 0, extra_count = 0;
+
+       /*
+        * 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) ||
+           (info->flags & ASYNC_CLOSING)) {
+               wait_event_interruptible_tty(info->close_wait,
+                       !(info->flags & ASYNC_CLOSING));
+#ifdef SERIAL_DO_RESTART
+               if (info->flags & ASYNC_HUP_NOTIFY)
+                       return -EAGAIN;
+               else
+                       return -ERESTARTSYS;
+#else
+               return -EAGAIN;
+#endif
+       }
+
+       /*
+        * 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))) {
+               info->flags |= ASYNC_NORMAL_ACTIVE;
+               return 0;
+       }
+
+       if (tty->termios->c_cflag & CLOCAL) {
+                       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, info->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(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+       printk("block_til_ready before block: ttyS%d, count = %d\n",
+              info->line, info->count);
+#endif
+       local_irq_save(flags);
+       if (!tty_hung_up_p(filp)) {
+               extra_count++;
+               info->count--;
+       }
+       local_irq_restore(flags);
+       info->blocked_open++;
+       while (1) {
+               local_irq_save(flags);
+               /* assert RTS and DTR */
+               e100_rts(info, 1);
+               e100_dtr(info, 1);
+               local_irq_restore(flags);
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (tty_hung_up_p(filp) ||
+                   !(info->flags & ASYNC_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+                       if (info->flags & ASYNC_HUP_NOTIFY)
+                               retval = -EAGAIN;
+                       else
+                               retval = -ERESTARTSYS;
+#else
+                       retval = -EAGAIN;
+#endif
+                       break;
+               }
+               if (!(info->flags & ASYNC_CLOSING) && do_clocal)
+                       /* && (do_clocal || DCD_IS_ASSERTED) */
+                       break;
+               if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+                       break;
+               }
+#ifdef SERIAL_DEBUG_OPEN
+               printk("block_til_ready blocking: ttyS%d, count = %d\n",
+                      info->line, info->count);
+#endif
+               tty_unlock();
+               schedule();
+               tty_lock();
+       }
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&info->open_wait, &wait);
+       if (extra_count)
+               info->count++;
+       info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+       printk("block_til_ready after blocking: ttyS%d, count = %d\n",
+              info->line, info->count);
+#endif
+       if (retval)
+               return retval;
+       info->flags |= ASYNC_NORMAL_ACTIVE;
+       return 0;
+}
+
+static void
+deinit_port(struct e100_serial *info)
+{
+       if (info->dma_out_enabled) {
+               cris_free_dma(info->dma_out_nbr, info->dma_out_irq_description);
+               free_irq(info->dma_out_irq_nbr, info);
+       }
+       if (info->dma_in_enabled) {
+               cris_free_dma(info->dma_in_nbr, info->dma_in_irq_description);
+               free_irq(info->dma_in_irq_nbr, info);
+       }
+}
+
+/*
+ * This routine is called whenever a serial port is opened.
+ * It performs the serial-specific initialization for the tty structure.
+ */
+static int
+rs_open(struct tty_struct *tty, struct file * filp)
+{
+       struct e100_serial      *info;
+       int                     retval, line;
+       unsigned long           page;
+       int                     allocated_resources = 0;
+
+       /* find which port we want to open */
+       line = tty->index;
+
+       if (line < 0 || line >= NR_PORTS)
+               return -ENODEV;
+
+       /* find the corresponding e100_serial struct in the table */
+       info = rs_table + line;
+
+       /* don't allow the opening of ports that are not enabled in the HW config */
+       if (!info->enabled)
+               return -ENODEV;
+
+#ifdef SERIAL_DEBUG_OPEN
+        printk("[%d] rs_open %s, count = %d\n", current->pid, tty->name,
+              info->count);
+#endif
+
+       info->count++;
+       tty->driver_data = info;
+       info->port.tty = tty;
+
+       info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+       if (!tmp_buf) {
+               page = get_zeroed_page(GFP_KERNEL);
+               if (!page) {
+                       return -ENOMEM;
+               }
+               if (tmp_buf)
+                       free_page(page);
+               else
+                       tmp_buf = (unsigned char *) page;
+       }
+
+       /*
+        * If the port is in the middle of closing, bail out now
+        */
+       if (tty_hung_up_p(filp) ||
+           (info->flags & ASYNC_CLOSING)) {
+               wait_event_interruptible_tty(info->close_wait,
+                       !(info->flags & ASYNC_CLOSING));
+#ifdef SERIAL_DO_RESTART
+               return ((info->flags & ASYNC_HUP_NOTIFY) ?
+                       -EAGAIN : -ERESTARTSYS);
+#else
+               return -EAGAIN;
+#endif
+       }
+
+       /*
+        * If DMA is enabled try to allocate the irq's.
+        */
+       if (info->count == 1) {
+               allocated_resources = 1;
+               if (info->dma_in_enabled) {
+                       if (request_irq(info->dma_in_irq_nbr,
+                                       rec_interrupt,
+                                       info->dma_in_irq_flags,
+                                       info->dma_in_irq_description,
+                                       info)) {
+                               printk(KERN_WARNING "DMA irq '%s' busy; "
+                                       "falling back to non-DMA mode\n",
+                                       info->dma_in_irq_description);
+                               /* Make sure we never try to use DMA in */
+                               /* for the port again. */
+                               info->dma_in_enabled = 0;
+                       } else if (cris_request_dma(info->dma_in_nbr,
+                                       info->dma_in_irq_description,
+                                       DMA_VERBOSE_ON_ERROR,
+                                       info->dma_owner)) {
+                               free_irq(info->dma_in_irq_nbr, info);
+                               printk(KERN_WARNING "DMA '%s' busy; "
+                                       "falling back to non-DMA mode\n",
+                                       info->dma_in_irq_description);
+                               /* Make sure we never try to use DMA in */
+                               /* for the port again. */
+                               info->dma_in_enabled = 0;
+                       }
+#ifdef SERIAL_DEBUG_OPEN
+                       else
+                               printk(KERN_DEBUG "DMA irq '%s' allocated\n",
+                                       info->dma_in_irq_description);
+#endif
+               }
+               if (info->dma_out_enabled) {
+                       if (request_irq(info->dma_out_irq_nbr,
+                                              tr_interrupt,
+                                              info->dma_out_irq_flags,
+                                              info->dma_out_irq_description,
+                                              info)) {
+                               printk(KERN_WARNING "DMA irq '%s' busy; "
+                                       "falling back to non-DMA mode\n",
+                                       info->dma_out_irq_description);
+                               /* Make sure we never try to use DMA out */
+                               /* for the port again. */
+                               info->dma_out_enabled = 0;
+                       } else if (cris_request_dma(info->dma_out_nbr,
+                                            info->dma_out_irq_description,
+                                            DMA_VERBOSE_ON_ERROR,
+                                            info->dma_owner)) {
+                               free_irq(info->dma_out_irq_nbr, info);
+                               printk(KERN_WARNING "DMA '%s' busy; "
+                                       "falling back to non-DMA mode\n",
+                                       info->dma_out_irq_description);
+                               /* Make sure we never try to use DMA out */
+                               /* for the port again. */
+                               info->dma_out_enabled = 0;
+                       }
+#ifdef SERIAL_DEBUG_OPEN
+                       else
+                               printk(KERN_DEBUG "DMA irq '%s' allocated\n",
+                                       info->dma_out_irq_description);
+#endif
+               }
+       }
+
+       /*
+        * Start up the serial port
+        */
+
+       retval = startup(info);
+       if (retval) {
+               if (allocated_resources)
+                       deinit_port(info);
+
+               /* FIXME Decrease count info->count here too? */
+               return retval;
+       }
+
+
+       retval = block_til_ready(tty, filp, info);
+       if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+               printk("rs_open returning after block_til_ready with %d\n",
+                      retval);
+#endif
+               if (allocated_resources)
+                       deinit_port(info);
+
+               return retval;
+       }
+
+       if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
+               *tty->termios = info->normal_termios;
+               change_speed(info);
+       }
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("rs_open ttyS%d successful...\n", info->line);
+#endif
+       DLOG_INT_TRIG( log_int_pos = 0);
+
+       DFLIP(  if (info->line == SERIAL_DEBUG_LINE) {
+                       info->icount.rx = 0;
+               } );
+
+       return 0;
+}
+
+#ifdef CONFIG_PROC_FS
+/*
+ * /proc fs routines....
+ */
+
+static void seq_line_info(struct seq_file *m, struct e100_serial *info)
+{
+       unsigned long tmp;
+
+       seq_printf(m, "%d: uart:E100 port:%lX irq:%d",
+                  info->line, (unsigned long)info->ioport, info->irq);
+
+       if (!info->ioport || (info->type == PORT_UNKNOWN)) {
+               seq_printf(m, "\n");
+               return;
+       }
+
+       seq_printf(m, " baud:%d", info->baud);
+       seq_printf(m, " tx:%lu rx:%lu",
+                      (unsigned long)info->icount.tx,
+                      (unsigned long)info->icount.rx);
+       tmp = CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+       if (tmp)
+               seq_printf(m, " tx_pend:%lu/%lu",
+                          (unsigned long)tmp,
+                          (unsigned long)SERIAL_XMIT_SIZE);
+
+       seq_printf(m, " rx_pend:%lu/%lu",
+                  (unsigned long)info->recv_cnt,
+                  (unsigned long)info->max_recv_cnt);
+
+#if 1
+       if (info->port.tty) {
+               if (info->port.tty->stopped)
+                       seq_printf(m, " stopped:%i",
+                                  (int)info->port.tty->stopped);
+               if (info->port.tty->hw_stopped)
+                       seq_printf(m, " hw_stopped:%i",
+                                  (int)info->port.tty->hw_stopped);
+       }
+
+       {
+               unsigned char rstat = info->ioport[REG_STATUS];
+               if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect))
+                       seq_printf(m, " xoff_detect:1");
+       }
+
+#endif
+
+       if (info->icount.frame)
+               seq_printf(m, " fe:%lu", (unsigned long)info->icount.frame);
+
+       if (info->icount.parity)
+               seq_printf(m, " pe:%lu", (unsigned long)info->icount.parity);
+
+       if (info->icount.brk)
+               seq_printf(m, " brk:%lu", (unsigned long)info->icount.brk);
+
+       if (info->icount.overrun)
+               seq_printf(m, " oe:%lu", (unsigned long)info->icount.overrun);
+
+       /*
+        * Last thing is the RS-232 status lines
+        */
+       if (!E100_RTS_GET(info))
+               seq_puts(m, "|RTS");
+       if (!E100_CTS_GET(info))
+               seq_puts(m, "|CTS");
+       if (!E100_DTR_GET(info))
+               seq_puts(m, "|DTR");
+       if (!E100_DSR_GET(info))
+               seq_puts(m, "|DSR");
+       if (!E100_CD_GET(info))
+               seq_puts(m, "|CD");
+       if (!E100_RI_GET(info))
+               seq_puts(m, "|RI");
+       seq_puts(m, "\n");
+}
+
+
+static int crisv10_proc_show(struct seq_file *m, void *v)
+{
+       int i;
+
+       seq_printf(m, "serinfo:1.0 driver:%s\n", serial_version);
+
+       for (i = 0; i < NR_PORTS; i++) {
+               if (!rs_table[i].enabled)
+                       continue;
+               seq_line_info(m, &rs_table[i]);
+       }
+#ifdef DEBUG_LOG_INCLUDED
+       for (i = 0; i < debug_log_pos; i++) {
+               seq_printf(m, "%-4i %lu.%lu ",
+                        i, debug_log[i].time,
+                        timer_data_to_ns(debug_log[i].timer_data));
+               seq_printf(m, debug_log[i].string, debug_log[i].value);
+       }
+       seq_printf(m, "debug_log %i/%i\n", i, DEBUG_LOG_SIZE);
+       debug_log_pos = 0;
+#endif
+       return 0;
+}
+
+static int crisv10_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, crisv10_proc_show, NULL);
+}
+
+static const struct file_operations crisv10_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = crisv10_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+#endif
+
+
+/* Finally, routines used to initialize the serial driver. */
+
+static void show_serial_version(void)
+{
+       printk(KERN_INFO
+              "ETRAX 100LX serial-driver %s, "
+              "(c) 2000-2004 Axis Communications AB\r\n",
+              &serial_version[11]); /* "$Revision: x.yy" */
+}
+
+/* rs_init inits the driver at boot (using the module_init chain) */
+
+static const struct tty_operations rs_ops = {
+       .open = rs_open,
+       .close = rs_close,
+       .write = rs_write,
+       .flush_chars = rs_flush_chars,
+       .write_room = rs_write_room,
+       .chars_in_buffer = rs_chars_in_buffer,
+       .flush_buffer = rs_flush_buffer,
+       .ioctl = rs_ioctl,
+       .throttle = rs_throttle,
+        .unthrottle = rs_unthrottle,
+       .set_termios = rs_set_termios,
+       .stop = rs_stop,
+       .start = rs_start,
+       .hangup = rs_hangup,
+       .break_ctl = rs_break,
+       .send_xchar = rs_send_xchar,
+       .wait_until_sent = rs_wait_until_sent,
+       .tiocmget = rs_tiocmget,
+       .tiocmset = rs_tiocmset,
+#ifdef CONFIG_PROC_FS
+       .proc_fops = &crisv10_proc_fops,
+#endif
+};
+
+static int __init rs_init(void)
+{
+       int i;
+       struct e100_serial *info;
+       struct tty_driver *driver = alloc_tty_driver(NR_PORTS);
+
+       if (!driver)
+               return -ENOMEM;
+
+       show_serial_version();
+
+       /* Setup the timed flush handler system */
+
+#if !defined(CONFIG_ETRAX_SERIAL_FAST_TIMER)
+       setup_timer(&flush_timer, timed_flush_handler, 0);
+       mod_timer(&flush_timer, jiffies + 5);
+#endif
+
+#if defined(CONFIG_ETRAX_RS485)
+#if defined(CONFIG_ETRAX_RS485_ON_PA)
+       if (cris_io_interface_allocate_pins(if_ser0, 'a', rs485_pa_bit,
+                       rs485_pa_bit)) {
+               printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
+                       "RS485 pin\n");
+               put_tty_driver(driver);
+               return -EBUSY;
+       }
+#endif
+#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
+       if (cris_io_interface_allocate_pins(if_ser0, 'g', rs485_pa_bit,
+                       rs485_port_g_bit)) {
+               printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
+                       "RS485 pin\n");
+               put_tty_driver(driver);
+               return -EBUSY;
+       }
+#endif
+#endif
+
+       /* Initialize the tty_driver structure */
+
+       driver->driver_name = "serial";
+       driver->name = "ttyS";
+       driver->major = TTY_MAJOR;
+       driver->minor_start = 64;
+       driver->type = TTY_DRIVER_TYPE_SERIAL;
+       driver->subtype = SERIAL_TYPE_NORMAL;
+       driver->init_termios = tty_std_termios;
+       driver->init_termios.c_cflag =
+               B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */
+       driver->init_termios.c_ispeed = 115200;
+       driver->init_termios.c_ospeed = 115200;
+       driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+
+       tty_set_operations(driver, &rs_ops);
+        serial_driver = driver;
+       if (tty_register_driver(driver))
+               panic("Couldn't register serial driver\n");
+       /* do some initializing for the separate ports */
+
+       for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
+               if (info->enabled) {
+                       if (cris_request_io_interface(info->io_if,
+                                       info->io_if_description)) {
+                               printk(KERN_CRIT "ETRAX100LX async serial: "
+                                       "Could not allocate IO pins for "
+                                       "%s, port %d\n",
+                                       info->io_if_description, i);
+                               info->enabled = 0;
+                       }
+               }
+               info->uses_dma_in = 0;
+               info->uses_dma_out = 0;
+               info->line = i;
+               info->port.tty = NULL;
+               info->type = PORT_ETRAX;
+               info->tr_running = 0;
+               info->forced_eop = 0;
+               info->baud_base = DEF_BAUD_BASE;
+               info->custom_divisor = 0;
+               info->flags = 0;
+               info->close_delay = 5*HZ/10;
+               info->closing_wait = 30*HZ;
+               info->x_char = 0;
+               info->event = 0;
+               info->count = 0;
+               info->blocked_open = 0;
+               info->normal_termios = driver->init_termios;
+               init_waitqueue_head(&info->open_wait);
+               init_waitqueue_head(&info->close_wait);
+               info->xmit.buf = NULL;
+               info->xmit.tail = info->xmit.head = 0;
+               info->first_recv_buffer = info->last_recv_buffer = NULL;
+               info->recv_cnt = info->max_recv_cnt = 0;
+               info->last_tx_active_usec = 0;
+               info->last_tx_active = 0;
+
+#if defined(CONFIG_ETRAX_RS485)
+               /* Set sane defaults */
+               info->rs485.flags &= ~(SER_RS485_RTS_ON_SEND);
+               info->rs485.flags |= SER_RS485_RTS_AFTER_SEND;
+               info->rs485.flags &= ~(SER_RS485_RTS_BEFORE_SEND);
+               info->rs485.delay_rts_before_send = 0;
+               info->rs485.flags &= ~(SER_RS485_ENABLED);
+#endif
+               INIT_WORK(&info->work, do_softint);
+
+               if (info->enabled) {
+                       printk(KERN_INFO "%s%d at %p is a builtin UART with DMA\n",
+                              serial_driver->name, info->line, info->ioport);
+               }
+       }
+#ifdef CONFIG_ETRAX_FAST_TIMER
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+       memset(fast_timers, 0, sizeof(fast_timers));
+#endif
+#ifdef CONFIG_ETRAX_RS485
+       memset(fast_timers_rs485, 0, sizeof(fast_timers_rs485));
+#endif
+       fast_timer_init();
+#endif
+
+#ifndef CONFIG_SVINTO_SIM
+#ifndef CONFIG_ETRAX_KGDB
+       /* Not needed in simulator.  May only complicate stuff. */
+       /* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */
+
+       if (request_irq(SERIAL_IRQ_NBR, ser_interrupt,
+                       IRQF_SHARED | IRQF_DISABLED, "serial ", driver))
+               panic("%s: Failed to request irq8", __func__);
+
+#endif
+#endif /* CONFIG_SVINTO_SIM */
+
+       return 0;
+}
+
+/* this makes sure that rs_init is called during kernel boot */
+
+module_init(rs_init);
diff --git a/drivers/tty/serial/crisv10.h b/drivers/tty/serial/crisv10.h
new file mode 100644 (file)
index 0000000..ea0beb4
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * serial.h: Arch-dep definitions for the Etrax100 serial driver.
+ *
+ * Copyright (C) 1998-2007 Axis Communications AB
+ */
+
+#ifndef _ETRAX_SERIAL_H
+#define _ETRAX_SERIAL_H
+
+#include <linux/circ_buf.h>
+#include <asm/termios.h>
+#include <asm/dma.h>
+#include <arch/io_interface_mux.h>
+
+/* Software state per channel */
+
+#ifdef __KERNEL__
+/*
+ * This is our internal structure for each serial port's state.
+ *
+ * Many fields are paralleled by the structure used by the serial_struct
+ * structure.
+ *
+ * For definitions of the flags field, see tty.h
+ */
+
+#define SERIAL_RECV_DESCRIPTORS 8
+
+struct etrax_recv_buffer {
+       struct etrax_recv_buffer *next;
+       unsigned short length;
+       unsigned char error;
+       unsigned char pad;
+
+       unsigned char buffer[0];
+};
+
+struct e100_serial {
+       struct tty_port port;
+       int baud;
+       volatile u8     *ioport;        /* R_SERIALx_CTRL */
+       u32             irq;    /* bitnr in R_IRQ_MASK2 for dmaX_descr */
+
+       /* Output registers */
+       volatile u8 *oclrintradr;       /* adr to R_DMA_CHx_CLR_INTR */
+       volatile u32 *ofirstadr;        /* adr to R_DMA_CHx_FIRST */
+       volatile u8 *ocmdadr;           /* adr to R_DMA_CHx_CMD */
+       const volatile u8 *ostatusadr;  /* adr to R_DMA_CHx_STATUS */
+
+       /* Input registers */
+       volatile u8 *iclrintradr;       /* adr to R_DMA_CHx_CLR_INTR */
+       volatile u32 *ifirstadr;        /* adr to R_DMA_CHx_FIRST */
+       volatile u8 *icmdadr;           /* adr to R_DMA_CHx_CMD */
+       volatile u32 *idescradr;        /* adr to R_DMA_CHx_DESCR */
+
+       int flags;      /* defined in tty.h */
+
+       u8 rx_ctrl;     /* shadow for R_SERIALx_REC_CTRL */
+       u8 tx_ctrl;     /* shadow for R_SERIALx_TR_CTRL */
+       u8 iseteop;     /* bit number for R_SET_EOP for the input dma */
+       int enabled;    /* Set to 1 if the port is enabled in HW config */
+
+       u8 dma_out_enabled;     /* Set to 1 if DMA should be used */
+       u8 dma_in_enabled;      /* Set to 1 if DMA should be used */
+
+       /* end of fields defined in rs_table[] in .c-file */
+       int             dma_owner;
+       unsigned int    dma_in_nbr;
+       unsigned int    dma_out_nbr;
+       unsigned int    dma_in_irq_nbr;
+       unsigned int    dma_out_irq_nbr;
+       unsigned long   dma_in_irq_flags;
+       unsigned long   dma_out_irq_flags;
+       char            *dma_in_irq_description;
+       char            *dma_out_irq_description;
+
+       enum cris_io_interface io_if;
+       char            *io_if_description;
+
+       u8              uses_dma_in;  /* Set to 1 if DMA is used */
+       u8              uses_dma_out; /* Set to 1 if DMA is used */
+       u8              forced_eop;   /* a fifo eop has been forced */
+       int                     baud_base;     /* For special baudrates */
+       int                     custom_divisor; /* For special baudrates */
+       struct etrax_dma_descr  tr_descr;
+       struct etrax_dma_descr  rec_descr[SERIAL_RECV_DESCRIPTORS];
+       int                     cur_rec_descr;
+
+       volatile int            tr_running; /* 1 if output is running */
+
+       struct tty_struct       *tty;
+       int                     read_status_mask;
+       int                     ignore_status_mask;
+       int                     x_char; /* xon/xoff character */
+       int                     close_delay;
+       unsigned short          closing_wait;
+       unsigned short          closing_wait2;
+       unsigned long           event;
+       unsigned long           last_active;
+       int                     line;
+       int                     type;  /* PORT_ETRAX */
+       int                     count;      /* # of fd on device */
+       int                     blocked_open; /* # of blocked opens */
+       struct circ_buf         xmit;
+       struct etrax_recv_buffer *first_recv_buffer;
+       struct etrax_recv_buffer *last_recv_buffer;
+       unsigned int            recv_cnt;
+       unsigned int            max_recv_cnt;
+
+       struct work_struct      work;
+       struct async_icount     icount;   /* error-statistics etc.*/
+       struct ktermios         normal_termios;
+       struct ktermios         callout_termios;
+       wait_queue_head_t       open_wait;
+       wait_queue_head_t       close_wait;
+
+       unsigned long char_time_usec;       /* The time for 1 char, in usecs */
+       unsigned long flush_time_usec;      /* How often we should flush */
+       unsigned long last_tx_active_usec;  /* Last tx usec in the jiffies */
+       unsigned long last_tx_active;       /* Last tx time in jiffies */
+       unsigned long last_rx_active_usec;  /* Last rx usec in the jiffies */
+       unsigned long last_rx_active;       /* Last rx time in jiffies */
+
+       int break_detected_cnt;
+       int errorcode;
+
+#ifdef CONFIG_ETRAX_RS485
+       struct serial_rs485     rs485;  /* RS-485 support */
+#endif
+};
+
+/* this PORT is not in the standard serial.h. it's not actually used for
+ * anything since we only have one type of async serial-port anyway in this
+ * system.
+ */
+
+#define PORT_ETRAX 1
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at rs interrupt time.
+ */
+#define RS_EVENT_WRITE_WAKEUP  0
+
+#endif /* __KERNEL__ */
+
+#endif /* !_ETRAX_SERIAL_H */
diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c
new file mode 100644 (file)
index 0000000..57421d7
--- /dev/null
@@ -0,0 +1,955 @@
+/*
+ * dz.c: Serial port driver for DECstations equipped
+ *       with the DZ chipset.
+ *
+ * Copyright (C) 1998 Olivier A. D. Lebaillif
+ *
+ * Email: olivier.lebaillif@ifrsys.com
+ *
+ * Copyright (C) 2004, 2006, 2007  Maciej W. Rozycki
+ *
+ * [31-AUG-98] triemer
+ * Changed IRQ to use Harald's dec internals interrupts.h
+ * removed base_addr code - moving address assignment to setup.c
+ * Changed name of dz_init to rs_init to be consistent with tc code
+ * [13-NOV-98] triemer fixed code to receive characters
+ *    after patches by harald to irq code.
+ * [09-JAN-99] triemer minor fix for schedule - due to removal of timeout
+ *            field from "current" - somewhere between 2.1.121 and 2.1.131
+ Qua Jun 27 15:02:26 BRT 2001
+ * [27-JUN-2001] Arnaldo Carvalho de Melo <acme@conectiva.com.br> - cleanups
+ *
+ * Parts (C) 1999 David Airlie, airlied@linux.ie
+ * [07-SEP-99] Bugfixes
+ *
+ * [06-Jan-2002] Russell King <rmk@arm.linux.org.uk>
+ * Converted to new serial core
+ */
+
+#undef DEBUG_DZ
+
+#if defined(CONFIG_SERIAL_DZ_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/bitops.h>
+#include <linux/compiler.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/sysrq.h>
+#include <linux/tty.h>
+
+#include <asm/atomic.h>
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <asm/dec/interrupts.h>
+#include <asm/dec/kn01.h>
+#include <asm/dec/kn02.h>
+#include <asm/dec/machtype.h>
+#include <asm/dec/prom.h>
+#include <asm/dec/system.h>
+
+#include "dz.h"
+
+
+MODULE_DESCRIPTION("DECstation DZ serial driver");
+MODULE_LICENSE("GPL");
+
+
+static char dz_name[] __initdata = "DECstation DZ serial driver version ";
+static char dz_version[] __initdata = "1.04";
+
+struct dz_port {
+       struct dz_mux           *mux;
+       struct uart_port        port;
+       unsigned int            cflag;
+};
+
+struct dz_mux {
+       struct dz_port          dport[DZ_NB_PORT];
+       atomic_t                map_guard;
+       atomic_t                irq_guard;
+       int                     initialised;
+};
+
+static struct dz_mux dz_mux;
+
+static inline struct dz_port *to_dport(struct uart_port *uport)
+{
+       return container_of(uport, struct dz_port, port);
+}
+
+/*
+ * ------------------------------------------------------------
+ * dz_in () and dz_out ()
+ *
+ * These routines are used to access the registers of the DZ
+ * chip, hiding relocation differences between implementation.
+ * ------------------------------------------------------------
+ */
+
+static u16 dz_in(struct dz_port *dport, unsigned offset)
+{
+       void __iomem *addr = dport->port.membase + offset;
+
+       return readw(addr);
+}
+
+static void dz_out(struct dz_port *dport, unsigned offset, u16 value)
+{
+       void __iomem *addr = dport->port.membase + offset;
+
+       writew(value, addr);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop () and rs_start ()
+ *
+ * These routines are called before setting or resetting
+ * tty->stopped. They enable or disable transmitter interrupts,
+ * as necessary.
+ * ------------------------------------------------------------
+ */
+
+static void dz_stop_tx(struct uart_port *uport)
+{
+       struct dz_port *dport = to_dport(uport);
+       u16 tmp, mask = 1 << dport->port.line;
+
+       tmp = dz_in(dport, DZ_TCR);     /* read the TX flag */
+       tmp &= ~mask;                   /* clear the TX flag */
+       dz_out(dport, DZ_TCR, tmp);
+}
+
+static void dz_start_tx(struct uart_port *uport)
+{
+       struct dz_port *dport = to_dport(uport);
+       u16 tmp, mask = 1 << dport->port.line;
+
+       tmp = dz_in(dport, DZ_TCR);     /* read the TX flag */
+       tmp |= mask;                    /* set the TX flag */
+       dz_out(dport, DZ_TCR, tmp);
+}
+
+static void dz_stop_rx(struct uart_port *uport)
+{
+       struct dz_port *dport = to_dport(uport);
+
+       dport->cflag &= ~DZ_RXENAB;
+       dz_out(dport, DZ_LPR, dport->cflag);
+}
+
+static void dz_enable_ms(struct uart_port *uport)
+{
+       /* nothing to do */
+}
+
+/*
+ * ------------------------------------------------------------
+ *
+ * Here start the interrupt handling routines.  All of the following
+ * subroutines are declared as inline and are folded into
+ * dz_interrupt.  They were separated out for readability's sake.
+ *
+ * Note: dz_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off.  People who may want to modify
+ * dz_interrupt() should try to keep the interrupt handler as fast as
+ * possible.  After you are done making modifications, it is not a bad
+ * idea to do:
+ *
+ *     make drivers/serial/dz.s
+ *
+ * and look at the resulting assemble code in dz.s.
+ *
+ * ------------------------------------------------------------
+ */
+
+/*
+ * ------------------------------------------------------------
+ * receive_char ()
+ *
+ * This routine deals with inputs from any lines.
+ * ------------------------------------------------------------
+ */
+static inline void dz_receive_chars(struct dz_mux *mux)
+{
+       struct uart_port *uport;
+       struct dz_port *dport = &mux->dport[0];
+       struct tty_struct *tty = NULL;
+       struct uart_icount *icount;
+       int lines_rx[DZ_NB_PORT] = { [0 ... DZ_NB_PORT - 1] = 0 };
+       unsigned char ch, flag;
+       u16 status;
+       int i;
+
+       while ((status = dz_in(dport, DZ_RBUF)) & DZ_DVAL) {
+               dport = &mux->dport[LINE(status)];
+               uport = &dport->port;
+               tty = uport->state->port.tty;   /* point to the proper dev */
+
+               ch = UCHAR(status);             /* grab the char */
+               flag = TTY_NORMAL;
+
+               icount = &uport->icount;
+               icount->rx++;
+
+               if (unlikely(status & (DZ_OERR | DZ_FERR | DZ_PERR))) {
+
+                       /*
+                        * There is no separate BREAK status bit, so treat
+                        * null characters with framing errors as BREAKs;
+                        * normally, otherwise.  For this move the Framing
+                        * Error bit to a simulated BREAK bit.
+                        */
+                       if (!ch) {
+                               status |= (status & DZ_FERR) >>
+                                         (ffs(DZ_FERR) - ffs(DZ_BREAK));
+                               status &= ~DZ_FERR;
+                       }
+
+                       /* Handle SysRq/SAK & keep track of the statistics. */
+                       if (status & DZ_BREAK) {
+                               icount->brk++;
+                               if (uart_handle_break(uport))
+                                       continue;
+                       } else if (status & DZ_FERR)
+                               icount->frame++;
+                       else if (status & DZ_PERR)
+                               icount->parity++;
+                       if (status & DZ_OERR)
+                               icount->overrun++;
+
+                       status &= uport->read_status_mask;
+                       if (status & DZ_BREAK)
+                               flag = TTY_BREAK;
+                       else if (status & DZ_FERR)
+                               flag = TTY_FRAME;
+                       else if (status & DZ_PERR)
+                               flag = TTY_PARITY;
+
+               }
+
+               if (uart_handle_sysrq_char(uport, ch))
+                       continue;
+
+               uart_insert_char(uport, status, DZ_OERR, ch, flag);
+               lines_rx[LINE(status)] = 1;
+       }
+       for (i = 0; i < DZ_NB_PORT; i++)
+               if (lines_rx[i])
+                       tty_flip_buffer_push(mux->dport[i].port.state->port.tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * transmit_char ()
+ *
+ * This routine deals with outputs to any lines.
+ * ------------------------------------------------------------
+ */
+static inline void dz_transmit_chars(struct dz_mux *mux)
+{
+       struct dz_port *dport = &mux->dport[0];
+       struct circ_buf *xmit;
+       unsigned char tmp;
+       u16 status;
+
+       status = dz_in(dport, DZ_CSR);
+       dport = &mux->dport[LINE(status)];
+       xmit = &dport->port.state->xmit;
+
+       if (dport->port.x_char) {               /* XON/XOFF chars */
+               dz_out(dport, DZ_TDR, dport->port.x_char);
+               dport->port.icount.tx++;
+               dport->port.x_char = 0;
+               return;
+       }
+       /* If nothing to do or stopped or hardware stopped. */
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&dport->port)) {
+               spin_lock(&dport->port.lock);
+               dz_stop_tx(&dport->port);
+               spin_unlock(&dport->port.lock);
+               return;
+       }
+
+       /*
+        * If something to do... (remember the dz has no output fifo,
+        * so we go one char at a time) :-<
+        */
+       tmp = xmit->buf[xmit->tail];
+       xmit->tail = (xmit->tail + 1) & (DZ_XMIT_SIZE - 1);
+       dz_out(dport, DZ_TDR, tmp);
+       dport->port.icount.tx++;
+
+       if (uart_circ_chars_pending(xmit) < DZ_WAKEUP_CHARS)
+               uart_write_wakeup(&dport->port);
+
+       /* Are we are done. */
+       if (uart_circ_empty(xmit)) {
+               spin_lock(&dport->port.lock);
+               dz_stop_tx(&dport->port);
+               spin_unlock(&dport->port.lock);
+       }
+}
+
+/*
+ * ------------------------------------------------------------
+ * check_modem_status()
+ *
+ * DS 3100 & 5100: Only valid for the MODEM line, duh!
+ * DS 5000/200: Valid for the MODEM and PRINTER line.
+ * ------------------------------------------------------------
+ */
+static inline void check_modem_status(struct dz_port *dport)
+{
+       /*
+        * FIXME:
+        * 1. No status change interrupt; use a timer.
+        * 2. Handle the 3100/5000 as appropriate. --macro
+        */
+       u16 status;
+
+       /* If not the modem line just return.  */
+       if (dport->port.line != DZ_MODEM)
+               return;
+
+       status = dz_in(dport, DZ_MSR);
+
+       /* it's easy, since DSR2 is the only bit in the register */
+       if (status)
+               dport->port.icount.dsr++;
+}
+
+/*
+ * ------------------------------------------------------------
+ * dz_interrupt ()
+ *
+ * this is the main interrupt routine for the DZ chip.
+ * It deals with the multiple ports.
+ * ------------------------------------------------------------
+ */
+static irqreturn_t dz_interrupt(int irq, void *dev_id)
+{
+       struct dz_mux *mux = dev_id;
+       struct dz_port *dport = &mux->dport[0];
+       u16 status;
+
+       /* get the reason why we just got an irq */
+       status = dz_in(dport, DZ_CSR);
+
+       if ((status & (DZ_RDONE | DZ_RIE)) == (DZ_RDONE | DZ_RIE))
+               dz_receive_chars(mux);
+
+       if ((status & (DZ_TRDY | DZ_TIE)) == (DZ_TRDY | DZ_TIE))
+               dz_transmit_chars(mux);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the DZ interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+static unsigned int dz_get_mctrl(struct uart_port *uport)
+{
+       /*
+        * FIXME: Handle the 3100/5000 as appropriate. --macro
+        */
+       struct dz_port *dport = to_dport(uport);
+       unsigned int mctrl = TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+
+       if (dport->port.line == DZ_MODEM) {
+               if (dz_in(dport, DZ_MSR) & DZ_MODEM_DSR)
+                       mctrl &= ~TIOCM_DSR;
+       }
+
+       return mctrl;
+}
+
+static void dz_set_mctrl(struct uart_port *uport, unsigned int mctrl)
+{
+       /*
+        * FIXME: Handle the 3100/5000 as appropriate. --macro
+        */
+       struct dz_port *dport = to_dport(uport);
+       u16 tmp;
+
+       if (dport->port.line == DZ_MODEM) {
+               tmp = dz_in(dport, DZ_TCR);
+               if (mctrl & TIOCM_DTR)
+                       tmp &= ~DZ_MODEM_DTR;
+               else
+                       tmp |= DZ_MODEM_DTR;
+               dz_out(dport, DZ_TCR, tmp);
+       }
+}
+
+/*
+ * -------------------------------------------------------------------
+ * startup ()
+ *
+ * various initialization tasks
+ * -------------------------------------------------------------------
+ */
+static int dz_startup(struct uart_port *uport)
+{
+       struct dz_port *dport = to_dport(uport);
+       struct dz_mux *mux = dport->mux;
+       unsigned long flags;
+       int irq_guard;
+       int ret;
+       u16 tmp;
+
+       irq_guard = atomic_add_return(1, &mux->irq_guard);
+       if (irq_guard != 1)
+               return 0;
+
+       ret = request_irq(dport->port.irq, dz_interrupt,
+                         IRQF_SHARED, "dz", mux);
+       if (ret) {
+               atomic_add(-1, &mux->irq_guard);
+               printk(KERN_ERR "dz: Cannot get IRQ %d!\n", dport->port.irq);
+               return ret;
+       }
+
+       spin_lock_irqsave(&dport->port.lock, flags);
+
+       /* Enable interrupts.  */
+       tmp = dz_in(dport, DZ_CSR);
+       tmp |= DZ_RIE | DZ_TIE;
+       dz_out(dport, DZ_CSR, tmp);
+
+       spin_unlock_irqrestore(&dport->port.lock, flags);
+
+       return 0;
+}
+
+/*
+ * -------------------------------------------------------------------
+ * shutdown ()
+ *
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ * -------------------------------------------------------------------
+ */
+static void dz_shutdown(struct uart_port *uport)
+{
+       struct dz_port *dport = to_dport(uport);
+       struct dz_mux *mux = dport->mux;
+       unsigned long flags;
+       int irq_guard;
+       u16 tmp;
+
+       spin_lock_irqsave(&dport->port.lock, flags);
+       dz_stop_tx(&dport->port);
+       spin_unlock_irqrestore(&dport->port.lock, flags);
+
+       irq_guard = atomic_add_return(-1, &mux->irq_guard);
+       if (!irq_guard) {
+               /* Disable interrupts.  */
+               tmp = dz_in(dport, DZ_CSR);
+               tmp &= ~(DZ_RIE | DZ_TIE);
+               dz_out(dport, DZ_CSR, tmp);
+
+               free_irq(dport->port.irq, mux);
+       }
+}
+
+/*
+ * -------------------------------------------------------------------
+ * dz_tx_empty() -- get the transmitter empty status
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ *          is emptied.  On bus types like RS485, the transmitter must
+ *          release the bus after transmitting. This must be done when
+ *          the transmit shift register is empty, not be done when the
+ *          transmit holding register is empty.  This functionality
+ *          allows an RS485 driver to be written in user space.
+ * -------------------------------------------------------------------
+ */
+static unsigned int dz_tx_empty(struct uart_port *uport)
+{
+       struct dz_port *dport = to_dport(uport);
+       unsigned short tmp, mask = 1 << dport->port.line;
+
+       tmp = dz_in(dport, DZ_TCR);
+       tmp &= mask;
+
+       return tmp ? 0 : TIOCSER_TEMT;
+}
+
+static void dz_break_ctl(struct uart_port *uport, int break_state)
+{
+       /*
+        * FIXME: Can't access BREAK bits in TDR easily;
+        * reuse the code for polled TX. --macro
+        */
+       struct dz_port *dport = to_dport(uport);
+       unsigned long flags;
+       unsigned short tmp, mask = 1 << dport->port.line;
+
+       spin_lock_irqsave(&uport->lock, flags);
+       tmp = dz_in(dport, DZ_TCR);
+       if (break_state)
+               tmp |= mask;
+       else
+               tmp &= ~mask;
+       dz_out(dport, DZ_TCR, tmp);
+       spin_unlock_irqrestore(&uport->lock, flags);
+}
+
+static int dz_encode_baud_rate(unsigned int baud)
+{
+       switch (baud) {
+       case 50:
+               return DZ_B50;
+       case 75:
+               return DZ_B75;
+       case 110:
+               return DZ_B110;
+       case 134:
+               return DZ_B134;
+       case 150:
+               return DZ_B150;
+       case 300:
+               return DZ_B300;
+       case 600:
+               return DZ_B600;
+       case 1200:
+               return DZ_B1200;
+       case 1800:
+               return DZ_B1800;
+       case 2000:
+               return DZ_B2000;
+       case 2400:
+               return DZ_B2400;
+       case 3600:
+               return DZ_B3600;
+       case 4800:
+               return DZ_B4800;
+       case 7200:
+               return DZ_B7200;
+       case 9600:
+               return DZ_B9600;
+       default:
+               return -1;
+       }
+}
+
+
+static void dz_reset(struct dz_port *dport)
+{
+       struct dz_mux *mux = dport->mux;
+
+       if (mux->initialised)
+               return;
+
+       dz_out(dport, DZ_CSR, DZ_CLR);
+       while (dz_in(dport, DZ_CSR) & DZ_CLR);
+       iob();
+
+       /* Enable scanning.  */
+       dz_out(dport, DZ_CSR, DZ_MSE);
+
+       mux->initialised = 1;
+}
+
+static void dz_set_termios(struct uart_port *uport, struct ktermios *termios,
+                          struct ktermios *old_termios)
+{
+       struct dz_port *dport = to_dport(uport);
+       unsigned long flags;
+       unsigned int cflag, baud;
+       int bflag;
+
+       cflag = dport->port.line;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               cflag |= DZ_CS5;
+               break;
+       case CS6:
+               cflag |= DZ_CS6;
+               break;
+       case CS7:
+               cflag |= DZ_CS7;
+               break;
+       case CS8:
+       default:
+               cflag |= DZ_CS8;
+       }
+
+       if (termios->c_cflag & CSTOPB)
+               cflag |= DZ_CSTOPB;
+       if (termios->c_cflag & PARENB)
+               cflag |= DZ_PARENB;
+       if (termios->c_cflag & PARODD)
+               cflag |= DZ_PARODD;
+
+       baud = uart_get_baud_rate(uport, termios, old_termios, 50, 9600);
+       bflag = dz_encode_baud_rate(baud);
+       if (bflag < 0)  {                       /* Try to keep unchanged.  */
+               baud = uart_get_baud_rate(uport, old_termios, NULL, 50, 9600);
+               bflag = dz_encode_baud_rate(baud);
+               if (bflag < 0)  {               /* Resort to 9600.  */
+                       baud = 9600;
+                       bflag = DZ_B9600;
+               }
+               tty_termios_encode_baud_rate(termios, baud, baud);
+       }
+       cflag |= bflag;
+
+       if (termios->c_cflag & CREAD)
+               cflag |= DZ_RXENAB;
+
+       spin_lock_irqsave(&dport->port.lock, flags);
+
+       uart_update_timeout(uport, termios->c_cflag, baud);
+
+       dz_out(dport, DZ_LPR, cflag);
+       dport->cflag = cflag;
+
+       /* setup accept flag */
+       dport->port.read_status_mask = DZ_OERR;
+       if (termios->c_iflag & INPCK)
+               dport->port.read_status_mask |= DZ_FERR | DZ_PERR;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               dport->port.read_status_mask |= DZ_BREAK;
+
+       /* characters to ignore */
+       uport->ignore_status_mask = 0;
+       if ((termios->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
+               dport->port.ignore_status_mask |= DZ_OERR;
+       if (termios->c_iflag & IGNPAR)
+               dport->port.ignore_status_mask |= DZ_FERR | DZ_PERR;
+       if (termios->c_iflag & IGNBRK)
+               dport->port.ignore_status_mask |= DZ_BREAK;
+
+       spin_unlock_irqrestore(&dport->port.lock, flags);
+}
+
+/*
+ * Hack alert!
+ * Required solely so that the initial PROM-based console
+ * works undisturbed in parallel with this one.
+ */
+static void dz_pm(struct uart_port *uport, unsigned int state,
+                 unsigned int oldstate)
+{
+       struct dz_port *dport = to_dport(uport);
+       unsigned long flags;
+
+       spin_lock_irqsave(&dport->port.lock, flags);
+       if (state < 3)
+               dz_start_tx(&dport->port);
+       else
+               dz_stop_tx(&dport->port);
+       spin_unlock_irqrestore(&dport->port.lock, flags);
+}
+
+
+static const char *dz_type(struct uart_port *uport)
+{
+       return "DZ";
+}
+
+static void dz_release_port(struct uart_port *uport)
+{
+       struct dz_mux *mux = to_dport(uport)->mux;
+       int map_guard;
+
+       iounmap(uport->membase);
+       uport->membase = NULL;
+
+       map_guard = atomic_add_return(-1, &mux->map_guard);
+       if (!map_guard)
+               release_mem_region(uport->mapbase, dec_kn_slot_size);
+}
+
+static int dz_map_port(struct uart_port *uport)
+{
+       if (!uport->membase)
+               uport->membase = ioremap_nocache(uport->mapbase,
+                                                dec_kn_slot_size);
+       if (!uport->membase) {
+               printk(KERN_ERR "dz: Cannot map MMIO\n");
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static int dz_request_port(struct uart_port *uport)
+{
+       struct dz_mux *mux = to_dport(uport)->mux;
+       int map_guard;
+       int ret;
+
+       map_guard = atomic_add_return(1, &mux->map_guard);
+       if (map_guard == 1) {
+               if (!request_mem_region(uport->mapbase, dec_kn_slot_size,
+                                       "dz")) {
+                       atomic_add(-1, &mux->map_guard);
+                       printk(KERN_ERR
+                              "dz: Unable to reserve MMIO resource\n");
+                       return -EBUSY;
+               }
+       }
+       ret = dz_map_port(uport);
+       if (ret) {
+               map_guard = atomic_add_return(-1, &mux->map_guard);
+               if (!map_guard)
+                       release_mem_region(uport->mapbase, dec_kn_slot_size);
+               return ret;
+       }
+       return 0;
+}
+
+static void dz_config_port(struct uart_port *uport, int flags)
+{
+       struct dz_port *dport = to_dport(uport);
+
+       if (flags & UART_CONFIG_TYPE) {
+               if (dz_request_port(uport))
+                       return;
+
+               uport->type = PORT_DZ;
+
+               dz_reset(dport);
+       }
+}
+
+/*
+ * Verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int dz_verify_port(struct uart_port *uport, struct serial_struct *ser)
+{
+       int ret = 0;
+
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_DZ)
+               ret = -EINVAL;
+       if (ser->irq != uport->irq)
+               ret = -EINVAL;
+       return ret;
+}
+
+static struct uart_ops dz_ops = {
+       .tx_empty       = dz_tx_empty,
+       .get_mctrl      = dz_get_mctrl,
+       .set_mctrl      = dz_set_mctrl,
+       .stop_tx        = dz_stop_tx,
+       .start_tx       = dz_start_tx,
+       .stop_rx        = dz_stop_rx,
+       .enable_ms      = dz_enable_ms,
+       .break_ctl      = dz_break_ctl,
+       .startup        = dz_startup,
+       .shutdown       = dz_shutdown,
+       .set_termios    = dz_set_termios,
+       .pm             = dz_pm,
+       .type           = dz_type,
+       .release_port   = dz_release_port,
+       .request_port   = dz_request_port,
+       .config_port    = dz_config_port,
+       .verify_port    = dz_verify_port,
+};
+
+static void __init dz_init_ports(void)
+{
+       static int first = 1;
+       unsigned long base;
+       int line;
+
+       if (!first)
+               return;
+       first = 0;
+
+       if (mips_machtype == MACH_DS23100 || mips_machtype == MACH_DS5100)
+               base = dec_kn_slot_base + KN01_DZ11;
+       else
+               base = dec_kn_slot_base + KN02_DZ11;
+
+       for (line = 0; line < DZ_NB_PORT; line++) {
+               struct dz_port *dport = &dz_mux.dport[line];
+               struct uart_port *uport = &dport->port;
+
+               dport->mux      = &dz_mux;
+
+               uport->irq      = dec_interrupt[DEC_IRQ_DZ11];
+               uport->fifosize = 1;
+               uport->iotype   = UPIO_MEM;
+               uport->flags    = UPF_BOOT_AUTOCONF;
+               uport->ops      = &dz_ops;
+               uport->line     = line;
+               uport->mapbase  = base;
+       }
+}
+
+#ifdef CONFIG_SERIAL_DZ_CONSOLE
+/*
+ * -------------------------------------------------------------------
+ * dz_console_putchar() -- transmit a character
+ *
+ * Polled transmission.  This is tricky.  We need to mask transmit
+ * interrupts so that they do not interfere, enable the transmitter
+ * for the line requested and then wait till the transmit scanner
+ * requests data for this line.  But it may request data for another
+ * line first, in which case we have to disable its transmitter and
+ * repeat waiting till our line pops up.  Only then the character may
+ * be transmitted.  Finally, the state of the transmitter mask is
+ * restored.  Welcome to the world of PDP-11!
+ * -------------------------------------------------------------------
+ */
+static void dz_console_putchar(struct uart_port *uport, int ch)
+{
+       struct dz_port *dport = to_dport(uport);
+       unsigned long flags;
+       unsigned short csr, tcr, trdy, mask;
+       int loops = 10000;
+
+       spin_lock_irqsave(&dport->port.lock, flags);
+       csr = dz_in(dport, DZ_CSR);
+       dz_out(dport, DZ_CSR, csr & ~DZ_TIE);
+       tcr = dz_in(dport, DZ_TCR);
+       tcr |= 1 << dport->port.line;
+       mask = tcr;
+       dz_out(dport, DZ_TCR, mask);
+       iob();
+       spin_unlock_irqrestore(&dport->port.lock, flags);
+
+       do {
+               trdy = dz_in(dport, DZ_CSR);
+               if (!(trdy & DZ_TRDY))
+                       continue;
+               trdy = (trdy & DZ_TLINE) >> 8;
+               if (trdy == dport->port.line)
+                       break;
+               mask &= ~(1 << trdy);
+               dz_out(dport, DZ_TCR, mask);
+               iob();
+               udelay(2);
+       } while (--loops);
+
+       if (loops)                              /* Cannot send otherwise. */
+               dz_out(dport, DZ_TDR, ch);
+
+       dz_out(dport, DZ_TCR, tcr);
+       dz_out(dport, DZ_CSR, csr);
+}
+
+/*
+ * -------------------------------------------------------------------
+ * dz_console_print ()
+ *
+ * dz_console_print is registered for printk.
+ * The console must be locked when we get here.
+ * -------------------------------------------------------------------
+ */
+static void dz_console_print(struct console *co,
+                            const char *str,
+                            unsigned int count)
+{
+       struct dz_port *dport = &dz_mux.dport[co->index];
+#ifdef DEBUG_DZ
+       prom_printf((char *) str);
+#endif
+       uart_console_write(&dport->port, str, count, dz_console_putchar);
+}
+
+static int __init dz_console_setup(struct console *co, char *options)
+{
+       struct dz_port *dport = &dz_mux.dport[co->index];
+       struct uart_port *uport = &dport->port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+       int ret;
+
+       ret = dz_map_port(uport);
+       if (ret)
+               return ret;
+
+       spin_lock_init(&dport->port.lock);      /* For dz_pm().  */
+
+       dz_reset(dport);
+       dz_pm(uport, 0, -1);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(&dport->port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver dz_reg;
+static struct console dz_console = {
+       .name   = "ttyS",
+       .write  = dz_console_print,
+       .device = uart_console_device,
+       .setup  = dz_console_setup,
+       .flags  = CON_PRINTBUFFER,
+       .index  = -1,
+       .data   = &dz_reg,
+};
+
+static int __init dz_serial_console_init(void)
+{
+       if (!IOASIC) {
+               dz_init_ports();
+               register_console(&dz_console);
+               return 0;
+       } else
+               return -ENXIO;
+}
+
+console_initcall(dz_serial_console_init);
+
+#define SERIAL_DZ_CONSOLE      &dz_console
+#else
+#define SERIAL_DZ_CONSOLE      NULL
+#endif /* CONFIG_SERIAL_DZ_CONSOLE */
+
+static struct uart_driver dz_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "serial",
+       .dev_name               = "ttyS",
+       .major                  = TTY_MAJOR,
+       .minor                  = 64,
+       .nr                     = DZ_NB_PORT,
+       .cons                   = SERIAL_DZ_CONSOLE,
+};
+
+static int __init dz_init(void)
+{
+       int ret, i;
+
+       if (IOASIC)
+               return -ENXIO;
+
+       printk("%s%s\n", dz_name, dz_version);
+
+       dz_init_ports();
+
+       ret = uart_register_driver(&dz_reg);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < DZ_NB_PORT; i++)
+               uart_add_one_port(&dz_reg, &dz_mux.dport[i].port);
+
+       return 0;
+}
+
+module_init(dz_init);
diff --git a/drivers/tty/serial/dz.h b/drivers/tty/serial/dz.h
new file mode 100644 (file)
index 0000000..faf169e
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * dz.h: Serial port driver for DECstations equipped
+ *       with the DZ chipset.
+ *
+ * Copyright (C) 1998 Olivier A. D. Lebaillif 
+ *             
+ * Email: olivier.lebaillif@ifrsys.com
+ *
+ * Copyright (C) 2004, 2006  Maciej W. Rozycki
+ */
+#ifndef DZ_SERIAL_H
+#define DZ_SERIAL_H
+
+/*
+ * Definitions for the Control and Status Register.
+ */
+#define DZ_TRDY        0x8000                 /* Transmitter empty */
+#define DZ_TIE         0x4000                 /* Transmitter Interrupt Enbl */
+#define DZ_TLINE       0x0300                 /* Transmitter Line Number */
+#define DZ_RDONE       0x0080                 /* Receiver data ready */
+#define DZ_RIE         0x0040                 /* Receive Interrupt Enable */
+#define DZ_MSE         0x0020                 /* Master Scan Enable */
+#define DZ_CLR         0x0010                 /* Master reset */
+#define DZ_MAINT       0x0008                 /* Loop Back Mode */
+
+/*
+ * Definitions for the Receiver Buffer Register.
+ */
+#define DZ_RBUF_MASK   0x00FF                 /* Data Mask */
+#define DZ_LINE_MASK   0x0300                 /* Line Mask */
+#define DZ_DVAL        0x8000                 /* Valid Data indicator */
+#define DZ_OERR        0x4000                 /* Overrun error indicator */
+#define DZ_FERR        0x2000                 /* Frame error indicator */
+#define DZ_PERR        0x1000                 /* Parity error indicator */
+
+#define DZ_BREAK       0x0800                 /* BREAK event software flag */
+
+#define LINE(x) ((x & DZ_LINE_MASK) >> 8)     /* Get the line number
+                                                 from the input buffer */
+#define UCHAR(x) ((unsigned char)(x & DZ_RBUF_MASK))
+
+/*
+ * Definitions for the Transmit Control Register.
+ */
+#define DZ_LINE_KEYBOARD 0x0001
+#define DZ_LINE_MOUSE    0x0002
+#define DZ_LINE_MODEM    0x0004
+#define DZ_LINE_PRINTER  0x0008
+
+#define DZ_MODEM_RTS     0x0800               /* RTS for the modem line (2) */
+#define DZ_MODEM_DTR     0x0400               /* DTR for the modem line (2) */
+#define DZ_PRINT_RTS     0x0200               /* RTS for the prntr line (3) */
+#define DZ_PRINT_DTR     0x0100               /* DTR for the prntr line (3) */
+#define DZ_LNENB         0x000f               /* Transmitter Line Enable */
+
+/*
+ * Definitions for the Modem Status Register.
+ */
+#define DZ_MODEM_RI      0x0800               /* RI for the modem line (2) */
+#define DZ_MODEM_CD      0x0400               /* CD for the modem line (2) */
+#define DZ_MODEM_DSR     0x0200               /* DSR for the modem line (2) */
+#define DZ_MODEM_CTS     0x0100               /* CTS for the modem line (2) */
+#define DZ_PRINT_RI      0x0008               /* RI for the printer line (3) */
+#define DZ_PRINT_CD      0x0004               /* CD for the printer line (3) */
+#define DZ_PRINT_DSR     0x0002               /* DSR for the prntr line (3) */
+#define DZ_PRINT_CTS     0x0001               /* CTS for the prntr line (3) */
+
+/*
+ * Definitions for the Transmit Data Register.
+ */
+#define DZ_BRK0          0x0100               /* Break assertion for line 0 */
+#define DZ_BRK1          0x0200               /* Break assertion for line 1 */
+#define DZ_BRK2          0x0400               /* Break assertion for line 2 */
+#define DZ_BRK3          0x0800               /* Break assertion for line 3 */
+
+/*
+ * Definitions for the Line Parameter Register.
+ */
+#define DZ_KEYBOARD      0x0000               /* line 0 = keyboard */
+#define DZ_MOUSE         0x0001               /* line 1 = mouse */
+#define DZ_MODEM         0x0002               /* line 2 = modem */
+#define DZ_PRINTER       0x0003               /* line 3 = printer */
+
+#define DZ_CSIZE         0x0018               /* Number of bits per byte (mask) */
+#define DZ_CS5           0x0000               /* 5 bits per byte */
+#define DZ_CS6           0x0008               /* 6 bits per byte */
+#define DZ_CS7           0x0010               /* 7 bits per byte */
+#define DZ_CS8           0x0018               /* 8 bits per byte */
+
+#define DZ_CSTOPB        0x0020               /* 2 stop bits instead of one */ 
+
+#define DZ_PARENB        0x0040               /* Parity enable */
+#define DZ_PARODD        0x0080               /* Odd parity instead of even */
+
+#define DZ_CBAUD         0x0E00               /* Baud Rate (mask) */
+#define DZ_B50           0x0000
+#define DZ_B75           0x0100
+#define DZ_B110          0x0200
+#define DZ_B134          0x0300
+#define DZ_B150          0x0400
+#define DZ_B300          0x0500
+#define DZ_B600          0x0600
+#define DZ_B1200         0x0700 
+#define DZ_B1800         0x0800
+#define DZ_B2000         0x0900
+#define DZ_B2400         0x0A00
+#define DZ_B3600         0x0B00
+#define DZ_B4800         0x0C00
+#define DZ_B7200         0x0D00
+#define DZ_B9600         0x0E00
+
+#define DZ_RXENAB        0x1000               /* Receiver Enable */
+
+/*
+ * Addresses for the DZ registers
+ */
+#define DZ_CSR       0x00            /* Control and Status Register */
+#define DZ_RBUF      0x08            /* Receive Buffer */
+#define DZ_LPR       0x08            /* Line Parameters Register */
+#define DZ_TCR       0x10            /* Transmitter Control Register */
+#define DZ_MSR       0x18            /* Modem Status Register */
+#define DZ_TDR       0x18            /* Transmit Data Register */
+
+#define DZ_NB_PORT 4
+
+#define DZ_XMIT_SIZE   4096                 /* buffer size */
+#define DZ_WAKEUP_CHARS   DZ_XMIT_SIZE/4
+
+#endif /* DZ_SERIAL_H */
diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c
new file mode 100644 (file)
index 0000000..53a4682
--- /dev/null
@@ -0,0 +1,1658 @@
+/*
+  * icom.c
+  *
+  * Copyright (C) 2001 IBM Corporation. All rights reserved.
+  *
+  * Serial device driver.
+  *
+  * Based on code from serial.c
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 2 of the License, or
+  * (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software
+  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+  *
+  */
+#define SERIAL_DO_RESTART
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/termios.h>
+#include <linux/fs.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.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/delay.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/kref.h>
+#include <linux/firmware.h>
+#include <linux/bitops.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include "icom.h"
+
+/*#define ICOM_TRACE            enable port trace capabilities */
+
+#define ICOM_DRIVER_NAME "icom"
+#define ICOM_VERSION_STR "1.3.1"
+#define NR_PORTS              128
+#define ICOM_PORT ((struct icom_port *)port)
+#define to_icom_adapter(d) container_of(d, struct icom_adapter, kref)
+
+static const struct pci_device_id icom_pci_table[] = {
+       {
+               .vendor = PCI_VENDOR_ID_IBM,
+               .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_1,
+               .subvendor = PCI_ANY_ID,
+               .subdevice = PCI_ANY_ID,
+               .driver_data = ADAPTER_V1,
+       },
+       {
+               .vendor = PCI_VENDOR_ID_IBM,
+               .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
+               .subvendor = PCI_VENDOR_ID_IBM,
+               .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_TWO_PORTS_RVX,
+               .driver_data = ADAPTER_V2,
+       },
+       {
+               .vendor = PCI_VENDOR_ID_IBM,
+               .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
+               .subvendor = PCI_VENDOR_ID_IBM,
+               .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM,
+               .driver_data = ADAPTER_V2,
+       },
+       {
+               .vendor = PCI_VENDOR_ID_IBM,
+               .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
+               .subvendor = PCI_VENDOR_ID_IBM,
+               .subdevice = PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL,
+               .driver_data = ADAPTER_V2,
+       },
+       {
+               .vendor = PCI_VENDOR_ID_IBM,
+               .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
+               .subvendor = PCI_VENDOR_ID_IBM,
+               .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM_PCIE,
+               .driver_data = ADAPTER_V2,
+       },
+       {}
+};
+
+struct lookup_proc_table start_proc[4] = {
+       {NULL, ICOM_CONTROL_START_A},
+       {NULL, ICOM_CONTROL_START_B},
+       {NULL, ICOM_CONTROL_START_C},
+       {NULL, ICOM_CONTROL_START_D}
+};
+
+
+struct lookup_proc_table stop_proc[4] = {
+       {NULL, ICOM_CONTROL_STOP_A},
+       {NULL, ICOM_CONTROL_STOP_B},
+       {NULL, ICOM_CONTROL_STOP_C},
+       {NULL, ICOM_CONTROL_STOP_D}
+};
+
+struct lookup_int_table int_mask_tbl[4] = {
+       {NULL, ICOM_INT_MASK_PRC_A},
+       {NULL, ICOM_INT_MASK_PRC_B},
+       {NULL, ICOM_INT_MASK_PRC_C},
+       {NULL, ICOM_INT_MASK_PRC_D},
+};
+
+
+MODULE_DEVICE_TABLE(pci, icom_pci_table);
+
+static LIST_HEAD(icom_adapter_head);
+
+/* spinlock for adapter initialization and changing adapter operations */
+static spinlock_t icom_lock;
+
+#ifdef ICOM_TRACE
+static inline void trace(struct icom_port *icom_port, char *trace_pt,
+                       unsigned long trace_data)
+{
+       dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n",
+       icom_port->port, trace_pt, trace_data);
+}
+#else
+static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {};
+#endif
+static void icom_kref_release(struct kref *kref);
+
+static void free_port_memory(struct icom_port *icom_port)
+{
+       struct pci_dev *dev = icom_port->adapter->pci_dev;
+
+       trace(icom_port, "RET_PORT_MEM", 0);
+       if (icom_port->recv_buf) {
+               pci_free_consistent(dev, 4096, icom_port->recv_buf,
+                                   icom_port->recv_buf_pci);
+               icom_port->recv_buf = NULL;
+       }
+       if (icom_port->xmit_buf) {
+               pci_free_consistent(dev, 4096, icom_port->xmit_buf,
+                                   icom_port->xmit_buf_pci);
+               icom_port->xmit_buf = NULL;
+       }
+       if (icom_port->statStg) {
+               pci_free_consistent(dev, 4096, icom_port->statStg,
+                                   icom_port->statStg_pci);
+               icom_port->statStg = NULL;
+       }
+
+       if (icom_port->xmitRestart) {
+               pci_free_consistent(dev, 4096, icom_port->xmitRestart,
+                                   icom_port->xmitRestart_pci);
+               icom_port->xmitRestart = NULL;
+       }
+}
+
+static int __devinit get_port_memory(struct icom_port *icom_port)
+{
+       int index;
+       unsigned long stgAddr;
+       unsigned long startStgAddr;
+       unsigned long offset;
+       struct pci_dev *dev = icom_port->adapter->pci_dev;
+
+       icom_port->xmit_buf =
+           pci_alloc_consistent(dev, 4096, &icom_port->xmit_buf_pci);
+       if (!icom_port->xmit_buf) {
+               dev_err(&dev->dev, "Can not allocate Transmit buffer\n");
+               return -ENOMEM;
+       }
+
+       trace(icom_port, "GET_PORT_MEM",
+             (unsigned long) icom_port->xmit_buf);
+
+       icom_port->recv_buf =
+           pci_alloc_consistent(dev, 4096, &icom_port->recv_buf_pci);
+       if (!icom_port->recv_buf) {
+               dev_err(&dev->dev, "Can not allocate Receive buffer\n");
+               free_port_memory(icom_port);
+               return -ENOMEM;
+       }
+       trace(icom_port, "GET_PORT_MEM",
+             (unsigned long) icom_port->recv_buf);
+
+       icom_port->statStg =
+           pci_alloc_consistent(dev, 4096, &icom_port->statStg_pci);
+       if (!icom_port->statStg) {
+               dev_err(&dev->dev, "Can not allocate Status buffer\n");
+               free_port_memory(icom_port);
+               return -ENOMEM;
+       }
+       trace(icom_port, "GET_PORT_MEM",
+             (unsigned long) icom_port->statStg);
+
+       icom_port->xmitRestart =
+           pci_alloc_consistent(dev, 4096, &icom_port->xmitRestart_pci);
+       if (!icom_port->xmitRestart) {
+               dev_err(&dev->dev,
+                       "Can not allocate xmit Restart buffer\n");
+               free_port_memory(icom_port);
+               return -ENOMEM;
+       }
+
+       memset(icom_port->statStg, 0, 4096);
+
+       /* FODs: Frame Out Descriptor Queue, this is a FIFO queue that
+           indicates that frames are to be transmitted
+       */
+
+       stgAddr = (unsigned long) icom_port->statStg;
+       for (index = 0; index < NUM_XBUFFS; index++) {
+               trace(icom_port, "FOD_ADDR", stgAddr);
+               stgAddr = stgAddr + sizeof(icom_port->statStg->xmit[0]);
+               if (index < (NUM_XBUFFS - 1)) {
+                       memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area));
+                       icom_port->statStg->xmit[index].leLengthASD =
+                           (unsigned short int) cpu_to_le16(XMIT_BUFF_SZ);
+                       trace(icom_port, "FOD_ADDR", stgAddr);
+                       trace(icom_port, "FOD_XBUFF",
+                             (unsigned long) icom_port->xmit_buf);
+                       icom_port->statStg->xmit[index].leBuffer =
+                           cpu_to_le32(icom_port->xmit_buf_pci);
+               } else if (index == (NUM_XBUFFS - 1)) {
+                       memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area));
+                       icom_port->statStg->xmit[index].leLengthASD =
+                           (unsigned short int) cpu_to_le16(XMIT_BUFF_SZ);
+                       trace(icom_port, "FOD_XBUFF",
+                             (unsigned long) icom_port->xmit_buf);
+                       icom_port->statStg->xmit[index].leBuffer =
+                           cpu_to_le32(icom_port->xmit_buf_pci);
+               } else {
+                       memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area));
+               }
+       }
+       /* FIDs */
+       startStgAddr = stgAddr;
+
+       /* fill in every entry, even if no buffer */
+       for (index = 0; index <  NUM_RBUFFS; index++) {
+               trace(icom_port, "FID_ADDR", stgAddr);
+               stgAddr = stgAddr + sizeof(icom_port->statStg->rcv[0]);
+               icom_port->statStg->rcv[index].leLength = 0;
+               icom_port->statStg->rcv[index].WorkingLength =
+                   (unsigned short int) cpu_to_le16(RCV_BUFF_SZ);
+               if (index < (NUM_RBUFFS - 1) ) {
+                       offset = stgAddr - (unsigned long) icom_port->statStg;
+                       icom_port->statStg->rcv[index].leNext =
+                             cpu_to_le32(icom_port-> statStg_pci + offset);
+                       trace(icom_port, "FID_RBUFF",
+                             (unsigned long) icom_port->recv_buf);
+                       icom_port->statStg->rcv[index].leBuffer =
+                           cpu_to_le32(icom_port->recv_buf_pci);
+               } else if (index == (NUM_RBUFFS -1) ) {
+                       offset = startStgAddr - (unsigned long) icom_port->statStg;
+                       icom_port->statStg->rcv[index].leNext =
+                           cpu_to_le32(icom_port-> statStg_pci + offset);
+                       trace(icom_port, "FID_RBUFF",
+                             (unsigned long) icom_port->recv_buf + 2048);
+                       icom_port->statStg->rcv[index].leBuffer =
+                           cpu_to_le32(icom_port->recv_buf_pci + 2048);
+               } else {
+                       icom_port->statStg->rcv[index].leNext = 0;
+                       icom_port->statStg->rcv[index].leBuffer = 0;
+               }
+       }
+
+       return 0;
+}
+
+static void stop_processor(struct icom_port *icom_port)
+{
+       unsigned long temp;
+       unsigned long flags;
+       int port;
+
+       spin_lock_irqsave(&icom_lock, flags);
+
+       port = icom_port->port;
+       if (port == 0 || port == 1)
+               stop_proc[port].global_control_reg = &icom_port->global_reg->control;
+       else
+               stop_proc[port].global_control_reg = &icom_port->global_reg->control_2;
+
+
+       if (port < 4) {
+               temp = readl(stop_proc[port].global_control_reg);
+               temp =
+                       (temp & ~start_proc[port].processor_id) | stop_proc[port].processor_id;
+               writel(temp, stop_proc[port].global_control_reg);
+
+               /* write flush */
+               readl(stop_proc[port].global_control_reg);
+       } else {
+               dev_err(&icom_port->adapter->pci_dev->dev,
+                        "Invalid port assignment\n");
+       }
+
+       spin_unlock_irqrestore(&icom_lock, flags);
+}
+
+static void start_processor(struct icom_port *icom_port)
+{
+       unsigned long temp;
+       unsigned long flags;
+       int port;
+
+       spin_lock_irqsave(&icom_lock, flags);
+
+       port = icom_port->port;
+       if (port == 0 || port == 1)
+               start_proc[port].global_control_reg = &icom_port->global_reg->control;
+       else
+               start_proc[port].global_control_reg = &icom_port->global_reg->control_2;
+       if (port < 4) {
+               temp = readl(start_proc[port].global_control_reg);
+               temp =
+                       (temp & ~stop_proc[port].processor_id) | start_proc[port].processor_id;
+               writel(temp, start_proc[port].global_control_reg);
+
+               /* write flush */
+               readl(start_proc[port].global_control_reg);
+       } else {
+               dev_err(&icom_port->adapter->pci_dev->dev,
+                        "Invalid port assignment\n");
+       }
+
+       spin_unlock_irqrestore(&icom_lock, flags);
+}
+
+static void load_code(struct icom_port *icom_port)
+{
+       const struct firmware *fw;
+       char __iomem *iram_ptr;
+       int index;
+       int status = 0;
+       void __iomem *dram_ptr = icom_port->dram;
+       dma_addr_t temp_pci;
+       unsigned char *new_page = NULL;
+       unsigned char cable_id = NO_CABLE;
+       struct pci_dev *dev = icom_port->adapter->pci_dev;
+
+       /* Clear out any pending interrupts */
+       writew(0x3FFF, icom_port->int_reg);
+
+       trace(icom_port, "CLEAR_INTERRUPTS", 0);
+
+       /* Stop processor */
+       stop_processor(icom_port);
+
+       /* Zero out DRAM */
+       memset_io(dram_ptr, 0, 512);
+
+       /* Load Call Setup into Adapter */
+       if (request_firmware(&fw, "icom_call_setup.bin", &dev->dev) < 0) {
+               dev_err(&dev->dev,"Unable to load icom_call_setup.bin firmware image\n");
+               status = -1;
+               goto load_code_exit;
+       }
+
+       if (fw->size > ICOM_DCE_IRAM_OFFSET) {
+               dev_err(&dev->dev, "Invalid firmware image for icom_call_setup.bin found.\n");
+               release_firmware(fw);
+               status = -1;
+               goto load_code_exit;
+       }
+
+       iram_ptr = (char __iomem *)icom_port->dram + ICOM_IRAM_OFFSET;
+       for (index = 0; index < fw->size; index++)
+               writeb(fw->data[index], &iram_ptr[index]);
+
+       release_firmware(fw);
+
+       /* Load Resident DCE portion of Adapter */
+       if (request_firmware(&fw, "icom_res_dce.bin", &dev->dev) < 0) {
+               dev_err(&dev->dev,"Unable to load icom_res_dce.bin firmware image\n");
+               status = -1;
+               goto load_code_exit;
+       }
+
+       if (fw->size > ICOM_IRAM_SIZE) {
+               dev_err(&dev->dev, "Invalid firmware image for icom_res_dce.bin found.\n");
+               release_firmware(fw);
+               status = -1;
+               goto load_code_exit;
+       }
+
+       iram_ptr = (char __iomem *) icom_port->dram + ICOM_IRAM_OFFSET;
+       for (index = ICOM_DCE_IRAM_OFFSET; index < fw->size; index++)
+               writeb(fw->data[index], &iram_ptr[index]);
+
+       release_firmware(fw);
+
+       /* Set Hardware level */
+       if (icom_port->adapter->version == ADAPTER_V2)
+               writeb(V2_HARDWARE, &(icom_port->dram->misc_flags));
+
+       /* Start the processor in Adapter */
+       start_processor(icom_port);
+
+       writeb((HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL),
+              &(icom_port->dram->HDLCConfigReg));
+       writeb(0x04, &(icom_port->dram->FlagFillIdleTimer));    /* 0.5 seconds */
+       writeb(0x00, &(icom_port->dram->CmdReg));
+       writeb(0x10, &(icom_port->dram->async_config3));
+       writeb((ICOM_ACFG_DRIVE1 | ICOM_ACFG_NO_PARITY | ICOM_ACFG_8BPC |
+               ICOM_ACFG_1STOP_BIT), &(icom_port->dram->async_config2));
+
+       /*Set up data in icom DRAM to indicate where personality
+        *code is located and its length.
+        */
+       new_page = pci_alloc_consistent(dev, 4096, &temp_pci);
+
+       if (!new_page) {
+               dev_err(&dev->dev, "Can not allocate DMA buffer\n");
+               status = -1;
+               goto load_code_exit;
+       }
+
+       if (request_firmware(&fw, "icom_asc.bin", &dev->dev) < 0) {
+               dev_err(&dev->dev,"Unable to load icom_asc.bin firmware image\n");
+               status = -1;
+               goto load_code_exit;
+       }
+
+       if (fw->size > ICOM_DCE_IRAM_OFFSET) {
+               dev_err(&dev->dev, "Invalid firmware image for icom_asc.bin found.\n");
+               release_firmware(fw);
+               status = -1;
+               goto load_code_exit;
+       }
+
+       for (index = 0; index < fw->size; index++)
+               new_page[index] = fw->data[index];
+
+       release_firmware(fw);
+
+       writeb((char) ((fw->size + 16)/16), &icom_port->dram->mac_length);
+       writel(temp_pci, &icom_port->dram->mac_load_addr);
+
+       /*Setting the syncReg to 0x80 causes adapter to start downloading
+          the personality code into adapter instruction RAM.
+          Once code is loaded, it will begin executing and, based on
+          information provided above, will start DMAing data from
+          shared memory to adapter DRAM.
+        */
+       /* the wait loop below verifies this write operation has been done
+          and processed
+       */
+       writeb(START_DOWNLOAD, &icom_port->dram->sync);
+
+       /* Wait max 1 Sec for data download and processor to start */
+       for (index = 0; index < 10; index++) {
+               msleep(100);
+               if (readb(&icom_port->dram->misc_flags) & ICOM_HDW_ACTIVE)
+                       break;
+       }
+
+       if (index == 10)
+               status = -1;
+
+       /*
+        * check Cable ID
+        */
+       cable_id = readb(&icom_port->dram->cable_id);
+
+       if (cable_id & ICOM_CABLE_ID_VALID) {
+               /* Get cable ID into the lower 4 bits (standard form) */
+               cable_id = (cable_id & ICOM_CABLE_ID_MASK) >> 4;
+               icom_port->cable_id = cable_id;
+       } else {
+               dev_err(&dev->dev,"Invalid or no cable attached\n");
+               icom_port->cable_id = NO_CABLE;
+       }
+
+      load_code_exit:
+
+       if (status != 0) {
+               /* Clear out any pending interrupts */
+               writew(0x3FFF, icom_port->int_reg);
+
+               /* Turn off port */
+               writeb(ICOM_DISABLE, &(icom_port->dram->disable));
+
+               /* Stop processor */
+               stop_processor(icom_port);
+
+               dev_err(&icom_port->adapter->pci_dev->dev,"Port not opertional\n");
+       }
+
+       if (new_page != NULL)
+               pci_free_consistent(dev, 4096, new_page, temp_pci);
+}
+
+static int startup(struct icom_port *icom_port)
+{
+       unsigned long temp;
+       unsigned char cable_id, raw_cable_id;
+       unsigned long flags;
+       int port;
+
+       trace(icom_port, "STARTUP", 0);
+
+       if (!icom_port->dram) {
+               /* should NEVER be NULL */
+               dev_err(&icom_port->adapter->pci_dev->dev,
+                       "Unusable Port, port configuration missing\n");
+               return -ENODEV;
+       }
+
+       /*
+        * check Cable ID
+        */
+       raw_cable_id = readb(&icom_port->dram->cable_id);
+       trace(icom_port, "CABLE_ID", raw_cable_id);
+
+       /* Get cable ID into the lower 4 bits (standard form) */
+       cable_id = (raw_cable_id & ICOM_CABLE_ID_MASK) >> 4;
+
+       /* Check for valid Cable ID */
+       if (!(raw_cable_id & ICOM_CABLE_ID_VALID) ||
+           (cable_id != icom_port->cable_id)) {
+
+               /* reload adapter code, pick up any potential changes in cable id */
+               load_code(icom_port);
+
+               /* still no sign of cable, error out */
+               raw_cable_id = readb(&icom_port->dram->cable_id);
+               cable_id = (raw_cable_id & ICOM_CABLE_ID_MASK) >> 4;
+               if (!(raw_cable_id & ICOM_CABLE_ID_VALID) ||
+                   (icom_port->cable_id == NO_CABLE))
+                       return -EIO;
+       }
+
+       /*
+        * Finally, clear and  enable interrupts
+        */
+       spin_lock_irqsave(&icom_lock, flags);
+       port = icom_port->port;
+       if (port == 0 || port == 1)
+               int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask;
+       else
+               int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2;
+
+       if (port == 0 || port == 2)
+               writew(0x00FF, icom_port->int_reg);
+       else
+               writew(0x3F00, icom_port->int_reg);
+       if (port < 4) {
+               temp = readl(int_mask_tbl[port].global_int_mask);
+               writel(temp & ~int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask);
+
+               /* write flush */
+               readl(int_mask_tbl[port].global_int_mask);
+       } else {
+               dev_err(&icom_port->adapter->pci_dev->dev,
+                        "Invalid port assignment\n");
+       }
+
+       spin_unlock_irqrestore(&icom_lock, flags);
+       return 0;
+}
+
+static void shutdown(struct icom_port *icom_port)
+{
+       unsigned long temp;
+       unsigned char cmdReg;
+       unsigned long flags;
+       int port;
+
+       spin_lock_irqsave(&icom_lock, flags);
+       trace(icom_port, "SHUTDOWN", 0);
+
+       /*
+        * disable all interrupts
+        */
+       port = icom_port->port;
+       if (port == 0 || port == 1)
+               int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask;
+       else
+               int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2;
+
+       if (port < 4) {
+               temp = readl(int_mask_tbl[port].global_int_mask);
+               writel(temp | int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask);
+
+               /* write flush */
+               readl(int_mask_tbl[port].global_int_mask);
+       } else {
+               dev_err(&icom_port->adapter->pci_dev->dev,
+                        "Invalid port assignment\n");
+       }
+       spin_unlock_irqrestore(&icom_lock, flags);
+
+       /*
+        * disable break condition
+        */
+       cmdReg = readb(&icom_port->dram->CmdReg);
+       if (cmdReg & CMD_SND_BREAK) {
+               writeb(cmdReg & ~CMD_SND_BREAK, &icom_port->dram->CmdReg);
+       }
+}
+
+static int icom_write(struct uart_port *port)
+{
+       unsigned long data_count;
+       unsigned char cmdReg;
+       unsigned long offset;
+       int temp_tail = port->state->xmit.tail;
+
+       trace(ICOM_PORT, "WRITE", 0);
+
+       if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) &
+           SA_FLAGS_READY_TO_XMIT) {
+               trace(ICOM_PORT, "WRITE_FULL", 0);
+               return 0;
+       }
+
+       data_count = 0;
+       while ((port->state->xmit.head != temp_tail) &&
+              (data_count <= XMIT_BUFF_SZ)) {
+
+               ICOM_PORT->xmit_buf[data_count++] =
+                   port->state->xmit.buf[temp_tail];
+
+               temp_tail++;
+               temp_tail &= (UART_XMIT_SIZE - 1);
+       }
+
+       if (data_count) {
+               ICOM_PORT->statStg->xmit[0].flags =
+                   cpu_to_le16(SA_FLAGS_READY_TO_XMIT);
+               ICOM_PORT->statStg->xmit[0].leLength =
+                   cpu_to_le16(data_count);
+               offset =
+                   (unsigned long) &ICOM_PORT->statStg->xmit[0] -
+                   (unsigned long) ICOM_PORT->statStg;
+               *ICOM_PORT->xmitRestart =
+                   cpu_to_le32(ICOM_PORT->statStg_pci + offset);
+               cmdReg = readb(&ICOM_PORT->dram->CmdReg);
+               writeb(cmdReg | CMD_XMIT_RCV_ENABLE,
+                      &ICOM_PORT->dram->CmdReg);
+               writeb(START_XMIT, &ICOM_PORT->dram->StartXmitCmd);
+               trace(ICOM_PORT, "WRITE_START", data_count);
+               /* write flush */
+               readb(&ICOM_PORT->dram->StartXmitCmd);
+       }
+
+       return data_count;
+}
+
+static inline void check_modem_status(struct icom_port *icom_port)
+{
+       static char old_status = 0;
+       char delta_status;
+       unsigned char status;
+
+       spin_lock(&icom_port->uart_port.lock);
+
+       /*modem input register */
+       status = readb(&icom_port->dram->isr);
+       trace(icom_port, "CHECK_MODEM", status);
+       delta_status = status ^ old_status;
+       if (delta_status) {
+               if (delta_status & ICOM_RI)
+                       icom_port->uart_port.icount.rng++;
+               if (delta_status & ICOM_DSR)
+                       icom_port->uart_port.icount.dsr++;
+               if (delta_status & ICOM_DCD)
+                       uart_handle_dcd_change(&icom_port->uart_port,
+                                              delta_status & ICOM_DCD);
+               if (delta_status & ICOM_CTS)
+                       uart_handle_cts_change(&icom_port->uart_port,
+                                              delta_status & ICOM_CTS);
+
+               wake_up_interruptible(&icom_port->uart_port.state->
+                                     port.delta_msr_wait);
+               old_status = status;
+       }
+       spin_unlock(&icom_port->uart_port.lock);
+}
+
+static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port)
+{
+       unsigned short int count;
+       int i;
+
+       if (port_int_reg & (INT_XMIT_COMPLETED)) {
+               trace(icom_port, "XMIT_COMPLETE", 0);
+
+               /* clear buffer in use bit */
+               icom_port->statStg->xmit[0].flags &=
+                       cpu_to_le16(~SA_FLAGS_READY_TO_XMIT);
+
+               count = (unsigned short int)
+                       cpu_to_le16(icom_port->statStg->xmit[0].leLength);
+               icom_port->uart_port.icount.tx += count;
+
+               for (i=0; i<count &&
+                       !uart_circ_empty(&icom_port->uart_port.state->xmit); i++) {
+
+                       icom_port->uart_port.state->xmit.tail++;
+                       icom_port->uart_port.state->xmit.tail &=
+                               (UART_XMIT_SIZE - 1);
+               }
+
+               if (!icom_write(&icom_port->uart_port))
+                       /* activate write queue */
+                       uart_write_wakeup(&icom_port->uart_port);
+       } else
+               trace(icom_port, "XMIT_DISABLED", 0);
+}
+
+static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port)
+{
+       short int count, rcv_buff;
+       struct tty_struct *tty = icom_port->uart_port.state->port.tty;
+       unsigned short int status;
+       struct uart_icount *icount;
+       unsigned long offset;
+       unsigned char flag;
+
+       trace(icom_port, "RCV_COMPLETE", 0);
+       rcv_buff = icom_port->next_rcv;
+
+       status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags);
+       while (status & SA_FL_RCV_DONE) {
+               int first = -1;
+
+               trace(icom_port, "FID_STATUS", status);
+               count = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].leLength);
+
+               trace(icom_port, "RCV_COUNT", count);
+
+               trace(icom_port, "REAL_COUNT", count);
+
+               offset =
+                       cpu_to_le32(icom_port->statStg->rcv[rcv_buff].leBuffer) -
+                       icom_port->recv_buf_pci;
+
+               /* Block copy all but the last byte as this may have status */
+               if (count > 0) {
+                       first = icom_port->recv_buf[offset];
+                       tty_insert_flip_string(tty, icom_port->recv_buf + offset, count - 1);
+               }
+
+               icount = &icom_port->uart_port.icount;
+               icount->rx += count;
+
+               /* Break detect logic */
+               if ((status & SA_FLAGS_FRAME_ERROR)
+                   && first == 0) {
+                       status &= ~SA_FLAGS_FRAME_ERROR;
+                       status |= SA_FLAGS_BREAK_DET;
+                       trace(icom_port, "BREAK_DET", 0);
+               }
+
+               flag = TTY_NORMAL;
+
+               if (status &
+                   (SA_FLAGS_BREAK_DET | SA_FLAGS_PARITY_ERROR |
+                    SA_FLAGS_FRAME_ERROR | SA_FLAGS_OVERRUN)) {
+
+                       if (status & SA_FLAGS_BREAK_DET)
+                               icount->brk++;
+                       if (status & SA_FLAGS_PARITY_ERROR)
+                               icount->parity++;
+                       if (status & SA_FLAGS_FRAME_ERROR)
+                               icount->frame++;
+                       if (status & SA_FLAGS_OVERRUN)
+                               icount->overrun++;
+
+                       /*
+                        * Now check to see if character should be
+                        * ignored, and mask off conditions which
+                        * should be ignored.
+                        */
+                       if (status & icom_port->ignore_status_mask) {
+                               trace(icom_port, "IGNORE_CHAR", 0);
+                               goto ignore_char;
+                       }
+
+                       status &= icom_port->read_status_mask;
+
+                       if (status & SA_FLAGS_BREAK_DET) {
+                               flag = TTY_BREAK;
+                       } else if (status & SA_FLAGS_PARITY_ERROR) {
+                               trace(icom_port, "PARITY_ERROR", 0);
+                               flag = TTY_PARITY;
+                       } else if (status & SA_FLAGS_FRAME_ERROR)
+                               flag = TTY_FRAME;
+
+               }
+
+               tty_insert_flip_char(tty, *(icom_port->recv_buf + offset + count - 1), flag);
+
+               if (status & SA_FLAGS_OVERRUN)
+                       /*
+                        * Overrun is special, since it's
+                        * reported immediately, and doesn't
+                        * affect the current character
+                        */
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ignore_char:
+               icom_port->statStg->rcv[rcv_buff].flags = 0;
+               icom_port->statStg->rcv[rcv_buff].leLength = 0;
+               icom_port->statStg->rcv[rcv_buff].WorkingLength =
+                       (unsigned short int) cpu_to_le16(RCV_BUFF_SZ);
+
+               rcv_buff++;
+               if (rcv_buff == NUM_RBUFFS)
+                       rcv_buff = 0;
+
+               status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags);
+       }
+       icom_port->next_rcv = rcv_buff;
+       tty_flip_buffer_push(tty);
+}
+
+static void process_interrupt(u16 port_int_reg,
+                             struct icom_port *icom_port)
+{
+
+       spin_lock(&icom_port->uart_port.lock);
+       trace(icom_port, "INTERRUPT", port_int_reg);
+
+       if (port_int_reg & (INT_XMIT_COMPLETED | INT_XMIT_DISABLED))
+               xmit_interrupt(port_int_reg, icom_port);
+
+       if (port_int_reg & INT_RCV_COMPLETED)
+               recv_interrupt(port_int_reg, icom_port);
+
+       spin_unlock(&icom_port->uart_port.lock);
+}
+
+static irqreturn_t icom_interrupt(int irq, void *dev_id)
+{
+       void __iomem * int_reg;
+       u32 adapter_interrupts;
+       u16 port_int_reg;
+       struct icom_adapter *icom_adapter;
+       struct icom_port *icom_port;
+
+       /* find icom_port for this interrupt */
+       icom_adapter = (struct icom_adapter *) dev_id;
+
+       if (icom_adapter->version == ADAPTER_V2) {
+               int_reg = icom_adapter->base_addr + 0x8024;
+
+               adapter_interrupts = readl(int_reg);
+
+               if (adapter_interrupts & 0x00003FFF) {
+                       /* port 2 interrupt,  NOTE:  for all ADAPTER_V2, port 2 will be active */
+                       icom_port = &icom_adapter->port_info[2];
+                       port_int_reg = (u16) adapter_interrupts;
+                       process_interrupt(port_int_reg, icom_port);
+                       check_modem_status(icom_port);
+               }
+               if (adapter_interrupts & 0x3FFF0000) {
+                       /* port 3 interrupt */
+                       icom_port = &icom_adapter->port_info[3];
+                       if (icom_port->status == ICOM_PORT_ACTIVE) {
+                               port_int_reg =
+                                   (u16) (adapter_interrupts >> 16);
+                               process_interrupt(port_int_reg, icom_port);
+                               check_modem_status(icom_port);
+                       }
+               }
+
+               /* Clear out any pending interrupts */
+               writel(adapter_interrupts, int_reg);
+
+               int_reg = icom_adapter->base_addr + 0x8004;
+       } else {
+               int_reg = icom_adapter->base_addr + 0x4004;
+       }
+
+       adapter_interrupts = readl(int_reg);
+
+       if (adapter_interrupts & 0x00003FFF) {
+               /* port 0 interrupt, NOTE:  for all adapters, port 0 will be active */
+               icom_port = &icom_adapter->port_info[0];
+               port_int_reg = (u16) adapter_interrupts;
+               process_interrupt(port_int_reg, icom_port);
+               check_modem_status(icom_port);
+       }
+       if (adapter_interrupts & 0x3FFF0000) {
+               /* port 1 interrupt */
+               icom_port = &icom_adapter->port_info[1];
+               if (icom_port->status == ICOM_PORT_ACTIVE) {
+                       port_int_reg = (u16) (adapter_interrupts >> 16);
+                       process_interrupt(port_int_reg, icom_port);
+                       check_modem_status(icom_port);
+               }
+       }
+
+       /* Clear out any pending interrupts */
+       writel(adapter_interrupts, int_reg);
+
+       /* flush the write */
+       adapter_interrupts = readl(int_reg);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * ------------------------------------------------------------------
+ * Begin serial-core API
+ * ------------------------------------------------------------------
+ */
+static unsigned int icom_tx_empty(struct uart_port *port)
+{
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) &
+           SA_FLAGS_READY_TO_XMIT)
+               ret = TIOCSER_TEMT;
+       else
+               ret = 0;
+
+       spin_unlock_irqrestore(&port->lock, flags);
+       return ret;
+}
+
+static void icom_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       unsigned char local_osr;
+
+       trace(ICOM_PORT, "SET_MODEM", 0);
+       local_osr = readb(&ICOM_PORT->dram->osr);
+
+       if (mctrl & TIOCM_RTS) {
+               trace(ICOM_PORT, "RAISE_RTS", 0);
+               local_osr |= ICOM_RTS;
+       } else {
+               trace(ICOM_PORT, "LOWER_RTS", 0);
+               local_osr &= ~ICOM_RTS;
+       }
+
+       if (mctrl & TIOCM_DTR) {
+               trace(ICOM_PORT, "RAISE_DTR", 0);
+               local_osr |= ICOM_DTR;
+       } else {
+               trace(ICOM_PORT, "LOWER_DTR", 0);
+               local_osr &= ~ICOM_DTR;
+       }
+
+       writeb(local_osr, &ICOM_PORT->dram->osr);
+}
+
+static unsigned int icom_get_mctrl(struct uart_port *port)
+{
+       unsigned char status;
+       unsigned int result;
+
+       trace(ICOM_PORT, "GET_MODEM", 0);
+
+       status = readb(&ICOM_PORT->dram->isr);
+
+       result = ((status & ICOM_DCD) ? TIOCM_CAR : 0)
+           | ((status & ICOM_RI) ? TIOCM_RNG : 0)
+           | ((status & ICOM_DSR) ? TIOCM_DSR : 0)
+           | ((status & ICOM_CTS) ? TIOCM_CTS : 0);
+       return result;
+}
+
+static void icom_stop_tx(struct uart_port *port)
+{
+       unsigned char cmdReg;
+
+       trace(ICOM_PORT, "STOP", 0);
+       cmdReg = readb(&ICOM_PORT->dram->CmdReg);
+       writeb(cmdReg | CMD_HOLD_XMIT, &ICOM_PORT->dram->CmdReg);
+}
+
+static void icom_start_tx(struct uart_port *port)
+{
+       unsigned char cmdReg;
+
+       trace(ICOM_PORT, "START", 0);
+       cmdReg = readb(&ICOM_PORT->dram->CmdReg);
+       if ((cmdReg & CMD_HOLD_XMIT) == CMD_HOLD_XMIT)
+               writeb(cmdReg & ~CMD_HOLD_XMIT,
+                      &ICOM_PORT->dram->CmdReg);
+
+       icom_write(port);
+}
+
+static void icom_send_xchar(struct uart_port *port, char ch)
+{
+       unsigned char xdata;
+       int index;
+       unsigned long flags;
+
+       trace(ICOM_PORT, "SEND_XCHAR", ch);
+
+       /* wait .1 sec to send char */
+       for (index = 0; index < 10; index++) {
+               spin_lock_irqsave(&port->lock, flags);
+               xdata = readb(&ICOM_PORT->dram->xchar);
+               if (xdata == 0x00) {
+                       trace(ICOM_PORT, "QUICK_WRITE", 0);
+                       writeb(ch, &ICOM_PORT->dram->xchar);
+
+                       /* flush write operation */
+                       xdata = readb(&ICOM_PORT->dram->xchar);
+                       spin_unlock_irqrestore(&port->lock, flags);
+                       break;
+               }
+               spin_unlock_irqrestore(&port->lock, flags);
+               msleep(10);
+       }
+}
+
+static void icom_stop_rx(struct uart_port *port)
+{
+       unsigned char cmdReg;
+
+       cmdReg = readb(&ICOM_PORT->dram->CmdReg);
+       writeb(cmdReg & ~CMD_RCV_ENABLE, &ICOM_PORT->dram->CmdReg);
+}
+
+static void icom_enable_ms(struct uart_port *port)
+{
+       /* no-op */
+}
+
+static void icom_break(struct uart_port *port, int break_state)
+{
+       unsigned char cmdReg;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       trace(ICOM_PORT, "BREAK", 0);
+       cmdReg = readb(&ICOM_PORT->dram->CmdReg);
+       if (break_state == -1) {
+               writeb(cmdReg | CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg);
+       } else {
+               writeb(cmdReg & ~CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg);
+       }
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int icom_open(struct uart_port *port)
+{
+       int retval;
+
+       kref_get(&ICOM_PORT->adapter->kref);
+       retval = startup(ICOM_PORT);
+
+       if (retval) {
+               kref_put(&ICOM_PORT->adapter->kref, icom_kref_release);
+               trace(ICOM_PORT, "STARTUP_ERROR", 0);
+               return retval;
+       }
+
+       return 0;
+}
+
+static void icom_close(struct uart_port *port)
+{
+       unsigned char cmdReg;
+
+       trace(ICOM_PORT, "CLOSE", 0);
+
+       /* stop receiver */
+       cmdReg = readb(&ICOM_PORT->dram->CmdReg);
+       writeb(cmdReg & (unsigned char) ~CMD_RCV_ENABLE,
+              &ICOM_PORT->dram->CmdReg);
+
+       shutdown(ICOM_PORT);
+
+       kref_put(&ICOM_PORT->adapter->kref, icom_kref_release);
+}
+
+static void icom_set_termios(struct uart_port *port,
+                            struct ktermios *termios,
+                            struct ktermios *old_termios)
+{
+       int baud;
+       unsigned cflag, iflag;
+       char new_config2;
+       char new_config3 = 0;
+       char tmp_byte;
+       int index;
+       int rcv_buff, xmit_buff;
+       unsigned long offset;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       trace(ICOM_PORT, "CHANGE_SPEED", 0);
+
+       cflag = termios->c_cflag;
+       iflag = termios->c_iflag;
+
+       new_config2 = ICOM_ACFG_DRIVE1;
+
+       /* byte size and parity */
+       switch (cflag & CSIZE) {
+       case CS5:               /* 5 bits/char */
+               new_config2 |= ICOM_ACFG_5BPC;
+               break;
+       case CS6:               /* 6 bits/char */
+               new_config2 |= ICOM_ACFG_6BPC;
+               break;
+       case CS7:               /* 7 bits/char */
+               new_config2 |= ICOM_ACFG_7BPC;
+               break;
+       case CS8:               /* 8 bits/char */
+               new_config2 |= ICOM_ACFG_8BPC;
+               break;
+       default:
+               break;
+       }
+       if (cflag & CSTOPB) {
+               /* 2 stop bits */
+               new_config2 |= ICOM_ACFG_2STOP_BIT;
+       }
+       if (cflag & PARENB) {
+               /* parity bit enabled */
+               new_config2 |= ICOM_ACFG_PARITY_ENAB;
+               trace(ICOM_PORT, "PARENB", 0);
+       }
+       if (cflag & PARODD) {
+               /* odd parity */
+               new_config2 |= ICOM_ACFG_PARITY_ODD;
+               trace(ICOM_PORT, "PARODD", 0);
+       }
+
+       /* Determine divisor based on baud rate */
+       baud = uart_get_baud_rate(port, termios, old_termios,
+                                 icom_acfg_baud[0],
+                                 icom_acfg_baud[BAUD_TABLE_LIMIT]);
+       if (!baud)
+               baud = 9600;    /* B0 transition handled in rs_set_termios */
+
+       for (index = 0; index < BAUD_TABLE_LIMIT; index++) {
+               if (icom_acfg_baud[index] == baud) {
+                       new_config3 = index;
+                       break;
+               }
+       }
+
+       uart_update_timeout(port, cflag, baud);
+
+       /* CTS flow control flag and modem status interrupts */
+       tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg));
+       if (cflag & CRTSCTS)
+               tmp_byte |= HDLC_HDW_FLOW;
+       else
+               tmp_byte &= ~HDLC_HDW_FLOW;
+       writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg));
+
+       /*
+        * Set up parity check flag
+        */
+       ICOM_PORT->read_status_mask = SA_FLAGS_OVERRUN | SA_FL_RCV_DONE;
+       if (iflag & INPCK)
+               ICOM_PORT->read_status_mask |=
+                   SA_FLAGS_FRAME_ERROR | SA_FLAGS_PARITY_ERROR;
+
+       if ((iflag & BRKINT) || (iflag & PARMRK))
+               ICOM_PORT->read_status_mask |= SA_FLAGS_BREAK_DET;
+
+       /*
+        * Characters to ignore
+        */
+       ICOM_PORT->ignore_status_mask = 0;
+       if (iflag & IGNPAR)
+               ICOM_PORT->ignore_status_mask |=
+                   SA_FLAGS_PARITY_ERROR | SA_FLAGS_FRAME_ERROR;
+       if (iflag & IGNBRK) {
+               ICOM_PORT->ignore_status_mask |= SA_FLAGS_BREAK_DET;
+               /*
+                * If we're ignore parity and break indicators, ignore
+                * overruns too.  (For real raw support).
+                */
+               if (iflag & IGNPAR)
+                       ICOM_PORT->ignore_status_mask |= SA_FLAGS_OVERRUN;
+       }
+
+       /*
+        * !!! ignore all characters if CREAD is not set
+        */
+       if ((cflag & CREAD) == 0)
+               ICOM_PORT->ignore_status_mask |= SA_FL_RCV_DONE;
+
+       /* Turn off Receiver to prepare for reset */
+       writeb(CMD_RCV_DISABLE, &ICOM_PORT->dram->CmdReg);
+
+       for (index = 0; index < 10; index++) {
+               if (readb(&ICOM_PORT->dram->PrevCmdReg) == 0x00) {
+                       break;
+               }
+       }
+
+       /* clear all current buffers of data */
+       for (rcv_buff = 0; rcv_buff < NUM_RBUFFS; rcv_buff++) {
+               ICOM_PORT->statStg->rcv[rcv_buff].flags = 0;
+               ICOM_PORT->statStg->rcv[rcv_buff].leLength = 0;
+               ICOM_PORT->statStg->rcv[rcv_buff].WorkingLength =
+                   (unsigned short int) cpu_to_le16(RCV_BUFF_SZ);
+       }
+
+       for (xmit_buff = 0; xmit_buff < NUM_XBUFFS; xmit_buff++) {
+               ICOM_PORT->statStg->xmit[xmit_buff].flags = 0;
+       }
+
+       /* activate changes and start xmit and receiver here */
+       /* Enable the receiver */
+       writeb(new_config3, &(ICOM_PORT->dram->async_config3));
+       writeb(new_config2, &(ICOM_PORT->dram->async_config2));
+       tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg));
+       tmp_byte |= HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL;
+       writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg));
+       writeb(0x04, &(ICOM_PORT->dram->FlagFillIdleTimer));    /* 0.5 seconds */
+       writeb(0xFF, &(ICOM_PORT->dram->ier));  /* enable modem signal interrupts */
+
+       /* reset processor */
+       writeb(CMD_RESTART, &ICOM_PORT->dram->CmdReg);
+
+       for (index = 0; index < 10; index++) {
+               if (readb(&ICOM_PORT->dram->CmdReg) == 0x00) {
+                       break;
+               }
+       }
+
+       /* Enable Transmitter and Reciever */
+       offset =
+           (unsigned long) &ICOM_PORT->statStg->rcv[0] -
+           (unsigned long) ICOM_PORT->statStg;
+       writel(ICOM_PORT->statStg_pci + offset,
+              &ICOM_PORT->dram->RcvStatusAddr);
+       ICOM_PORT->next_rcv = 0;
+       ICOM_PORT->put_length = 0;
+       *ICOM_PORT->xmitRestart = 0;
+       writel(ICOM_PORT->xmitRestart_pci,
+              &ICOM_PORT->dram->XmitStatusAddr);
+       trace(ICOM_PORT, "XR_ENAB", 0);
+       writeb(CMD_XMIT_RCV_ENABLE, &ICOM_PORT->dram->CmdReg);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *icom_type(struct uart_port *port)
+{
+       return "icom";
+}
+
+static void icom_release_port(struct uart_port *port)
+{
+}
+
+static int icom_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static void icom_config_port(struct uart_port *port, int flags)
+{
+       port->type = PORT_ICOM;
+}
+
+static struct uart_ops icom_ops = {
+       .tx_empty = icom_tx_empty,
+       .set_mctrl = icom_set_mctrl,
+       .get_mctrl = icom_get_mctrl,
+       .stop_tx = icom_stop_tx,
+       .start_tx = icom_start_tx,
+       .send_xchar = icom_send_xchar,
+       .stop_rx = icom_stop_rx,
+       .enable_ms = icom_enable_ms,
+       .break_ctl = icom_break,
+       .startup = icom_open,
+       .shutdown = icom_close,
+       .set_termios = icom_set_termios,
+       .type = icom_type,
+       .release_port = icom_release_port,
+       .request_port = icom_request_port,
+       .config_port = icom_config_port,
+};
+
+#define ICOM_CONSOLE NULL
+
+static struct uart_driver icom_uart_driver = {
+       .owner = THIS_MODULE,
+       .driver_name = ICOM_DRIVER_NAME,
+       .dev_name = "ttyA",
+       .major = ICOM_MAJOR,
+       .minor = ICOM_MINOR_START,
+       .nr = NR_PORTS,
+       .cons = ICOM_CONSOLE,
+};
+
+static int __devinit icom_init_ports(struct icom_adapter *icom_adapter)
+{
+       u32 subsystem_id = icom_adapter->subsystem_id;
+       int i;
+       struct icom_port *icom_port;
+
+       if (icom_adapter->version == ADAPTER_V1) {
+               icom_adapter->numb_ports = 2;
+
+               for (i = 0; i < 2; i++) {
+                       icom_port = &icom_adapter->port_info[i];
+                       icom_port->port = i;
+                       icom_port->status = ICOM_PORT_ACTIVE;
+                       icom_port->imbed_modem = ICOM_UNKNOWN;
+               }
+       } else {
+               if (subsystem_id == PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL) {
+                       icom_adapter->numb_ports = 4;
+
+                       for (i = 0; i < 4; i++) {
+                               icom_port = &icom_adapter->port_info[i];
+
+                               icom_port->port = i;
+                               icom_port->status = ICOM_PORT_ACTIVE;
+                               icom_port->imbed_modem = ICOM_IMBED_MODEM;
+                       }
+               } else {
+                       icom_adapter->numb_ports = 4;
+
+                       icom_adapter->port_info[0].port = 0;
+                       icom_adapter->port_info[0].status = ICOM_PORT_ACTIVE;
+
+                       if (subsystem_id ==
+                           PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM) {
+                               icom_adapter->port_info[0].imbed_modem = ICOM_IMBED_MODEM;
+                       } else {
+                               icom_adapter->port_info[0].imbed_modem = ICOM_RVX;
+                       }
+
+                       icom_adapter->port_info[1].status = ICOM_PORT_OFF;
+
+                       icom_adapter->port_info[2].port = 2;
+                       icom_adapter->port_info[2].status = ICOM_PORT_ACTIVE;
+                       icom_adapter->port_info[2].imbed_modem = ICOM_RVX;
+                       icom_adapter->port_info[3].status = ICOM_PORT_OFF;
+               }
+       }
+
+       return 0;
+}
+
+static void icom_port_active(struct icom_port *icom_port, struct icom_adapter *icom_adapter, int port_num)
+{
+       if (icom_adapter->version == ADAPTER_V1) {
+               icom_port->global_reg = icom_adapter->base_addr + 0x4000;
+               icom_port->int_reg = icom_adapter->base_addr +
+                   0x4004 + 2 - 2 * port_num;
+       } else {
+               icom_port->global_reg = icom_adapter->base_addr + 0x8000;
+               if (icom_port->port < 2)
+                       icom_port->int_reg = icom_adapter->base_addr +
+                           0x8004 + 2 - 2 * icom_port->port;
+               else
+                       icom_port->int_reg = icom_adapter->base_addr +
+                           0x8024 + 2 - 2 * (icom_port->port - 2);
+       }
+}
+static int __devinit icom_load_ports(struct icom_adapter *icom_adapter)
+{
+       struct icom_port *icom_port;
+       int port_num;
+
+       for (port_num = 0; port_num < icom_adapter->numb_ports; port_num++) {
+
+               icom_port = &icom_adapter->port_info[port_num];
+
+               if (icom_port->status == ICOM_PORT_ACTIVE) {
+                       icom_port_active(icom_port, icom_adapter, port_num);
+                       icom_port->dram = icom_adapter->base_addr +
+                                       0x2000 * icom_port->port;
+
+                       icom_port->adapter = icom_adapter;
+
+                       /* get port memory */
+                       if (get_port_memory(icom_port) != 0) {
+                               dev_err(&icom_port->adapter->pci_dev->dev,
+                                       "Memory allocation for port FAILED\n");
+                       }
+               }
+       }
+       return 0;
+}
+
+static int __devinit icom_alloc_adapter(struct icom_adapter
+                                       **icom_adapter_ref)
+{
+       int adapter_count = 0;
+       struct icom_adapter *icom_adapter;
+       struct icom_adapter *cur_adapter_entry;
+       struct list_head *tmp;
+
+       icom_adapter = (struct icom_adapter *)
+           kzalloc(sizeof(struct icom_adapter), GFP_KERNEL);
+
+       if (!icom_adapter) {
+               return -ENOMEM;
+       }
+
+       list_for_each(tmp, &icom_adapter_head) {
+               cur_adapter_entry =
+                   list_entry(tmp, struct icom_adapter,
+                              icom_adapter_entry);
+               if (cur_adapter_entry->index != adapter_count) {
+                       break;
+               }
+               adapter_count++;
+       }
+
+       icom_adapter->index = adapter_count;
+       list_add_tail(&icom_adapter->icom_adapter_entry, tmp);
+
+       *icom_adapter_ref = icom_adapter;
+       return 0;
+}
+
+static void icom_free_adapter(struct icom_adapter *icom_adapter)
+{
+       list_del(&icom_adapter->icom_adapter_entry);
+       kfree(icom_adapter);
+}
+
+static void icom_remove_adapter(struct icom_adapter *icom_adapter)
+{
+       struct icom_port *icom_port;
+       int index;
+
+       for (index = 0; index < icom_adapter->numb_ports; index++) {
+               icom_port = &icom_adapter->port_info[index];
+
+               if (icom_port->status == ICOM_PORT_ACTIVE) {
+                       dev_info(&icom_adapter->pci_dev->dev,
+                                "Device removed\n");
+
+                       uart_remove_one_port(&icom_uart_driver,
+                                            &icom_port->uart_port);
+
+                       /* be sure that DTR and RTS are dropped */
+                       writeb(0x00, &icom_port->dram->osr);
+
+                       /* Wait 0.1 Sec for simple Init to complete */
+                       msleep(100);
+
+                       /* Stop proccessor */
+                       stop_processor(icom_port);
+
+                       free_port_memory(icom_port);
+               }
+       }
+
+       free_irq(icom_adapter->pci_dev->irq, (void *) icom_adapter);
+       iounmap(icom_adapter->base_addr);
+       pci_release_regions(icom_adapter->pci_dev);
+       icom_free_adapter(icom_adapter);
+}
+
+static void icom_kref_release(struct kref *kref)
+{
+       struct icom_adapter *icom_adapter;
+
+       icom_adapter = to_icom_adapter(kref);
+       icom_remove_adapter(icom_adapter);
+}
+
+static int __devinit icom_probe(struct pci_dev *dev,
+                               const struct pci_device_id *ent)
+{
+       int index;
+       unsigned int command_reg;
+       int retval;
+       struct icom_adapter *icom_adapter;
+       struct icom_port *icom_port;
+
+       retval = pci_enable_device(dev);
+       if (retval) {
+               dev_err(&dev->dev, "Device enable FAILED\n");
+               return retval;
+       }
+
+       if ( (retval = pci_request_regions(dev, "icom"))) {
+                dev_err(&dev->dev, "pci_request_regions FAILED\n");
+                pci_disable_device(dev);
+                return retval;
+        }
+
+       pci_set_master(dev);
+
+       if ( (retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg))) {
+               dev_err(&dev->dev, "PCI Config read FAILED\n");
+               return retval;
+       }
+
+       pci_write_config_dword(dev, PCI_COMMAND,
+               command_reg | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER
+               | PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+
+       if (ent->driver_data == ADAPTER_V1) {
+               pci_write_config_dword(dev, 0x44, 0x8300830A);
+       } else {
+               pci_write_config_dword(dev, 0x44, 0x42004200);
+               pci_write_config_dword(dev, 0x48, 0x42004200);
+       }
+
+
+       retval = icom_alloc_adapter(&icom_adapter);
+       if (retval) {
+                dev_err(&dev->dev, "icom_alloc_adapter FAILED\n");
+                retval = -EIO;
+                goto probe_exit0;
+       }
+
+       icom_adapter->base_addr_pci = pci_resource_start(dev, 0);
+       icom_adapter->pci_dev = dev;
+       icom_adapter->version = ent->driver_data;
+       icom_adapter->subsystem_id = ent->subdevice;
+
+
+       retval = icom_init_ports(icom_adapter);
+       if (retval) {
+               dev_err(&dev->dev, "Port configuration failed\n");
+               goto probe_exit1;
+       }
+
+       icom_adapter->base_addr = pci_ioremap_bar(dev, 0);
+
+       if (!icom_adapter->base_addr)
+               goto probe_exit1;
+
+        /* save off irq and request irq line */
+        if ( (retval = request_irq(dev->irq, icom_interrupt,
+                                  IRQF_DISABLED | IRQF_SHARED, ICOM_DRIVER_NAME,
+                                  (void *) icom_adapter))) {
+                 goto probe_exit2;
+        }
+
+       retval = icom_load_ports(icom_adapter);
+
+       for (index = 0; index < icom_adapter->numb_ports; index++) {
+               icom_port = &icom_adapter->port_info[index];
+
+               if (icom_port->status == ICOM_PORT_ACTIVE) {
+                       icom_port->uart_port.irq = icom_port->adapter->pci_dev->irq;
+                       icom_port->uart_port.type = PORT_ICOM;
+                       icom_port->uart_port.iotype = UPIO_MEM;
+                       icom_port->uart_port.membase =
+                                              (char *) icom_adapter->base_addr_pci;
+                       icom_port->uart_port.fifosize = 16;
+                       icom_port->uart_port.ops = &icom_ops;
+                       icom_port->uart_port.line =
+                       icom_port->port + icom_adapter->index * 4;
+                       if (uart_add_one_port (&icom_uart_driver, &icom_port->uart_port)) {
+                               icom_port->status = ICOM_PORT_OFF;
+                               dev_err(&dev->dev, "Device add failed\n");
+                        } else
+                               dev_info(&dev->dev, "Device added\n");
+               }
+       }
+
+       kref_init(&icom_adapter->kref);
+       return 0;
+
+probe_exit2:
+       iounmap(icom_adapter->base_addr);
+probe_exit1:
+       icom_free_adapter(icom_adapter);
+
+probe_exit0:
+       pci_release_regions(dev);
+       pci_disable_device(dev);
+
+       return retval;
+}
+
+static void __devexit icom_remove(struct pci_dev *dev)
+{
+       struct icom_adapter *icom_adapter;
+       struct list_head *tmp;
+
+       list_for_each(tmp, &icom_adapter_head) {
+               icom_adapter = list_entry(tmp, struct icom_adapter,
+                                         icom_adapter_entry);
+               if (icom_adapter->pci_dev == dev) {
+                       kref_put(&icom_adapter->kref, icom_kref_release);
+                       return;
+               }
+       }
+
+       dev_err(&dev->dev, "Unable to find device to remove\n");
+}
+
+static struct pci_driver icom_pci_driver = {
+       .name = ICOM_DRIVER_NAME,
+       .id_table = icom_pci_table,
+       .probe = icom_probe,
+       .remove = __devexit_p(icom_remove),
+};
+
+static int __init icom_init(void)
+{
+       int ret;
+
+       spin_lock_init(&icom_lock);
+
+       ret = uart_register_driver(&icom_uart_driver);
+       if (ret)
+               return ret;
+
+       ret = pci_register_driver(&icom_pci_driver);
+
+       if (ret < 0)
+               uart_unregister_driver(&icom_uart_driver);
+
+       return ret;
+}
+
+static void __exit icom_exit(void)
+{
+       pci_unregister_driver(&icom_pci_driver);
+       uart_unregister_driver(&icom_uart_driver);
+}
+
+module_init(icom_init);
+module_exit(icom_exit);
+
+MODULE_AUTHOR("Michael Anderson <mjanders@us.ibm.com>");
+MODULE_DESCRIPTION("IBM iSeries Serial IOA driver");
+MODULE_SUPPORTED_DEVICE
+    ("IBM iSeries 2745, 2771, 2772, 2742, 2793 and 2805 Communications adapters");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("icom_call_setup.bin");
+MODULE_FIRMWARE("icom_res_dce.bin");
+MODULE_FIRMWARE("icom_asc.bin");
diff --git a/drivers/tty/serial/icom.h b/drivers/tty/serial/icom.h
new file mode 100644 (file)
index 0000000..c8029e0
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * icom.h
+ *
+ * Copyright (C) 2001 Michael Anderson, IBM Corporation
+ *
+ * Serial device driver include file.
+ *
+ * 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/serial_core.h>
+
+#define BAUD_TABLE_LIMIT       ((sizeof(icom_acfg_baud)/sizeof(int)) - 1)
+static int icom_acfg_baud[] = {
+       300,
+       600,
+       900,
+       1200,
+       1800,
+       2400,
+       3600,
+       4800,
+       7200,
+       9600,
+       14400,
+       19200,
+       28800,
+       38400,
+       57600,
+       76800,
+       115200,
+       153600,
+       230400,
+       307200,
+       460800,
+};
+
+struct icom_regs {
+       u32 control;            /* Adapter Control Register     */
+       u32 interrupt;          /* Adapter Interrupt Register   */
+       u32 int_mask;           /* Adapter Interrupt Mask Reg   */
+       u32 int_pri;            /* Adapter Interrupt Priority r */
+       u32 int_reg_b;          /* Adapter non-masked Interrupt */
+       u32 resvd01;
+       u32 resvd02;
+       u32 resvd03;
+       u32 control_2;          /* Adapter Control Register 2   */
+       u32 interrupt_2;        /* Adapter Interrupt Register 2 */
+       u32 int_mask_2;         /* Adapter Interrupt Mask 2     */
+       u32 int_pri_2;          /* Adapter Interrupt Prior 2    */
+       u32 int_reg_2b;         /* Adapter non-masked 2         */
+};
+
+struct func_dram {
+       u32 reserved[108];      /* 0-1B0   reserved by personality code */
+       u32 RcvStatusAddr;      /* 1B0-1B3 Status Address for Next rcv */
+       u8 RcvStnAddr;          /* 1B4     Receive Station Addr */
+       u8 IdleState;           /* 1B5     Idle State */
+       u8 IdleMonitor;         /* 1B6     Idle Monitor */
+       u8 FlagFillIdleTimer;   /* 1B7     Flag Fill Idle Timer */
+       u32 XmitStatusAddr;     /* 1B8-1BB Transmit Status Address */
+       u8 StartXmitCmd;        /* 1BC     Start Xmit Command */
+       u8 HDLCConfigReg;       /* 1BD     Reserved */
+       u8 CauseCode;           /* 1BE     Cause code for fatal error */
+       u8 xchar;               /* 1BF     High priority send */
+       u32 reserved3;          /* 1C0-1C3 Reserved */
+       u8 PrevCmdReg;          /* 1C4     Reserved */
+       u8 CmdReg;              /* 1C5     Command Register */
+       u8 async_config2;       /* 1C6     Async Config Byte 2 */
+       u8 async_config3;       /* 1C7     Async Config Byte 3 */
+       u8 dce_resvd[20];       /* 1C8-1DB DCE Rsvd           */
+       u8 dce_resvd21;         /* 1DC     DCE Rsvd (21st byte */
+       u8 misc_flags;          /* 1DD     misc flags         */
+#define V2_HARDWARE     0x40
+#define ICOM_HDW_ACTIVE 0x01
+       u8 call_length;         /* 1DE     Phone #/CFI buff ln */
+       u8 call_length2;        /* 1DF     Upper byte (unused) */
+       u32 call_addr;          /* 1E0-1E3 Phn #/CFI buff addr */
+       u16 timer_value;        /* 1E4-1E5 general timer value */
+       u8 timer_command;       /* 1E6     general timer cmd  */
+       u8 dce_command;         /* 1E7     dce command reg    */
+       u8 dce_cmd_status;      /* 1E8     dce command stat   */
+       u8 x21_r1_ioff;         /* 1E9     dce ready counter  */
+       u8 x21_r0_ioff;         /* 1EA     dce not ready ctr  */
+       u8 x21_ralt_ioff;       /* 1EB     dce CNR counter    */
+       u8 x21_r1_ion;          /* 1EC     dce ready I on ctr */
+       u8 rsvd_ier;            /* 1ED     Rsvd for IER (if ne */
+       u8 ier;                 /* 1EE     Interrupt Enable   */
+       u8 isr;                 /* 1EF     Input Signal Reg   */
+       u8 osr;                 /* 1F0     Output Signal Reg  */
+       u8 reset;               /* 1F1     Reset/Reload Reg   */
+       u8 disable;             /* 1F2     Disable Reg        */
+       u8 sync;                /* 1F3     Sync Reg           */
+       u8 error_stat;          /* 1F4     Error Status       */
+       u8 cable_id;            /* 1F5     Cable ID           */
+       u8 cs_length;           /* 1F6     CS Load Length     */
+       u8 mac_length;          /* 1F7     Mac Load Length    */
+       u32 cs_load_addr;       /* 1F8-1FB Call Load PCI Addr */
+       u32 mac_load_addr;      /* 1FC-1FF Mac Load PCI Addr  */
+};
+
+/*
+ * adapter defines and structures
+ */
+#define ICOM_CONTROL_START_A         0x00000008
+#define ICOM_CONTROL_STOP_A          0x00000004
+#define ICOM_CONTROL_START_B         0x00000002
+#define ICOM_CONTROL_STOP_B          0x00000001
+#define ICOM_CONTROL_START_C         0x00000008
+#define ICOM_CONTROL_STOP_C          0x00000004
+#define ICOM_CONTROL_START_D         0x00000002
+#define ICOM_CONTROL_STOP_D          0x00000001
+#define ICOM_IRAM_OFFSET             0x1000
+#define ICOM_IRAM_SIZE               0x0C00
+#define ICOM_DCE_IRAM_OFFSET         0x0A00
+#define ICOM_CABLE_ID_VALID          0x01
+#define ICOM_CABLE_ID_MASK           0xF0
+#define ICOM_DISABLE                 0x80
+#define CMD_XMIT_RCV_ENABLE          0xC0
+#define CMD_XMIT_ENABLE              0x40
+#define CMD_RCV_DISABLE              0x00
+#define CMD_RCV_ENABLE               0x80
+#define CMD_RESTART                  0x01
+#define CMD_HOLD_XMIT                0x02
+#define CMD_SND_BREAK                0x04
+#define RS232_CABLE                  0x06
+#define V24_CABLE                    0x0E
+#define V35_CABLE                    0x0C
+#define V36_CABLE                    0x02
+#define NO_CABLE                     0x00
+#define START_DOWNLOAD               0x80
+#define ICOM_INT_MASK_PRC_A          0x00003FFF
+#define ICOM_INT_MASK_PRC_B          0x3FFF0000
+#define ICOM_INT_MASK_PRC_C          0x00003FFF
+#define ICOM_INT_MASK_PRC_D          0x3FFF0000
+#define INT_RCV_COMPLETED            0x1000
+#define INT_XMIT_COMPLETED           0x2000
+#define INT_IDLE_DETECT              0x0800
+#define INT_RCV_DISABLED             0x0400
+#define INT_XMIT_DISABLED            0x0200
+#define INT_RCV_XMIT_SHUTDOWN        0x0100
+#define INT_FATAL_ERROR              0x0080
+#define INT_CABLE_PULL               0x0020
+#define INT_SIGNAL_CHANGE            0x0010
+#define HDLC_PPP_PURE_ASYNC          0x02
+#define HDLC_FF_FILL                 0x00
+#define HDLC_HDW_FLOW                0x01
+#define START_XMIT                   0x80
+#define ICOM_ACFG_DRIVE1             0x20
+#define ICOM_ACFG_NO_PARITY          0x00
+#define ICOM_ACFG_PARITY_ENAB        0x02
+#define ICOM_ACFG_PARITY_ODD         0x01
+#define ICOM_ACFG_8BPC               0x00
+#define ICOM_ACFG_7BPC               0x04
+#define ICOM_ACFG_6BPC               0x08
+#define ICOM_ACFG_5BPC               0x0C
+#define ICOM_ACFG_1STOP_BIT          0x00
+#define ICOM_ACFG_2STOP_BIT          0x10
+#define ICOM_DTR                     0x80
+#define ICOM_RTS                     0x40
+#define ICOM_RI                      0x08
+#define ICOM_DSR                     0x80
+#define ICOM_DCD                     0x20
+#define ICOM_CTS                     0x40
+
+#define NUM_XBUFFS 1
+#define NUM_RBUFFS 2
+#define RCV_BUFF_SZ 0x0200
+#define XMIT_BUFF_SZ 0x1000
+struct statusArea {
+    /**********************************************/
+       /* Transmit Status Area                       */
+    /**********************************************/
+       struct xmit_status_area{
+               u32 leNext;     /* Next entry in Little Endian on Adapter */
+               u32 leNextASD;
+               u32 leBuffer;   /* Buffer for entry in LE for Adapter */
+               u16 leLengthASD;
+               u16 leOffsetASD;
+               u16 leLength;   /* Length of data in segment */
+               u16 flags;
+#define SA_FLAGS_DONE           0x0080 /* Done with Segment */
+#define SA_FLAGS_CONTINUED      0x8000 /* More Segments */
+#define SA_FLAGS_IDLE           0x4000 /* Mark IDLE after frm */
+#define SA_FLAGS_READY_TO_XMIT  0x0800
+#define SA_FLAGS_STAT_MASK      0x007F
+       } xmit[NUM_XBUFFS];
+
+    /**********************************************/
+       /* Receive Status Area                        */
+    /**********************************************/
+       struct {
+               u32 leNext;     /* Next entry in Little Endian on Adapter */
+               u32 leNextASD;
+               u32 leBuffer;   /* Buffer for entry in LE for Adapter */
+               u16 WorkingLength;      /* size of segment */
+               u16 reserv01;
+               u16 leLength;   /* Length of data in segment */
+               u16 flags;
+#define SA_FL_RCV_DONE           0x0010        /* Data ready */
+#define SA_FLAGS_OVERRUN         0x0040
+#define SA_FLAGS_PARITY_ERROR    0x0080
+#define SA_FLAGS_FRAME_ERROR     0x0001
+#define SA_FLAGS_FRAME_TRUNC     0x0002
+#define SA_FLAGS_BREAK_DET       0x0004        /* set conditionally by device driver, not hardware */
+#define SA_FLAGS_RCV_MASK        0xFFE6
+       } rcv[NUM_RBUFFS];
+};
+
+struct icom_adapter;
+
+
+#define ICOM_MAJOR       243
+#define ICOM_MINOR_START 0
+
+struct icom_port {
+       struct uart_port uart_port;
+       u8 imbed_modem;
+#define ICOM_UNKNOWN           1
+#define ICOM_RVX               2
+#define ICOM_IMBED_MODEM       3
+       unsigned char cable_id;
+       unsigned char read_status_mask;
+       unsigned char ignore_status_mask;
+       void __iomem * int_reg;
+       struct icom_regs __iomem *global_reg;
+       struct func_dram __iomem *dram;
+       int port;
+       struct statusArea *statStg;
+       dma_addr_t statStg_pci;
+       u32 *xmitRestart;
+       dma_addr_t xmitRestart_pci;
+       unsigned char *xmit_buf;
+       dma_addr_t xmit_buf_pci;
+       unsigned char *recv_buf;
+       dma_addr_t recv_buf_pci;
+       int next_rcv;
+       int put_length;
+       int status;
+#define ICOM_PORT_ACTIVE       1       /* Port exists. */
+#define ICOM_PORT_OFF          0       /* Port does not exist. */
+       int load_in_progress;
+       struct icom_adapter *adapter;
+};
+
+struct icom_adapter {
+       void __iomem * base_addr;
+       unsigned long base_addr_pci;
+       struct pci_dev *pci_dev;
+       struct icom_port port_info[4];
+       int index;
+       int version;
+#define ADAPTER_V1     0x0001
+#define ADAPTER_V2     0x0002
+       u32 subsystem_id;
+#define FOUR_PORT_MODEL                                0x0252
+#define V2_TWO_PORTS_RVX                       0x021A
+#define V2_ONE_PORT_RVX_ONE_PORT_IMBED_MDM     0x0251
+       int numb_ports;
+       struct list_head icom_adapter_entry;
+       struct kref kref;
+};
+
+/* prototype */
+extern void iCom_sercons_init(void);
+
+struct lookup_proc_table {
+       u32     __iomem *global_control_reg;
+       unsigned long   processor_id;
+};
+
+struct lookup_int_table {
+       u32     __iomem *global_int_mask;
+       unsigned long   processor_id;
+};
diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c
new file mode 100644 (file)
index 0000000..ab93763
--- /dev/null
@@ -0,0 +1,1406 @@
+/****************************************************************************
+ *
+ * Driver for the IFX 6x60 spi modem.
+ *
+ * Copyright (C) 2008 Option International
+ * Copyright (C) 2008 Filip Aben <f.aben@option.com>
+ *                   Denis Joseph Barrow <d.barow@option.com>
+ *                   Jan Dumon <j.dumon@option.com>
+ *
+ * Copyright (C) 2009, 2010 Intel Corp
+ * Russ Gorby <richardx.r.gorby@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA
+ *
+ * Driver modified by Intel from Option gtm501l_spi.c
+ *
+ * Notes
+ * o   The driver currently assumes a single device only. If you need to
+ *     change this then look for saved_ifx_dev and add a device lookup
+ * o   The driver is intended to be big-endian safe but has never been
+ *     tested that way (no suitable hardware). There are a couple of FIXME
+ *     notes by areas that may need addressing
+ * o   Some of the GPIO naming/setup assumptions may need revisiting if
+ *     you need to use this driver for another platform.
+ *
+ *****************************************************************************/
+#include <linux/module.h>
+#include <linux/termios.h>
+#include <linux/tty.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/tty.h>
+#include <linux/kfifo.h>
+#include <linux/tty_flip.h>
+#include <linux/timer.h>
+#include <linux/serial.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/rfkill.h>
+#include <linux/fs.h>
+#include <linux/ip.h>
+#include <linux/dmapool.h>
+#include <linux/gpio.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/tty.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/spi/ifx_modem.h>
+#include <linux/delay.h>
+
+#include "ifx6x60.h"
+
+#define IFX_SPI_MORE_MASK              0x10
+#define IFX_SPI_MORE_BIT               12      /* bit position in u16 */
+#define IFX_SPI_CTS_BIT                        13      /* bit position in u16 */
+#define IFX_SPI_TTY_ID                 0
+#define IFX_SPI_TIMEOUT_SEC            2
+#define IFX_SPI_HEADER_0               (-1)
+#define IFX_SPI_HEADER_F               (-2)
+
+/* forward reference */
+static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev);
+
+/* local variables */
+static int spi_b16 = 1;                        /* 8 or 16 bit word length */
+static struct tty_driver *tty_drv;
+static struct ifx_spi_device *saved_ifx_dev;
+static struct lock_class_key ifx_spi_key;
+
+/* GPIO/GPE settings */
+
+/**
+ *     mrdy_set_high           -       set MRDY GPIO
+ *     @ifx: device we are controlling
+ *
+ */
+static inline void mrdy_set_high(struct ifx_spi_device *ifx)
+{
+       gpio_set_value(ifx->gpio.mrdy, 1);
+}
+
+/**
+ *     mrdy_set_low            -       clear MRDY GPIO
+ *     @ifx: device we are controlling
+ *
+ */
+static inline void mrdy_set_low(struct ifx_spi_device *ifx)
+{
+       gpio_set_value(ifx->gpio.mrdy, 0);
+}
+
+/**
+ *     ifx_spi_power_state_set
+ *     @ifx_dev: our SPI device
+ *     @val: bits to set
+ *
+ *     Set bit in power status and signal power system if status becomes non-0
+ */
+static void
+ifx_spi_power_state_set(struct ifx_spi_device *ifx_dev, unsigned char val)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ifx_dev->power_lock, flags);
+
+       /*
+        * if power status is already non-0, just update, else
+        * tell power system
+        */
+       if (!ifx_dev->power_status)
+               pm_runtime_get(&ifx_dev->spi_dev->dev);
+       ifx_dev->power_status |= val;
+
+       spin_unlock_irqrestore(&ifx_dev->power_lock, flags);
+}
+
+/**
+ *     ifx_spi_power_state_clear       -       clear power bit
+ *     @ifx_dev: our SPI device
+ *     @val: bits to clear
+ *
+ *     clear bit in power status and signal power system if status becomes 0
+ */
+static void
+ifx_spi_power_state_clear(struct ifx_spi_device *ifx_dev, unsigned char val)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ifx_dev->power_lock, flags);
+
+       if (ifx_dev->power_status) {
+               ifx_dev->power_status &= ~val;
+               if (!ifx_dev->power_status)
+                       pm_runtime_put(&ifx_dev->spi_dev->dev);
+       }
+
+       spin_unlock_irqrestore(&ifx_dev->power_lock, flags);
+}
+
+/**
+ *     swap_buf
+ *     @buf: our buffer
+ *     @len : number of bytes (not words) in the buffer
+ *     @end: end of buffer
+ *
+ *     Swap the contents of a buffer into big endian format
+ */
+static inline void swap_buf(u16 *buf, int len, void *end)
+{
+       int n;
+
+       len = ((len + 1) >> 1);
+       if ((void *)&buf[len] > end) {
+               pr_err("swap_buf: swap exceeds boundary (%p > %p)!",
+                      &buf[len], end);
+               return;
+       }
+       for (n = 0; n < len; n++) {
+               *buf = cpu_to_be16(*buf);
+               buf++;
+       }
+}
+
+/**
+ *     mrdy_assert             -       assert MRDY line
+ *     @ifx_dev: our SPI device
+ *
+ *     Assert mrdy and set timer to wait for SRDY interrupt, if SRDY is low
+ *     now.
+ *
+ *     FIXME: Can SRDY even go high as we are running this code ?
+ */
+static void mrdy_assert(struct ifx_spi_device *ifx_dev)
+{
+       int val = gpio_get_value(ifx_dev->gpio.srdy);
+       if (!val) {
+               if (!test_and_set_bit(IFX_SPI_STATE_TIMER_PENDING,
+                                     &ifx_dev->flags)) {
+                       ifx_dev->spi_timer.expires =
+                               jiffies + IFX_SPI_TIMEOUT_SEC*HZ;
+                       add_timer(&ifx_dev->spi_timer);
+
+               }
+       }
+       ifx_spi_power_state_set(ifx_dev, IFX_SPI_POWER_DATA_PENDING);
+       mrdy_set_high(ifx_dev);
+}
+
+/**
+ *     ifx_spi_hangup          -       hang up an IFX device
+ *     @ifx_dev: our SPI device
+ *
+ *     Hang up the tty attached to the IFX device if one is currently
+ *     open. If not take no action
+ */
+static void ifx_spi_ttyhangup(struct ifx_spi_device *ifx_dev)
+{
+       struct tty_port *pport = &ifx_dev->tty_port;
+       struct tty_struct *tty = tty_port_tty_get(pport);
+       if (tty) {
+               tty_hangup(tty);
+               tty_kref_put(tty);
+       }
+}
+
+/**
+ *     ifx_spi_timeout         -       SPI timeout
+ *     @arg: our SPI device
+ *
+ *     The SPI has timed out: hang up the tty. Users will then see a hangup
+ *     and error events.
+ */
+static void ifx_spi_timeout(unsigned long arg)
+{
+       struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *)arg;
+
+       dev_warn(&ifx_dev->spi_dev->dev, "*** SPI Timeout ***");
+       ifx_spi_ttyhangup(ifx_dev);
+       mrdy_set_low(ifx_dev);
+       clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
+}
+
+/* char/tty operations */
+
+/**
+ *     ifx_spi_tiocmget        -       get modem lines
+ *     @tty: our tty device
+ *     @filp: file handle issuing the request
+ *
+ *     Map the signal state into Linux modem flags and report the value
+ *     in Linux terms
+ */
+static int ifx_spi_tiocmget(struct tty_struct *tty, struct file *filp)
+{
+       unsigned int value;
+       struct ifx_spi_device *ifx_dev = tty->driver_data;
+
+       value =
+       (test_bit(IFX_SPI_RTS, &ifx_dev->signal_state) ? TIOCM_RTS : 0) |
+       (test_bit(IFX_SPI_DTR, &ifx_dev->signal_state) ? TIOCM_DTR : 0) |
+       (test_bit(IFX_SPI_CTS, &ifx_dev->signal_state) ? TIOCM_CTS : 0) |
+       (test_bit(IFX_SPI_DSR, &ifx_dev->signal_state) ? TIOCM_DSR : 0) |
+       (test_bit(IFX_SPI_DCD, &ifx_dev->signal_state) ? TIOCM_CAR : 0) |
+       (test_bit(IFX_SPI_RI, &ifx_dev->signal_state) ? TIOCM_RNG : 0);
+       return value;
+}
+
+/**
+ *     ifx_spi_tiocmset        -       set modem bits
+ *     @tty: the tty structure
+ *     @filp: file handle issuing the request
+ *     @set: bits to set
+ *     @clear: bits to clear
+ *
+ *     The IFX6x60 only supports DTR and RTS. Set them accordingly
+ *     and flag that an update to the modem is needed.
+ *
+ *     FIXME: do we need to kick the tranfers when we do this ?
+ */
+static int ifx_spi_tiocmset(struct tty_struct *tty, struct file *filp,
+                           unsigned int set, unsigned int clear)
+{
+       struct ifx_spi_device *ifx_dev = tty->driver_data;
+
+       if (set & TIOCM_RTS)
+               set_bit(IFX_SPI_RTS, &ifx_dev->signal_state);
+       if (set & TIOCM_DTR)
+               set_bit(IFX_SPI_DTR, &ifx_dev->signal_state);
+       if (clear & TIOCM_RTS)
+               clear_bit(IFX_SPI_RTS, &ifx_dev->signal_state);
+       if (clear & TIOCM_DTR)
+               clear_bit(IFX_SPI_DTR, &ifx_dev->signal_state);
+
+       set_bit(IFX_SPI_UPDATE, &ifx_dev->signal_state);
+       return 0;
+}
+
+/**
+ *     ifx_spi_open    -       called on tty open
+ *     @tty: our tty device
+ *     @filp: file handle being associated with the tty
+ *
+ *     Open the tty interface. We let the tty_port layer do all the work
+ *     for us.
+ *
+ *     FIXME: Remove single device assumption and saved_ifx_dev
+ */
+static int ifx_spi_open(struct tty_struct *tty, struct file *filp)
+{
+       return tty_port_open(&saved_ifx_dev->tty_port, tty, filp);
+}
+
+/**
+ *     ifx_spi_close   -       called when our tty closes
+ *     @tty: the tty being closed
+ *     @filp: the file handle being closed
+ *
+ *     Perform the close of the tty. We use the tty_port layer to do all
+ *     our hard work.
+ */
+static void ifx_spi_close(struct tty_struct *tty, struct file *filp)
+{
+       struct ifx_spi_device *ifx_dev = tty->driver_data;
+       tty_port_close(&ifx_dev->tty_port, tty, filp);
+       /* FIXME: should we do an ifx_spi_reset here ? */
+}
+
+/**
+ *     ifx_decode_spi_header   -       decode received header
+ *     @buffer: the received data
+ *     @length: decoded length
+ *     @more: decoded more flag
+ *     @received_cts: status of cts we received
+ *
+ *     Note how received_cts is handled -- if header is all F it is left
+ *     the same as it was, if header is all 0 it is set to 0 otherwise it is
+ *     taken from the incoming header.
+ *
+ *     FIXME: endianness
+ */
+static int ifx_spi_decode_spi_header(unsigned char *buffer, int *length,
+                       unsigned char *more, unsigned char *received_cts)
+{
+       u16 h1;
+       u16 h2;
+       u16 *in_buffer = (u16 *)buffer;
+
+       h1 = *in_buffer;
+       h2 = *(in_buffer+1);
+
+       if (h1 == 0 && h2 == 0) {
+               *received_cts = 0;
+               return IFX_SPI_HEADER_0;
+       } else if (h1 == 0xffff && h2 == 0xffff) {
+               /* spi_slave_cts remains as it was */
+               return IFX_SPI_HEADER_F;
+       }
+
+       *length = h1 & 0xfff;   /* upper bits of byte are flags */
+       *more = (buffer[1] >> IFX_SPI_MORE_BIT) & 1;
+       *received_cts = (buffer[3] >> IFX_SPI_CTS_BIT) & 1;
+       return 0;
+}
+
+/**
+ *     ifx_setup_spi_header    -       set header fields
+ *     @txbuffer: pointer to start of SPI buffer
+ *     @tx_count: bytes
+ *     @more: indicate if more to follow
+ *
+ *     Format up an SPI header for a transfer
+ *
+ *     FIXME: endianness?
+ */
+static void ifx_spi_setup_spi_header(unsigned char *txbuffer, int tx_count,
+                                       unsigned char more)
+{
+       *(u16 *)(txbuffer) = tx_count;
+       *(u16 *)(txbuffer+2) = IFX_SPI_PAYLOAD_SIZE;
+       txbuffer[1] |= (more << IFX_SPI_MORE_BIT) & IFX_SPI_MORE_MASK;
+}
+
+/**
+ *     ifx_spi_wakeup_serial   -       SPI space made
+ *     @port_data: our SPI device
+ *
+ *     We have emptied the FIFO enough that we want to get more data
+ *     queued into it. Poke the line discipline via tty_wakeup so that
+ *     it will feed us more bits
+ */
+static void ifx_spi_wakeup_serial(struct ifx_spi_device *ifx_dev)
+{
+       struct tty_struct *tty;
+
+       tty = tty_port_tty_get(&ifx_dev->tty_port);
+       if (!tty)
+               return;
+       tty_wakeup(tty);
+       tty_kref_put(tty);
+}
+
+/**
+ *     ifx_spi_prepare_tx_buffer       -       prepare transmit frame
+ *     @ifx_dev: our SPI device
+ *
+ *     The transmit buffr needs a header and various other bits of
+ *     information followed by as much data as we can pull from the FIFO
+ *     and transfer. This function formats up a suitable buffer in the
+ *     ifx_dev->tx_buffer
+ *
+ *     FIXME: performance - should we wake the tty when the queue is half
+ *                          empty ?
+ */
+static int ifx_spi_prepare_tx_buffer(struct ifx_spi_device *ifx_dev)
+{
+       int temp_count;
+       int queue_length;
+       int tx_count;
+       unsigned char *tx_buffer;
+
+       tx_buffer = ifx_dev->tx_buffer;
+       memset(tx_buffer, 0, IFX_SPI_TRANSFER_SIZE);
+
+       /* make room for required SPI header */
+       tx_buffer += IFX_SPI_HEADER_OVERHEAD;
+       tx_count = IFX_SPI_HEADER_OVERHEAD;
+
+       /* clear to signal no more data if this turns out to be the
+        * last buffer sent in a sequence */
+       ifx_dev->spi_more = 0;
+
+       /* if modem cts is set, just send empty buffer */
+       if (!ifx_dev->spi_slave_cts) {
+               /* see if there's tx data */
+               queue_length = kfifo_len(&ifx_dev->tx_fifo);
+               if (queue_length != 0) {
+                       /* data to mux -- see if there's room for it */
+                       temp_count = min(queue_length, IFX_SPI_PAYLOAD_SIZE);
+                       temp_count = kfifo_out_locked(&ifx_dev->tx_fifo,
+                                       tx_buffer, temp_count,
+                                       &ifx_dev->fifo_lock);
+
+                       /* update buffer pointer and data count in message */
+                       tx_buffer += temp_count;
+                       tx_count += temp_count;
+                       if (temp_count == queue_length)
+                               /* poke port to get more data */
+                               ifx_spi_wakeup_serial(ifx_dev);
+                       else /* more data in port, use next SPI message */
+                               ifx_dev->spi_more = 1;
+               }
+       }
+       /* have data and info for header -- set up SPI header in buffer */
+       /* spi header needs payload size, not entire buffer size */
+       ifx_spi_setup_spi_header(ifx_dev->tx_buffer,
+                                       tx_count-IFX_SPI_HEADER_OVERHEAD,
+                                       ifx_dev->spi_more);
+       /* swap actual data in the buffer */
+       swap_buf((u16 *)(ifx_dev->tx_buffer), tx_count,
+               &ifx_dev->tx_buffer[IFX_SPI_TRANSFER_SIZE]);
+       return tx_count;
+}
+
+/**
+ *     ifx_spi_write           -       line discipline write
+ *     @tty: our tty device
+ *     @buf: pointer to buffer to write (kernel space)
+ *     @count: size of buffer
+ *
+ *     Write the characters we have been given into the FIFO. If the device
+ *     is not active then activate it, when the SRDY line is asserted back
+ *     this will commence I/O
+ */
+static int ifx_spi_write(struct tty_struct *tty, const unsigned char *buf,
+                        int count)
+{
+       struct ifx_spi_device *ifx_dev = tty->driver_data;
+       unsigned char *tmp_buf = (unsigned char *)buf;
+       int tx_count = kfifo_in_locked(&ifx_dev->tx_fifo, tmp_buf, count,
+                                  &ifx_dev->fifo_lock);
+       mrdy_assert(ifx_dev);
+       return tx_count;
+}
+
+/**
+ *     ifx_spi_chars_in_buffer -       line discipline helper
+ *     @tty: our tty device
+ *
+ *     Report how much data we can accept before we drop bytes. As we use
+ *     a simple FIFO this is nice and easy.
+ */
+static int ifx_spi_write_room(struct tty_struct *tty)
+{
+       struct ifx_spi_device *ifx_dev = tty->driver_data;
+       return IFX_SPI_FIFO_SIZE - kfifo_len(&ifx_dev->tx_fifo);
+}
+
+/**
+ *     ifx_spi_chars_in_buffer -       line discipline helper
+ *     @tty: our tty device
+ *
+ *     Report how many characters we have buffered. In our case this is the
+ *     number of bytes sitting in our transmit FIFO.
+ */
+static int ifx_spi_chars_in_buffer(struct tty_struct *tty)
+{
+       struct ifx_spi_device *ifx_dev = tty->driver_data;
+       return kfifo_len(&ifx_dev->tx_fifo);
+}
+
+/**
+ *     ifx_port_hangup
+ *     @port: our tty port
+ *
+ *     tty port hang up. Called when tty_hangup processing is invoked either
+ *     by loss of carrier, or by software (eg vhangup). Serialized against
+ *     activate/shutdown by the tty layer.
+ */
+static void ifx_spi_hangup(struct tty_struct *tty)
+{
+       struct ifx_spi_device *ifx_dev = tty->driver_data;
+       tty_port_hangup(&ifx_dev->tty_port);
+}
+
+/**
+ *     ifx_port_activate
+ *     @port: our tty port
+ *
+ *     tty port activate method - called for first open. Serialized
+ *     with hangup and shutdown by the tty layer.
+ */
+static int ifx_port_activate(struct tty_port *port, struct tty_struct *tty)
+{
+       struct ifx_spi_device *ifx_dev =
+               container_of(port, struct ifx_spi_device, tty_port);
+
+       /* clear any old data; can't do this in 'close' */
+       kfifo_reset(&ifx_dev->tx_fifo);
+
+       /* put port data into this tty */
+       tty->driver_data = ifx_dev;
+
+       /* allows flip string push from int context */
+       tty->low_latency = 1;
+
+       return 0;
+}
+
+/**
+ *     ifx_port_shutdown
+ *     @port: our tty port
+ *
+ *     tty port shutdown method - called for last port close. Serialized
+ *     with hangup and activate by the tty layer.
+ */
+static void ifx_port_shutdown(struct tty_port *port)
+{
+       struct ifx_spi_device *ifx_dev =
+               container_of(port, struct ifx_spi_device, tty_port);
+
+       mrdy_set_low(ifx_dev);
+       clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
+       tasklet_kill(&ifx_dev->io_work_tasklet);
+}
+
+static const struct tty_port_operations ifx_tty_port_ops = {
+       .activate = ifx_port_activate,
+       .shutdown = ifx_port_shutdown,
+};
+
+static const struct tty_operations ifx_spi_serial_ops = {
+       .open = ifx_spi_open,
+       .close = ifx_spi_close,
+       .write = ifx_spi_write,
+       .hangup = ifx_spi_hangup,
+       .write_room = ifx_spi_write_room,
+       .chars_in_buffer = ifx_spi_chars_in_buffer,
+       .tiocmget = ifx_spi_tiocmget,
+       .tiocmset = ifx_spi_tiocmset,
+};
+
+/**
+ *     ifx_spi_insert_fip_string       -       queue received data
+ *     @ifx_ser: our SPI device
+ *     @chars: buffer we have received
+ *     @size: number of chars reeived
+ *
+ *     Queue bytes to the tty assuming the tty side is currently open. If
+ *     not the discard the data.
+ */
+static void ifx_spi_insert_flip_string(struct ifx_spi_device *ifx_dev,
+                                   unsigned char *chars, size_t size)
+{
+       struct tty_struct *tty = tty_port_tty_get(&ifx_dev->tty_port);
+       if (!tty)
+               return;
+       tty_insert_flip_string(tty, chars, size);
+       tty_flip_buffer_push(tty);
+       tty_kref_put(tty);
+}
+
+/**
+ *     ifx_spi_complete        -       SPI transfer completed
+ *     @ctx: our SPI device
+ *
+ *     An SPI transfer has completed. Process any received data and kick off
+ *     any further transmits we can commence.
+ */
+static void ifx_spi_complete(void *ctx)
+{
+       struct ifx_spi_device *ifx_dev = ctx;
+       struct tty_struct *tty;
+       struct tty_ldisc *ldisc = NULL;
+       int length;
+       int actual_length;
+       unsigned char more;
+       unsigned char cts;
+       int local_write_pending = 0;
+       int queue_length;
+       int srdy;
+       int decode_result;
+
+       mrdy_set_low(ifx_dev);
+
+       if (!ifx_dev->spi_msg.status) {
+               /* check header validity, get comm flags */
+               swap_buf((u16 *)ifx_dev->rx_buffer, IFX_SPI_HEADER_OVERHEAD,
+                       &ifx_dev->rx_buffer[IFX_SPI_HEADER_OVERHEAD]);
+               decode_result = ifx_spi_decode_spi_header(ifx_dev->rx_buffer,
+                               &length, &more, &cts);
+               if (decode_result == IFX_SPI_HEADER_0) {
+                       dev_dbg(&ifx_dev->spi_dev->dev,
+                               "ignore input: invalid header 0");
+                       ifx_dev->spi_slave_cts = 0;
+                       goto complete_exit;
+               } else if (decode_result == IFX_SPI_HEADER_F) {
+                       dev_dbg(&ifx_dev->spi_dev->dev,
+                               "ignore input: invalid header F");
+                       goto complete_exit;
+               }
+
+               ifx_dev->spi_slave_cts = cts;
+
+               actual_length = min((unsigned int)length,
+                                       ifx_dev->spi_msg.actual_length);
+               swap_buf((u16 *)(ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD),
+                        actual_length,
+                        &ifx_dev->rx_buffer[IFX_SPI_TRANSFER_SIZE]);
+               ifx_spi_insert_flip_string(
+                       ifx_dev,
+                       ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD,
+                       (size_t)actual_length);
+       } else {
+               dev_dbg(&ifx_dev->spi_dev->dev, "SPI transfer error %d",
+                      ifx_dev->spi_msg.status);
+       }
+
+complete_exit:
+       if (ifx_dev->write_pending) {
+               ifx_dev->write_pending = 0;
+               local_write_pending = 1;
+       }
+
+       clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &(ifx_dev->flags));
+
+       queue_length = kfifo_len(&ifx_dev->tx_fifo);
+       srdy = gpio_get_value(ifx_dev->gpio.srdy);
+       if (!srdy)
+               ifx_spi_power_state_clear(ifx_dev, IFX_SPI_POWER_SRDY);
+
+       /* schedule output if there is more to do */
+       if (test_and_clear_bit(IFX_SPI_STATE_IO_READY, &ifx_dev->flags))
+               tasklet_schedule(&ifx_dev->io_work_tasklet);
+       else {
+               if (more || ifx_dev->spi_more || queue_length > 0 ||
+                       local_write_pending) {
+                       if (ifx_dev->spi_slave_cts) {
+                               if (more)
+                                       mrdy_assert(ifx_dev);
+                       } else
+                               mrdy_assert(ifx_dev);
+               } else {
+                       /*
+                        * poke line discipline driver if any for more data
+                        * may or may not get more data to write
+                        * for now, say not busy
+                        */
+                       ifx_spi_power_state_clear(ifx_dev,
+                                                 IFX_SPI_POWER_DATA_PENDING);
+                       tty = tty_port_tty_get(&ifx_dev->tty_port);
+                       if (tty) {
+                               ldisc = tty_ldisc_ref(tty);
+                               if (ldisc) {
+                                       ldisc->ops->write_wakeup(tty);
+                                       tty_ldisc_deref(ldisc);
+                               }
+                               tty_kref_put(tty);
+                       }
+               }
+       }
+}
+
+/**
+ *     ifx_spio_io             -       I/O tasklet
+ *     @data: our SPI device
+ *
+ *     Queue data for transmission if possible and then kick off the
+ *     transfer.
+ */
+static void ifx_spi_io(unsigned long data)
+{
+       int retval;
+       struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *) data;
+
+       if (!test_and_set_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags)) {
+               if (ifx_dev->gpio.unack_srdy_int_nb > 0)
+                       ifx_dev->gpio.unack_srdy_int_nb--;
+
+               ifx_spi_prepare_tx_buffer(ifx_dev);
+
+               spi_message_init(&ifx_dev->spi_msg);
+               INIT_LIST_HEAD(&ifx_dev->spi_msg.queue);
+
+               ifx_dev->spi_msg.context = ifx_dev;
+               ifx_dev->spi_msg.complete = ifx_spi_complete;
+
+               /* set up our spi transfer */
+               /* note len is BYTES, not transfers */
+               ifx_dev->spi_xfer.len = IFX_SPI_TRANSFER_SIZE;
+               ifx_dev->spi_xfer.cs_change = 0;
+               ifx_dev->spi_xfer.speed_hz = 12500000;
+               /* ifx_dev->spi_xfer.speed_hz = 390625; */
+               ifx_dev->spi_xfer.bits_per_word = spi_b16 ? 16 : 8;
+
+               ifx_dev->spi_xfer.tx_buf = ifx_dev->tx_buffer;
+               ifx_dev->spi_xfer.rx_buf = ifx_dev->rx_buffer;
+
+               /*
+                * setup dma pointers
+                */
+               if (ifx_dev->is_6160) {
+                       ifx_dev->spi_msg.is_dma_mapped = 1;
+                       ifx_dev->tx_dma = ifx_dev->tx_bus;
+                       ifx_dev->rx_dma = ifx_dev->rx_bus;
+                       ifx_dev->spi_xfer.tx_dma = ifx_dev->tx_dma;
+                       ifx_dev->spi_xfer.rx_dma = ifx_dev->rx_dma;
+               } else {
+                       ifx_dev->spi_msg.is_dma_mapped = 0;
+                       ifx_dev->tx_dma = (dma_addr_t)0;
+                       ifx_dev->rx_dma = (dma_addr_t)0;
+                       ifx_dev->spi_xfer.tx_dma = (dma_addr_t)0;
+                       ifx_dev->spi_xfer.rx_dma = (dma_addr_t)0;
+               }
+
+               spi_message_add_tail(&ifx_dev->spi_xfer, &ifx_dev->spi_msg);
+
+               /* Assert MRDY. This may have already been done by the write
+                * routine.
+                */
+               mrdy_assert(ifx_dev);
+
+               retval = spi_async(ifx_dev->spi_dev, &ifx_dev->spi_msg);
+               if (retval) {
+                       clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS,
+                                 &ifx_dev->flags);
+                       tasklet_schedule(&ifx_dev->io_work_tasklet);
+                       return;
+               }
+       } else
+               ifx_dev->write_pending = 1;
+}
+
+/**
+ *     ifx_spi_free_port       -       free up the tty side
+ *     @ifx_dev: IFX device going away
+ *
+ *     Unregister and free up a port when the device goes away
+ */
+static void ifx_spi_free_port(struct ifx_spi_device *ifx_dev)
+{
+       if (ifx_dev->tty_dev)
+               tty_unregister_device(tty_drv, ifx_dev->minor);
+       kfifo_free(&ifx_dev->tx_fifo);
+}
+
+/**
+ *     ifx_spi_create_port     -       create a new port
+ *     @ifx_dev: our spi device
+ *
+ *     Allocate and initialise the tty port that goes with this interface
+ *     and add it to the tty layer so that it can be opened.
+ */
+static int ifx_spi_create_port(struct ifx_spi_device *ifx_dev)
+{
+       int ret = 0;
+       struct tty_port *pport = &ifx_dev->tty_port;
+
+       spin_lock_init(&ifx_dev->fifo_lock);
+       lockdep_set_class_and_subclass(&ifx_dev->fifo_lock,
+               &ifx_spi_key, 0);
+
+       if (kfifo_alloc(&ifx_dev->tx_fifo, IFX_SPI_FIFO_SIZE, GFP_KERNEL)) {
+               ret = -ENOMEM;
+               goto error_ret;
+       }
+
+       pport->ops = &ifx_tty_port_ops;
+       tty_port_init(pport);
+       ifx_dev->minor = IFX_SPI_TTY_ID;
+       ifx_dev->tty_dev = tty_register_device(tty_drv, ifx_dev->minor,
+                                              &ifx_dev->spi_dev->dev);
+       if (IS_ERR(ifx_dev->tty_dev)) {
+               dev_dbg(&ifx_dev->spi_dev->dev,
+                       "%s: registering tty device failed", __func__);
+               ret = PTR_ERR(ifx_dev->tty_dev);
+               goto error_ret;
+       }
+       return 0;
+
+error_ret:
+       ifx_spi_free_port(ifx_dev);
+       return ret;
+}
+
+/**
+ *     ifx_spi_handle_srdy             -       handle SRDY
+ *     @ifx_dev: device asserting SRDY
+ *
+ *     Check our device state and see what we need to kick off when SRDY
+ *     is asserted. This usually means killing the timer and firing off the
+ *     I/O processing.
+ */
+static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev)
+{
+       if (test_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags)) {
+               del_timer_sync(&ifx_dev->spi_timer);
+               clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
+       }
+
+       ifx_spi_power_state_set(ifx_dev, IFX_SPI_POWER_SRDY);
+
+       if (!test_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags))
+               tasklet_schedule(&ifx_dev->io_work_tasklet);
+       else
+               set_bit(IFX_SPI_STATE_IO_READY, &ifx_dev->flags);
+}
+
+/**
+ *     ifx_spi_srdy_interrupt  -       SRDY asserted
+ *     @irq: our IRQ number
+ *     @dev: our ifx device
+ *
+ *     The modem asserted SRDY. Handle the srdy event
+ */
+static irqreturn_t ifx_spi_srdy_interrupt(int irq, void *dev)
+{
+       struct ifx_spi_device *ifx_dev = dev;
+       ifx_dev->gpio.unack_srdy_int_nb++;
+       ifx_spi_handle_srdy(ifx_dev);
+       return IRQ_HANDLED;
+}
+
+/**
+ *     ifx_spi_reset_interrupt -       Modem has changed reset state
+ *     @irq: interrupt number
+ *     @dev: our device pointer
+ *
+ *     The modem has either entered or left reset state. Check the GPIO
+ *     line to see which.
+ *
+ *     FIXME: review locking on MR_INPROGRESS versus
+ *     parallel unsolicited reset/solicited reset
+ */
+static irqreturn_t ifx_spi_reset_interrupt(int irq, void *dev)
+{
+       struct ifx_spi_device *ifx_dev = dev;
+       int val = gpio_get_value(ifx_dev->gpio.reset_out);
+       int solreset = test_bit(MR_START, &ifx_dev->mdm_reset_state);
+
+       if (val == 0) {
+               /* entered reset */
+               set_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state);
+               if (!solreset) {
+                       /* unsolicited reset  */
+                       ifx_spi_ttyhangup(ifx_dev);
+               }
+       } else {
+               /* exited reset */
+               clear_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state);
+               if (solreset) {
+                       set_bit(MR_COMPLETE, &ifx_dev->mdm_reset_state);
+                       wake_up(&ifx_dev->mdm_reset_wait);
+               }
+       }
+       return IRQ_HANDLED;
+}
+
+/**
+ *     ifx_spi_free_device - free device
+ *     @ifx_dev: device to free
+ *
+ *     Free the IFX device
+ */
+static void ifx_spi_free_device(struct ifx_spi_device *ifx_dev)
+{
+       ifx_spi_free_port(ifx_dev);
+       dma_free_coherent(&ifx_dev->spi_dev->dev,
+                               IFX_SPI_TRANSFER_SIZE,
+                               ifx_dev->tx_buffer,
+                               ifx_dev->tx_bus);
+       dma_free_coherent(&ifx_dev->spi_dev->dev,
+                               IFX_SPI_TRANSFER_SIZE,
+                               ifx_dev->rx_buffer,
+                               ifx_dev->rx_bus);
+}
+
+/**
+ *     ifx_spi_reset   -       reset modem
+ *     @ifx_dev: modem to reset
+ *
+ *     Perform a reset on the modem
+ */
+static int ifx_spi_reset(struct ifx_spi_device *ifx_dev)
+{
+       int ret;
+       /*
+        * set up modem power, reset
+        *
+        * delays are required on some platforms for the modem
+        * to reset properly
+        */
+       set_bit(MR_START, &ifx_dev->mdm_reset_state);
+       gpio_set_value(ifx_dev->gpio.po, 0);
+       gpio_set_value(ifx_dev->gpio.reset, 0);
+       msleep(25);
+       gpio_set_value(ifx_dev->gpio.reset, 1);
+       msleep(1);
+       gpio_set_value(ifx_dev->gpio.po, 1);
+       msleep(1);
+       gpio_set_value(ifx_dev->gpio.po, 0);
+       ret = wait_event_timeout(ifx_dev->mdm_reset_wait,
+                                test_bit(MR_COMPLETE,
+                                         &ifx_dev->mdm_reset_state),
+                                IFX_RESET_TIMEOUT);
+       if (!ret)
+               dev_warn(&ifx_dev->spi_dev->dev, "Modem reset timeout: (state:%lx)",
+                        ifx_dev->mdm_reset_state);
+
+       ifx_dev->mdm_reset_state = 0;
+       return ret;
+}
+
+/**
+ *     ifx_spi_spi_probe       -       probe callback
+ *     @spi: our possible matching SPI device
+ *
+ *     Probe for a 6x60 modem on SPI bus. Perform any needed device and
+ *     GPIO setup.
+ *
+ *     FIXME:
+ *     -       Support for multiple devices
+ *     -       Split out MID specific GPIO handling eventually
+ */
+
+static int ifx_spi_spi_probe(struct spi_device *spi)
+{
+       int ret;
+       int srdy;
+       struct ifx_modem_platform_data *pl_data = NULL;
+       struct ifx_spi_device *ifx_dev;
+
+       if (saved_ifx_dev) {
+               dev_dbg(&spi->dev, "ignoring subsequent detection");
+               return -ENODEV;
+       }
+
+       /* initialize structure to hold our device variables */
+       ifx_dev = kzalloc(sizeof(struct ifx_spi_device), GFP_KERNEL);
+       if (!ifx_dev) {
+               dev_err(&spi->dev, "spi device allocation failed");
+               return -ENOMEM;
+       }
+       saved_ifx_dev = ifx_dev;
+       ifx_dev->spi_dev = spi;
+       clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags);
+       spin_lock_init(&ifx_dev->write_lock);
+       spin_lock_init(&ifx_dev->power_lock);
+       ifx_dev->power_status = 0;
+       init_timer(&ifx_dev->spi_timer);
+       ifx_dev->spi_timer.function = ifx_spi_timeout;
+       ifx_dev->spi_timer.data = (unsigned long)ifx_dev;
+       ifx_dev->is_6160 = pl_data->is_6160;
+
+       /* ensure SPI protocol flags are initialized to enable transfer */
+       ifx_dev->spi_more = 0;
+       ifx_dev->spi_slave_cts = 0;
+
+       /*initialize transfer and dma buffers */
+       ifx_dev->tx_buffer = dma_alloc_coherent(&ifx_dev->spi_dev->dev,
+                               IFX_SPI_TRANSFER_SIZE,
+                               &ifx_dev->tx_bus,
+                               GFP_KERNEL);
+       if (!ifx_dev->tx_buffer) {
+               dev_err(&spi->dev, "DMA-TX buffer allocation failed");
+               ret = -ENOMEM;
+               goto error_ret;
+       }
+       ifx_dev->rx_buffer = dma_alloc_coherent(&ifx_dev->spi_dev->dev,
+                               IFX_SPI_TRANSFER_SIZE,
+                               &ifx_dev->rx_bus,
+                               GFP_KERNEL);
+       if (!ifx_dev->rx_buffer) {
+               dev_err(&spi->dev, "DMA-RX buffer allocation failed");
+               ret = -ENOMEM;
+               goto error_ret;
+       }
+
+       /* initialize waitq for modem reset */
+       init_waitqueue_head(&ifx_dev->mdm_reset_wait);
+
+       spi_set_drvdata(spi, ifx_dev);
+       tasklet_init(&ifx_dev->io_work_tasklet, ifx_spi_io,
+                                               (unsigned long)ifx_dev);
+
+       set_bit(IFX_SPI_STATE_PRESENT, &ifx_dev->flags);
+
+       /* create our tty port */
+       ret = ifx_spi_create_port(ifx_dev);
+       if (ret != 0) {
+               dev_err(&spi->dev, "create default tty port failed");
+               goto error_ret;
+       }
+
+       pl_data = (struct ifx_modem_platform_data *)spi->dev.platform_data;
+       if (pl_data) {
+               ifx_dev->gpio.reset = pl_data->rst_pmu;
+               ifx_dev->gpio.po = pl_data->pwr_on;
+               ifx_dev->gpio.mrdy = pl_data->mrdy;
+               ifx_dev->gpio.srdy = pl_data->srdy;
+               ifx_dev->gpio.reset_out = pl_data->rst_out;
+       } else {
+               dev_err(&spi->dev, "missing platform data!");
+               ret = -ENODEV;
+               goto error_ret;
+       }
+
+       dev_info(&spi->dev, "gpios %d, %d, %d, %d, %d",
+                ifx_dev->gpio.reset, ifx_dev->gpio.po, ifx_dev->gpio.mrdy,
+                ifx_dev->gpio.srdy, ifx_dev->gpio.reset_out);
+
+       /* Configure gpios */
+       ret = gpio_request(ifx_dev->gpio.reset, "ifxModem");
+       if (ret < 0) {
+               dev_err(&spi->dev, "Unable to allocate GPIO%d (RESET)",
+                       ifx_dev->gpio.reset);
+               goto error_ret;
+       }
+       ret += gpio_direction_output(ifx_dev->gpio.reset, 0);
+       ret += gpio_export(ifx_dev->gpio.reset, 1);
+       if (ret) {
+               dev_err(&spi->dev, "Unable to configure GPIO%d (RESET)",
+                       ifx_dev->gpio.reset);
+               ret = -EBUSY;
+               goto error_ret2;
+       }
+
+       ret = gpio_request(ifx_dev->gpio.po, "ifxModem");
+       ret += gpio_direction_output(ifx_dev->gpio.po, 0);
+       ret += gpio_export(ifx_dev->gpio.po, 1);
+       if (ret) {
+               dev_err(&spi->dev, "Unable to configure GPIO%d (ON)",
+                       ifx_dev->gpio.po);
+               ret = -EBUSY;
+               goto error_ret3;
+       }
+
+       ret = gpio_request(ifx_dev->gpio.mrdy, "ifxModem");
+       if (ret < 0) {
+               dev_err(&spi->dev, "Unable to allocate GPIO%d (MRDY)",
+                       ifx_dev->gpio.mrdy);
+               goto error_ret3;
+       }
+       ret += gpio_export(ifx_dev->gpio.mrdy, 1);
+       ret += gpio_direction_output(ifx_dev->gpio.mrdy, 0);
+       if (ret) {
+               dev_err(&spi->dev, "Unable to configure GPIO%d (MRDY)",
+                       ifx_dev->gpio.mrdy);
+               ret = -EBUSY;
+               goto error_ret4;
+       }
+
+       ret = gpio_request(ifx_dev->gpio.srdy, "ifxModem");
+       if (ret < 0) {
+               dev_err(&spi->dev, "Unable to allocate GPIO%d (SRDY)",
+                       ifx_dev->gpio.srdy);
+               ret = -EBUSY;
+               goto error_ret4;
+       }
+       ret += gpio_export(ifx_dev->gpio.srdy, 1);
+       ret += gpio_direction_input(ifx_dev->gpio.srdy);
+       if (ret) {
+               dev_err(&spi->dev, "Unable to configure GPIO%d (SRDY)",
+                       ifx_dev->gpio.srdy);
+               ret = -EBUSY;
+               goto error_ret5;
+       }
+
+       ret = gpio_request(ifx_dev->gpio.reset_out, "ifxModem");
+       if (ret < 0) {
+               dev_err(&spi->dev, "Unable to allocate GPIO%d (RESET_OUT)",
+                       ifx_dev->gpio.reset_out);
+               goto error_ret5;
+       }
+       ret += gpio_export(ifx_dev->gpio.reset_out, 1);
+       ret += gpio_direction_input(ifx_dev->gpio.reset_out);
+       if (ret) {
+               dev_err(&spi->dev, "Unable to configure GPIO%d (RESET_OUT)",
+                       ifx_dev->gpio.reset_out);
+               ret = -EBUSY;
+               goto error_ret6;
+       }
+
+       ret = request_irq(gpio_to_irq(ifx_dev->gpio.reset_out),
+                         ifx_spi_reset_interrupt,
+                         IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, DRVNAME,
+               (void *)ifx_dev);
+       if (ret) {
+               dev_err(&spi->dev, "Unable to get irq %x\n",
+                       gpio_to_irq(ifx_dev->gpio.reset_out));
+               goto error_ret6;
+       }
+
+       ret = ifx_spi_reset(ifx_dev);
+
+       ret = request_irq(gpio_to_irq(ifx_dev->gpio.srdy),
+                         ifx_spi_srdy_interrupt,
+                         IRQF_TRIGGER_RISING, DRVNAME,
+                         (void *)ifx_dev);
+       if (ret) {
+               dev_err(&spi->dev, "Unable to get irq %x",
+                       gpio_to_irq(ifx_dev->gpio.srdy));
+               goto error_ret7;
+       }
+
+       /* set pm runtime power state and register with power system */
+       pm_runtime_set_active(&spi->dev);
+       pm_runtime_enable(&spi->dev);
+
+       /* handle case that modem is already signaling SRDY */
+       /* no outgoing tty open at this point, this just satisfies the
+        * modem's read and should reset communication properly
+        */
+       srdy = gpio_get_value(ifx_dev->gpio.srdy);
+
+       if (srdy) {
+               mrdy_assert(ifx_dev);
+               ifx_spi_handle_srdy(ifx_dev);
+       } else
+               mrdy_set_low(ifx_dev);
+       return 0;
+
+error_ret7:
+       free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev);
+error_ret6:
+       gpio_free(ifx_dev->gpio.srdy);
+error_ret5:
+       gpio_free(ifx_dev->gpio.mrdy);
+error_ret4:
+       gpio_free(ifx_dev->gpio.reset);
+error_ret3:
+       gpio_free(ifx_dev->gpio.po);
+error_ret2:
+       gpio_free(ifx_dev->gpio.reset_out);
+error_ret:
+       ifx_spi_free_device(ifx_dev);
+       saved_ifx_dev = NULL;
+       return ret;
+}
+
+/**
+ *     ifx_spi_spi_remove      -       SPI device was removed
+ *     @spi: SPI device
+ *
+ *     FIXME: We should be shutting the device down here not in
+ *     the module unload path.
+ */
+
+static int ifx_spi_spi_remove(struct spi_device *spi)
+{
+       struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi);
+       /* stop activity */
+       tasklet_kill(&ifx_dev->io_work_tasklet);
+       /* free irq */
+       free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev);
+       free_irq(gpio_to_irq(ifx_dev->gpio.srdy), (void *)ifx_dev);
+
+       gpio_free(ifx_dev->gpio.srdy);
+       gpio_free(ifx_dev->gpio.mrdy);
+       gpio_free(ifx_dev->gpio.reset);
+       gpio_free(ifx_dev->gpio.po);
+       gpio_free(ifx_dev->gpio.reset_out);
+
+       /* free allocations */
+       ifx_spi_free_device(ifx_dev);
+
+       saved_ifx_dev = NULL;
+       return 0;
+}
+
+/**
+ *     ifx_spi_spi_shutdown    -       called on SPI shutdown
+ *     @spi: SPI device
+ *
+ *     No action needs to be taken here
+ */
+
+static void ifx_spi_spi_shutdown(struct spi_device *spi)
+{
+}
+
+/*
+ * various suspends and resumes have nothing to do
+ * no hardware to save state for
+ */
+
+/**
+ *     ifx_spi_spi_suspend     -       suspend SPI on system suspend
+ *     @dev: device being suspended
+ *
+ *     Suspend the SPI side. No action needed on Intel MID platforms, may
+ *     need extending for other systems.
+ */
+static int ifx_spi_spi_suspend(struct spi_device *spi, pm_message_t msg)
+{
+       return 0;
+}
+
+/**
+ *     ifx_spi_spi_resume      -       resume SPI side on system resume
+ *     @dev: device being suspended
+ *
+ *     Suspend the SPI side. No action needed on Intel MID platforms, may
+ *     need extending for other systems.
+ */
+static int ifx_spi_spi_resume(struct spi_device *spi)
+{
+       return 0;
+}
+
+/**
+ *     ifx_spi_pm_suspend      -       suspend modem on system suspend
+ *     @dev: device being suspended
+ *
+ *     Suspend the modem. No action needed on Intel MID platforms, may
+ *     need extending for other systems.
+ */
+static int ifx_spi_pm_suspend(struct device *dev)
+{
+       return 0;
+}
+
+/**
+ *     ifx_spi_pm_resume       -       resume modem on system resume
+ *     @dev: device being suspended
+ *
+ *     Allow the modem to resume. No action needed.
+ *
+ *     FIXME: do we need to reset anything here ?
+ */
+static int ifx_spi_pm_resume(struct device *dev)
+{
+       return 0;
+}
+
+/**
+ *     ifx_spi_pm_runtime_resume       -       suspend modem
+ *     @dev: device being suspended
+ *
+ *     Allow the modem to resume. No action needed.
+ */
+static int ifx_spi_pm_runtime_resume(struct device *dev)
+{
+       return 0;
+}
+
+/**
+ *     ifx_spi_pm_runtime_suspend      -       suspend modem
+ *     @dev: device being suspended
+ *
+ *     Allow the modem to suspend and thus suspend to continue up the
+ *     device tree.
+ */
+static int ifx_spi_pm_runtime_suspend(struct device *dev)
+{
+       return 0;
+}
+
+/**
+ *     ifx_spi_pm_runtime_idle         -       check if modem idle
+ *     @dev: our device
+ *
+ *     Check conditions and queue runtime suspend if idle.
+ */
+static int ifx_spi_pm_runtime_idle(struct device *dev)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi);
+
+       if (!ifx_dev->power_status)
+               pm_runtime_suspend(dev);
+
+       return 0;
+}
+
+static const struct dev_pm_ops ifx_spi_pm = {
+       .resume = ifx_spi_pm_resume,
+       .suspend = ifx_spi_pm_suspend,
+       .runtime_resume = ifx_spi_pm_runtime_resume,
+       .runtime_suspend = ifx_spi_pm_runtime_suspend,
+       .runtime_idle = ifx_spi_pm_runtime_idle
+};
+
+static const struct spi_device_id ifx_id_table[] = {
+       {"ifx6160", 0},
+       {"ifx6260", 0},
+       { }
+};
+MODULE_DEVICE_TABLE(spi, ifx_id_table);
+
+/* spi operations */
+static const struct spi_driver ifx_spi_driver_6160 = {
+       .driver = {
+               .name = "ifx6160",
+               .bus = &spi_bus_type,
+               .pm = &ifx_spi_pm,
+               .owner = THIS_MODULE},
+       .probe = ifx_spi_spi_probe,
+       .shutdown = ifx_spi_spi_shutdown,
+       .remove = __devexit_p(ifx_spi_spi_remove),
+       .suspend = ifx_spi_spi_suspend,
+       .resume = ifx_spi_spi_resume,
+       .id_table = ifx_id_table
+};
+
+/**
+ *     ifx_spi_exit    -       module exit
+ *
+ *     Unload the module.
+ */
+
+static void __exit ifx_spi_exit(void)
+{
+       /* unregister */
+       tty_unregister_driver(tty_drv);
+       spi_unregister_driver((void *)&ifx_spi_driver_6160);
+}
+
+/**
+ *     ifx_spi_init            -       module entry point
+ *
+ *     Initialise the SPI and tty interfaces for the IFX SPI driver
+ *     We need to initialize upper-edge spi driver after the tty
+ *     driver because otherwise the spi probe will race
+ */
+
+static int __init ifx_spi_init(void)
+{
+       int result;
+
+       tty_drv = alloc_tty_driver(1);
+       if (!tty_drv) {
+               pr_err("%s: alloc_tty_driver failed", DRVNAME);
+               return -ENOMEM;
+       }
+
+       tty_drv->magic = TTY_DRIVER_MAGIC;
+       tty_drv->owner = THIS_MODULE;
+       tty_drv->driver_name = DRVNAME;
+       tty_drv->name = TTYNAME;
+       tty_drv->minor_start = IFX_SPI_TTY_ID;
+       tty_drv->num = 1;
+       tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
+       tty_drv->subtype = SERIAL_TYPE_NORMAL;
+       tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+       tty_drv->init_termios = tty_std_termios;
+
+       tty_set_operations(tty_drv, &ifx_spi_serial_ops);
+
+       result = tty_register_driver(tty_drv);
+       if (result) {
+               pr_err("%s: tty_register_driver failed(%d)",
+                       DRVNAME, result);
+               put_tty_driver(tty_drv);
+               return result;
+       }
+
+       result = spi_register_driver((void *)&ifx_spi_driver_6160);
+       if (result) {
+               pr_err("%s: spi_register_driver failed(%d)",
+                       DRVNAME, result);
+               tty_unregister_driver(tty_drv);
+       }
+       return result;
+}
+
+module_init(ifx_spi_init);
+module_exit(ifx_spi_exit);
+
+MODULE_AUTHOR("Intel");
+MODULE_DESCRIPTION("IFX6x60 spi driver");
+MODULE_LICENSE("GPL");
+MODULE_INFO(Version, "0.1-IFX6x60");
diff --git a/drivers/tty/serial/ifx6x60.h b/drivers/tty/serial/ifx6x60.h
new file mode 100644 (file)
index 0000000..deb7b8d
--- /dev/null
@@ -0,0 +1,129 @@
+/****************************************************************************
+ *
+ * Driver for the IFX spi modem.
+ *
+ * Copyright (C) 2009, 2010 Intel Corp
+ * Jim Stanley <jim.stanley@intel.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA
+ *
+ *
+ *
+ *****************************************************************************/
+#ifndef _IFX6X60_H
+#define _IFX6X60_H
+
+#define DRVNAME                                "ifx6x60"
+#define TTYNAME                                "ttyIFX"
+
+/* #define IFX_THROTTLE_CODE */
+
+#define IFX_SPI_MAX_MINORS             1
+#define IFX_SPI_TRANSFER_SIZE          2048
+#define IFX_SPI_FIFO_SIZE              4096
+
+#define IFX_SPI_HEADER_OVERHEAD                4
+#define IFX_RESET_TIMEOUT              msecs_to_jiffies(50)
+
+/* device flags bitfield definitions */
+#define IFX_SPI_STATE_PRESENT          0
+#define IFX_SPI_STATE_IO_IN_PROGRESS   1
+#define IFX_SPI_STATE_IO_READY         2
+#define IFX_SPI_STATE_TIMER_PENDING    3
+
+/* flow control bitfields */
+#define IFX_SPI_DCD                    0
+#define IFX_SPI_CTS                    1
+#define IFX_SPI_DSR                    2
+#define IFX_SPI_RI                     3
+#define IFX_SPI_DTR                    4
+#define IFX_SPI_RTS                    5
+#define IFX_SPI_TX_FC                  6
+#define IFX_SPI_RX_FC                  7
+#define IFX_SPI_UPDATE                 8
+
+#define IFX_SPI_PAYLOAD_SIZE           (IFX_SPI_TRANSFER_SIZE - \
+                                               IFX_SPI_HEADER_OVERHEAD)
+
+#define IFX_SPI_IRQ_TYPE               DETECT_EDGE_RISING
+#define IFX_SPI_GPIO_TARGET            0
+#define IFX_SPI_GPIO0                  0x105
+
+#define IFX_SPI_STATUS_TIMEOUT         (2000*HZ)
+
+/* values for bits in power status byte */
+#define IFX_SPI_POWER_DATA_PENDING     1
+#define IFX_SPI_POWER_SRDY             2
+
+struct ifx_spi_device {
+       /* Our SPI device */
+       struct spi_device *spi_dev;
+
+       /* Port specific data */
+       struct kfifo tx_fifo;
+       spinlock_t fifo_lock;
+       unsigned long signal_state;
+
+       /* TTY Layer logic */
+       struct tty_port tty_port;
+       struct device *tty_dev;
+       int minor;
+
+       /* Low level I/O work */
+       struct tasklet_struct io_work_tasklet;
+       unsigned long flags;
+       dma_addr_t rx_dma;
+       dma_addr_t tx_dma;
+
+       int is_6160;                            /* Modem type */
+
+       spinlock_t write_lock;
+       int write_pending;
+       spinlock_t power_lock;
+       unsigned char power_status;
+
+       unsigned char *rx_buffer;
+       unsigned char *tx_buffer;
+       dma_addr_t rx_bus;
+       dma_addr_t tx_bus;
+       unsigned char spi_more;
+       unsigned char spi_slave_cts;
+
+       struct timer_list spi_timer;
+
+       struct spi_message spi_msg;
+       struct spi_transfer spi_xfer;
+
+       struct {
+               /* gpio lines */
+               unsigned short srdy;            /* slave-ready gpio */
+               unsigned short mrdy;            /* master-ready gpio */
+               unsigned short reset;           /* modem-reset gpio */
+               unsigned short po;              /* modem-on gpio */
+               unsigned short reset_out;       /* modem-in-reset gpio */
+               /* state/stats */
+               int unack_srdy_int_nb;
+       } gpio;
+
+       /* modem reset */
+       unsigned long mdm_reset_state;
+#define MR_START       0
+#define MR_INPROGRESS  1
+#define MR_COMPLETE    2
+       wait_queue_head_t mdm_reset_wait;
+};
+
+#endif /* _IFX6X60_H */
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
new file mode 100644 (file)
index 0000000..dfcf4b1
--- /dev/null
@@ -0,0 +1,1380 @@
+/*
+ *  linux/drivers/serial/imx.c
+ *
+ *  Driver for Motorola IMX serial ports
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ *  Author: Sascha Hauer <sascha@saschahauer.de>
+ *  Copyright (C) 2004 Pengutronix
+ *
+ *  Copyright (C) 2009 emlix GmbH
+ *  Author: Fabian Godehardt (added IrDA support for iMX)
+ *
+ * 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
+ *
+ * [29-Mar-2005] Mike Lee
+ * Added hardware handshake
+ */
+
+#if defined(CONFIG_SERIAL_IMX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/rational.h>
+#include <linux/slab.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <mach/hardware.h>
+#include <mach/imx-uart.h>
+
+/* Register definitions */
+#define URXD0 0x0  /* Receiver Register */
+#define URTX0 0x40 /* Transmitter Register */
+#define UCR1  0x80 /* Control Register 1 */
+#define UCR2  0x84 /* Control Register 2 */
+#define UCR3  0x88 /* Control Register 3 */
+#define UCR4  0x8c /* Control Register 4 */
+#define UFCR  0x90 /* FIFO Control Register */
+#define USR1  0x94 /* Status Register 1 */
+#define USR2  0x98 /* Status Register 2 */
+#define UESC  0x9c /* Escape Character Register */
+#define UTIM  0xa0 /* Escape Timer Register */
+#define UBIR  0xa4 /* BRM Incremental Register */
+#define UBMR  0xa8 /* BRM Modulator Register */
+#define UBRC  0xac /* Baud Rate Count Register */
+#define MX2_ONEMS 0xb0 /* One Millisecond register */
+#define UTS (cpu_is_mx1() ? 0xd0 : 0xb4) /* UART Test Register */
+
+/* UART Control Register Bit Fields.*/
+#define  URXD_CHARRDY    (1<<15)
+#define  URXD_ERR        (1<<14)
+#define  URXD_OVRRUN     (1<<13)
+#define  URXD_FRMERR     (1<<12)
+#define  URXD_BRK        (1<<11)
+#define  URXD_PRERR      (1<<10)
+#define  UCR1_ADEN       (1<<15) /* Auto dectect interrupt */
+#define  UCR1_ADBR       (1<<14) /* Auto detect baud rate */
+#define  UCR1_TRDYEN     (1<<13) /* Transmitter ready interrupt enable */
+#define  UCR1_IDEN       (1<<12) /* Idle condition interrupt */
+#define  UCR1_RRDYEN     (1<<9)         /* Recv ready interrupt enable */
+#define  UCR1_RDMAEN     (1<<8)         /* Recv ready DMA enable */
+#define  UCR1_IREN       (1<<7)         /* Infrared interface enable */
+#define  UCR1_TXMPTYEN   (1<<6)         /* Transimitter empty interrupt enable */
+#define  UCR1_RTSDEN     (1<<5)         /* RTS delta interrupt enable */
+#define  UCR1_SNDBRK     (1<<4)         /* Send break */
+#define  UCR1_TDMAEN     (1<<3)         /* Transmitter ready DMA enable */
+#define  MX1_UCR1_UARTCLKEN  (1<<2)     /* UART clock enabled, mx1 only */
+#define  UCR1_DOZE       (1<<1)         /* Doze */
+#define  UCR1_UARTEN     (1<<0)         /* UART enabled */
+#define  UCR2_ESCI              (1<<15) /* Escape seq interrupt enable */
+#define  UCR2_IRTS      (1<<14) /* Ignore RTS pin */
+#define  UCR2_CTSC      (1<<13) /* CTS pin control */
+#define  UCR2_CTS        (1<<12) /* Clear to send */
+#define  UCR2_ESCEN      (1<<11) /* Escape enable */
+#define  UCR2_PREN       (1<<8)  /* Parity enable */
+#define  UCR2_PROE       (1<<7)  /* Parity odd/even */
+#define  UCR2_STPB       (1<<6)         /* Stop */
+#define  UCR2_WS         (1<<5)         /* Word size */
+#define  UCR2_RTSEN      (1<<4)         /* Request to send interrupt enable */
+#define  UCR2_TXEN       (1<<2)         /* Transmitter enabled */
+#define  UCR2_RXEN       (1<<1)         /* Receiver enabled */
+#define  UCR2_SRST      (1<<0)  /* SW reset */
+#define  UCR3_DTREN     (1<<13) /* DTR interrupt enable */
+#define  UCR3_PARERREN   (1<<12) /* Parity enable */
+#define  UCR3_FRAERREN   (1<<11) /* Frame error interrupt enable */
+#define  UCR3_DSR        (1<<10) /* Data set ready */
+#define  UCR3_DCD        (1<<9)  /* Data carrier detect */
+#define  UCR3_RI         (1<<8)  /* Ring indicator */
+#define  UCR3_TIMEOUTEN  (1<<7)  /* Timeout interrupt enable */
+#define  UCR3_RXDSEN    (1<<6)  /* Receive status interrupt enable */
+#define  UCR3_AIRINTEN   (1<<5)  /* Async IR wake interrupt enable */
+#define  UCR3_AWAKEN    (1<<4)  /* Async wake interrupt enable */
+#define  MX1_UCR3_REF25         (1<<3)  /* Ref freq 25 MHz, only on mx1 */
+#define  MX1_UCR3_REF30         (1<<2)  /* Ref Freq 30 MHz, only on mx1 */
+#define  MX2_UCR3_RXDMUXSEL     (1<<2)  /* RXD Muxed Input Select, on mx2/mx3 */
+#define  UCR3_INVT      (1<<1)  /* Inverted Infrared transmission */
+#define  UCR3_BPEN      (1<<0)  /* Preset registers enable */
+#define  UCR4_CTSTL_SHF  10      /* CTS trigger level shift */
+#define  UCR4_CTSTL_MASK 0x3F    /* CTS trigger is 6 bits wide */
+#define  UCR4_INVR      (1<<9)  /* Inverted infrared reception */
+#define  UCR4_ENIRI     (1<<8)  /* Serial infrared interrupt enable */
+#define  UCR4_WKEN      (1<<7)  /* Wake interrupt enable */
+#define  UCR4_REF16     (1<<6)  /* Ref freq 16 MHz */
+#define  UCR4_IRSC      (1<<5)  /* IR special case */
+#define  UCR4_TCEN      (1<<3)  /* Transmit complete interrupt enable */
+#define  UCR4_BKEN      (1<<2)  /* Break condition interrupt enable */
+#define  UCR4_OREN      (1<<1)  /* Receiver overrun interrupt enable */
+#define  UCR4_DREN      (1<<0)  /* Recv data ready interrupt enable */
+#define  UFCR_RXTL_SHF   0       /* Receiver trigger level shift */
+#define  UFCR_RFDIV      (7<<7)  /* Reference freq divider mask */
+#define  UFCR_RFDIV_REG(x)     (((x) < 7 ? 6 - (x) : 6) << 7)
+#define  UFCR_TXTL_SHF   10      /* Transmitter trigger level shift */
+#define  USR1_PARITYERR  (1<<15) /* Parity error interrupt flag */
+#define  USR1_RTSS      (1<<14) /* RTS pin status */
+#define  USR1_TRDY      (1<<13) /* Transmitter ready interrupt/dma flag */
+#define  USR1_RTSD      (1<<12) /* RTS delta */
+#define  USR1_ESCF      (1<<11) /* Escape seq interrupt flag */
+#define  USR1_FRAMERR    (1<<10) /* Frame error interrupt flag */
+#define  USR1_RRDY       (1<<9)         /* Receiver ready interrupt/dma flag */
+#define  USR1_TIMEOUT    (1<<7)         /* Receive timeout interrupt status */
+#define  USR1_RXDS      (1<<6)  /* Receiver idle interrupt flag */
+#define  USR1_AIRINT    (1<<5)  /* Async IR wake interrupt flag */
+#define  USR1_AWAKE     (1<<4)  /* Aysnc wake interrupt flag */
+#define  USR2_ADET      (1<<15) /* Auto baud rate detect complete */
+#define  USR2_TXFE      (1<<14) /* Transmit buffer FIFO empty */
+#define  USR2_DTRF      (1<<13) /* DTR edge interrupt flag */
+#define  USR2_IDLE      (1<<12) /* Idle condition */
+#define  USR2_IRINT     (1<<8)  /* Serial infrared interrupt flag */
+#define  USR2_WAKE      (1<<7)  /* Wake */
+#define  USR2_RTSF      (1<<4)  /* RTS edge interrupt flag */
+#define  USR2_TXDC      (1<<3)  /* Transmitter complete */
+#define  USR2_BRCD      (1<<2)  /* Break condition */
+#define  USR2_ORE        (1<<1)         /* Overrun error */
+#define  USR2_RDR        (1<<0)         /* Recv data ready */
+#define  UTS_FRCPERR    (1<<13) /* Force parity error */
+#define  UTS_LOOP        (1<<12) /* Loop tx and rx */
+#define  UTS_TXEMPTY    (1<<6)  /* TxFIFO empty */
+#define  UTS_RXEMPTY    (1<<5)  /* RxFIFO empty */
+#define  UTS_TXFULL     (1<<4)  /* TxFIFO full */
+#define  UTS_RXFULL     (1<<3)  /* RxFIFO full */
+#define  UTS_SOFTRST    (1<<0)  /* Software reset */
+
+/* We've been assigned a range on the "Low-density serial ports" major */
+#define SERIAL_IMX_MAJOR        207
+#define MINOR_START            16
+#define DEV_NAME               "ttymxc"
+#define MAX_INTERNAL_IRQ       MXC_INTERNAL_IRQS
+
+/*
+ * This determines how often we check the modem status signals
+ * for any change.  They generally aren't connected to an IRQ
+ * so we have to poll them.  We also check immediately before
+ * filling the TX fifo incase CTS has been dropped.
+ */
+#define MCTRL_TIMEOUT  (250*HZ/1000)
+
+#define DRIVER_NAME "IMX-uart"
+
+#define UART_NR 8
+
+struct imx_port {
+       struct uart_port        port;
+       struct timer_list       timer;
+       unsigned int            old_status;
+       int                     txirq,rxirq,rtsirq;
+       unsigned int            have_rtscts:1;
+       unsigned int            use_irda:1;
+       unsigned int            irda_inv_rx:1;
+       unsigned int            irda_inv_tx:1;
+       unsigned short          trcv_delay; /* transceiver delay */
+       struct clk              *clk;
+};
+
+#ifdef CONFIG_IRDA
+#define USE_IRDA(sport)        ((sport)->use_irda)
+#else
+#define USE_IRDA(sport)        (0)
+#endif
+
+/*
+ * Handle any change of modem status signal since we were last called.
+ */
+static void imx_mctrl_check(struct imx_port *sport)
+{
+       unsigned int status, changed;
+
+       status = sport->port.ops->get_mctrl(&sport->port);
+       changed = status ^ sport->old_status;
+
+       if (changed == 0)
+               return;
+
+       sport->old_status = status;
+
+       if (changed & TIOCM_RI)
+               sport->port.icount.rng++;
+       if (changed & TIOCM_DSR)
+               sport->port.icount.dsr++;
+       if (changed & TIOCM_CAR)
+               uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
+       if (changed & TIOCM_CTS)
+               uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
+
+       wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
+}
+
+/*
+ * This is our per-port timeout handler, for checking the
+ * modem status signals.
+ */
+static void imx_timeout(unsigned long data)
+{
+       struct imx_port *sport = (struct imx_port *)data;
+       unsigned long flags;
+
+       if (sport->port.state) {
+               spin_lock_irqsave(&sport->port.lock, flags);
+               imx_mctrl_check(sport);
+               spin_unlock_irqrestore(&sport->port.lock, flags);
+
+               mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
+       }
+}
+
+/*
+ * interrupts disabled on entry
+ */
+static void imx_stop_tx(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       unsigned long temp;
+
+       if (USE_IRDA(sport)) {
+               /* half duplex - wait for end of transmission */
+               int n = 256;
+               while ((--n > 0) &&
+                     !(readl(sport->port.membase + USR2) & USR2_TXDC)) {
+                       udelay(5);
+                       barrier();
+               }
+               /*
+                * irda transceiver - wait a bit more to avoid
+                * cutoff, hardware dependent
+                */
+               udelay(sport->trcv_delay);
+
+               /*
+                * half duplex - reactivate receive mode,
+                * flush receive pipe echo crap
+                */
+               if (readl(sport->port.membase + USR2) & USR2_TXDC) {
+                       temp = readl(sport->port.membase + UCR1);
+                       temp &= ~(UCR1_TXMPTYEN | UCR1_TRDYEN);
+                       writel(temp, sport->port.membase + UCR1);
+
+                       temp = readl(sport->port.membase + UCR4);
+                       temp &= ~(UCR4_TCEN);
+                       writel(temp, sport->port.membase + UCR4);
+
+                       while (readl(sport->port.membase + URXD0) &
+                              URXD_CHARRDY)
+                               barrier();
+
+                       temp = readl(sport->port.membase + UCR1);
+                       temp |= UCR1_RRDYEN;
+                       writel(temp, sport->port.membase + UCR1);
+
+                       temp = readl(sport->port.membase + UCR4);
+                       temp |= UCR4_DREN;
+                       writel(temp, sport->port.membase + UCR4);
+               }
+               return;
+       }
+
+       temp = readl(sport->port.membase + UCR1);
+       writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1);
+}
+
+/*
+ * interrupts disabled on entry
+ */
+static void imx_stop_rx(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       unsigned long temp;
+
+       temp = readl(sport->port.membase + UCR2);
+       writel(temp &~ UCR2_RXEN, sport->port.membase + UCR2);
+}
+
+/*
+ * Set the modem control timer to fire immediately.
+ */
+static void imx_enable_ms(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+
+       mod_timer(&sport->timer, jiffies);
+}
+
+static inline void imx_transmit_buffer(struct imx_port *sport)
+{
+       struct circ_buf *xmit = &sport->port.state->xmit;
+
+       while (!uart_circ_empty(xmit) &&
+                       !(readl(sport->port.membase + UTS) & UTS_TXFULL)) {
+               /* send xmit->buf[xmit->tail]
+                * out the port here */
+               writel(xmit->buf[xmit->tail], sport->port.membase + URTX0);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               sport->port.icount.tx++;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&sport->port);
+
+       if (uart_circ_empty(xmit))
+               imx_stop_tx(&sport->port);
+}
+
+/*
+ * interrupts disabled on entry
+ */
+static void imx_start_tx(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       unsigned long temp;
+
+       if (USE_IRDA(sport)) {
+               /* half duplex in IrDA mode; have to disable receive mode */
+               temp = readl(sport->port.membase + UCR4);
+               temp &= ~(UCR4_DREN);
+               writel(temp, sport->port.membase + UCR4);
+
+               temp = readl(sport->port.membase + UCR1);
+               temp &= ~(UCR1_RRDYEN);
+               writel(temp, sport->port.membase + UCR1);
+       }
+
+       temp = readl(sport->port.membase + UCR1);
+       writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
+
+       if (USE_IRDA(sport)) {
+               temp = readl(sport->port.membase + UCR1);
+               temp |= UCR1_TRDYEN;
+               writel(temp, sport->port.membase + UCR1);
+
+               temp = readl(sport->port.membase + UCR4);
+               temp |= UCR4_TCEN;
+               writel(temp, sport->port.membase + UCR4);
+       }
+
+       if (readl(sport->port.membase + UTS) & UTS_TXEMPTY)
+               imx_transmit_buffer(sport);
+}
+
+static irqreturn_t imx_rtsint(int irq, void *dev_id)
+{
+       struct imx_port *sport = dev_id;
+       unsigned int val = readl(sport->port.membase + USR1) & USR1_RTSS;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sport->port.lock, flags);
+
+       writel(USR1_RTSD, sport->port.membase + USR1);
+       uart_handle_cts_change(&sport->port, !!val);
+       wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
+
+       spin_unlock_irqrestore(&sport->port.lock, flags);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t imx_txint(int irq, void *dev_id)
+{
+       struct imx_port *sport = dev_id;
+       struct circ_buf *xmit = &sport->port.state->xmit;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sport->port.lock,flags);
+       if (sport->port.x_char)
+       {
+               /* Send next char */
+               writel(sport->port.x_char, sport->port.membase + URTX0);
+               goto out;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
+               imx_stop_tx(&sport->port);
+               goto out;
+       }
+
+       imx_transmit_buffer(sport);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&sport->port);
+
+out:
+       spin_unlock_irqrestore(&sport->port.lock,flags);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t imx_rxint(int irq, void *dev_id)
+{
+       struct imx_port *sport = dev_id;
+       unsigned int rx,flg,ignored = 0;
+       struct tty_struct *tty = sport->port.state->port.tty;
+       unsigned long flags, temp;
+
+       spin_lock_irqsave(&sport->port.lock,flags);
+
+       while (readl(sport->port.membase + USR2) & USR2_RDR) {
+               flg = TTY_NORMAL;
+               sport->port.icount.rx++;
+
+               rx = readl(sport->port.membase + URXD0);
+
+               temp = readl(sport->port.membase + USR2);
+               if (temp & USR2_BRCD) {
+                       writel(USR2_BRCD, sport->port.membase + USR2);
+                       if (uart_handle_break(&sport->port))
+                               continue;
+               }
+
+               if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
+                       continue;
+
+               if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) {
+                       if (rx & URXD_PRERR)
+                               sport->port.icount.parity++;
+                       else if (rx & URXD_FRMERR)
+                               sport->port.icount.frame++;
+                       if (rx & URXD_OVRRUN)
+                               sport->port.icount.overrun++;
+
+                       if (rx & sport->port.ignore_status_mask) {
+                               if (++ignored > 100)
+                                       goto out;
+                               continue;
+                       }
+
+                       rx &= sport->port.read_status_mask;
+
+                       if (rx & URXD_PRERR)
+                               flg = TTY_PARITY;
+                       else if (rx & URXD_FRMERR)
+                               flg = TTY_FRAME;
+                       if (rx & URXD_OVRRUN)
+                               flg = TTY_OVERRUN;
+
+#ifdef SUPPORT_SYSRQ
+                       sport->port.sysrq = 0;
+#endif
+               }
+
+               tty_insert_flip_char(tty, rx, flg);
+       }
+
+out:
+       spin_unlock_irqrestore(&sport->port.lock,flags);
+       tty_flip_buffer_push(tty);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t imx_int(int irq, void *dev_id)
+{
+       struct imx_port *sport = dev_id;
+       unsigned int sts;
+
+       sts = readl(sport->port.membase + USR1);
+
+       if (sts & USR1_RRDY)
+               imx_rxint(irq, dev_id);
+
+       if (sts & USR1_TRDY &&
+                       readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN)
+               imx_txint(irq, dev_id);
+
+       if (sts & USR1_RTSD)
+               imx_rtsint(irq, dev_id);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * Return TIOCSER_TEMT when transmitter is not busy.
+ */
+static unsigned int imx_tx_empty(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+
+       return (readl(sport->port.membase + USR2) & USR2_TXDC) ?  TIOCSER_TEMT : 0;
+}
+
+/*
+ * We have a modem side uart, so the meanings of RTS and CTS are inverted.
+ */
+static unsigned int imx_get_mctrl(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       unsigned int tmp = TIOCM_DSR | TIOCM_CAR;
+
+       if (readl(sport->port.membase + USR1) & USR1_RTSS)
+               tmp |= TIOCM_CTS;
+
+       if (readl(sport->port.membase + UCR2) & UCR2_CTS)
+               tmp |= TIOCM_RTS;
+
+       return tmp;
+}
+
+static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       unsigned long temp;
+
+       temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS;
+
+       if (mctrl & TIOCM_RTS)
+               temp |= UCR2_CTS;
+
+       writel(temp, sport->port.membase + UCR2);
+}
+
+/*
+ * Interrupts always disabled.
+ */
+static void imx_break_ctl(struct uart_port *port, int break_state)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       unsigned long flags, temp;
+
+       spin_lock_irqsave(&sport->port.lock, flags);
+
+       temp = readl(sport->port.membase + UCR1) & ~UCR1_SNDBRK;
+
+       if ( break_state != 0 )
+               temp |= UCR1_SNDBRK;
+
+       writel(temp, sport->port.membase + UCR1);
+
+       spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+#define TXTL 2 /* reset default */
+#define RXTL 1 /* reset default */
+
+static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
+{
+       unsigned int val;
+       unsigned int ufcr_rfdiv;
+
+       /* set receiver / transmitter trigger level.
+        * RFDIV is set such way to satisfy requested uartclk value
+        */
+       val = TXTL << 10 | RXTL;
+       ufcr_rfdiv = (clk_get_rate(sport->clk) + sport->port.uartclk / 2)
+                       / sport->port.uartclk;
+
+       if(!ufcr_rfdiv)
+               ufcr_rfdiv = 1;
+
+       val |= UFCR_RFDIV_REG(ufcr_rfdiv);
+
+       writel(val, sport->port.membase + UFCR);
+
+       return 0;
+}
+
+/* half the RX buffer size */
+#define CTSTL 16
+
+static int imx_startup(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       int retval;
+       unsigned long flags, temp;
+
+       imx_setup_ufcr(sport, 0);
+
+       /* disable the DREN bit (Data Ready interrupt enable) before
+        * requesting IRQs
+        */
+       temp = readl(sport->port.membase + UCR4);
+
+       if (USE_IRDA(sport))
+               temp |= UCR4_IRSC;
+
+       /* set the trigger level for CTS */
+       temp &= ~(UCR4_CTSTL_MASK<<  UCR4_CTSTL_SHF);
+       temp |= CTSTL<<  UCR4_CTSTL_SHF;
+
+       writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
+
+       if (USE_IRDA(sport)) {
+               /* reset fifo's and state machines */
+               int i = 100;
+               temp = readl(sport->port.membase + UCR2);
+               temp &= ~UCR2_SRST;
+               writel(temp, sport->port.membase + UCR2);
+               while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) &&
+                   (--i > 0)) {
+                       udelay(1);
+               }
+       }
+
+       /*
+        * Allocate the IRQ(s) i.MX1 has three interrupts whereas later
+        * chips only have one interrupt.
+        */
+       if (sport->txirq > 0) {
+               retval = request_irq(sport->rxirq, imx_rxint, 0,
+                               DRIVER_NAME, sport);
+               if (retval)
+                       goto error_out1;
+
+               retval = request_irq(sport->txirq, imx_txint, 0,
+                               DRIVER_NAME, sport);
+               if (retval)
+                       goto error_out2;
+
+               /* do not use RTS IRQ on IrDA */
+               if (!USE_IRDA(sport)) {
+                       retval = request_irq(sport->rtsirq, imx_rtsint,
+                                    (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 :
+                                      IRQF_TRIGGER_FALLING |
+                                      IRQF_TRIGGER_RISING,
+                                       DRIVER_NAME, sport);
+                       if (retval)
+                               goto error_out3;
+               }
+       } else {
+               retval = request_irq(sport->port.irq, imx_int, 0,
+                               DRIVER_NAME, sport);
+               if (retval) {
+                       free_irq(sport->port.irq, sport);
+                       goto error_out1;
+               }
+       }
+
+       /*
+        * Finally, clear and enable interrupts
+        */
+       writel(USR1_RTSD, sport->port.membase + USR1);
+
+       temp = readl(sport->port.membase + UCR1);
+       temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
+
+       if (USE_IRDA(sport)) {
+               temp |= UCR1_IREN;
+               temp &= ~(UCR1_RTSDEN);
+       }
+
+       writel(temp, sport->port.membase + UCR1);
+
+       temp = readl(sport->port.membase + UCR2);
+       temp |= (UCR2_RXEN | UCR2_TXEN);
+       writel(temp, sport->port.membase + UCR2);
+
+       if (USE_IRDA(sport)) {
+               /* clear RX-FIFO */
+               int i = 64;
+               while ((--i > 0) &&
+                       (readl(sport->port.membase + URXD0) & URXD_CHARRDY)) {
+                       barrier();
+               }
+       }
+
+       if (!cpu_is_mx1()) {
+               temp = readl(sport->port.membase + UCR3);
+               temp |= MX2_UCR3_RXDMUXSEL;
+               writel(temp, sport->port.membase + UCR3);
+       }
+
+       if (USE_IRDA(sport)) {
+               temp = readl(sport->port.membase + UCR4);
+               if (sport->irda_inv_rx)
+                       temp |= UCR4_INVR;
+               else
+                       temp &= ~(UCR4_INVR);
+               writel(temp | UCR4_DREN, sport->port.membase + UCR4);
+
+               temp = readl(sport->port.membase + UCR3);
+               if (sport->irda_inv_tx)
+                       temp |= UCR3_INVT;
+               else
+                       temp &= ~(UCR3_INVT);
+               writel(temp, sport->port.membase + UCR3);
+       }
+
+       /*
+        * Enable modem status interrupts
+        */
+       spin_lock_irqsave(&sport->port.lock,flags);
+       imx_enable_ms(&sport->port);
+       spin_unlock_irqrestore(&sport->port.lock,flags);
+
+       if (USE_IRDA(sport)) {
+               struct imxuart_platform_data *pdata;
+               pdata = sport->port.dev->platform_data;
+               sport->irda_inv_rx = pdata->irda_inv_rx;
+               sport->irda_inv_tx = pdata->irda_inv_tx;
+               sport->trcv_delay = pdata->transceiver_delay;
+               if (pdata->irda_enable)
+                       pdata->irda_enable(1);
+       }
+
+       return 0;
+
+error_out3:
+       if (sport->txirq)
+               free_irq(sport->txirq, sport);
+error_out2:
+       if (sport->rxirq)
+               free_irq(sport->rxirq, sport);
+error_out1:
+       return retval;
+}
+
+static void imx_shutdown(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       unsigned long temp;
+
+       temp = readl(sport->port.membase + UCR2);
+       temp &= ~(UCR2_TXEN);
+       writel(temp, sport->port.membase + UCR2);
+
+       if (USE_IRDA(sport)) {
+               struct imxuart_platform_data *pdata;
+               pdata = sport->port.dev->platform_data;
+               if (pdata->irda_enable)
+                       pdata->irda_enable(0);
+       }
+
+       /*
+        * Stop our timer.
+        */
+       del_timer_sync(&sport->timer);
+
+       /*
+        * Free the interrupts
+        */
+       if (sport->txirq > 0) {
+               if (!USE_IRDA(sport))
+                       free_irq(sport->rtsirq, sport);
+               free_irq(sport->txirq, sport);
+               free_irq(sport->rxirq, sport);
+       } else
+               free_irq(sport->port.irq, sport);
+
+       /*
+        * Disable all interrupts, port and break condition.
+        */
+
+       temp = readl(sport->port.membase + UCR1);
+       temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);
+       if (USE_IRDA(sport))
+               temp &= ~(UCR1_IREN);
+
+       writel(temp, sport->port.membase + UCR1);
+}
+
+static void
+imx_set_termios(struct uart_port *port, struct ktermios *termios,
+                  struct ktermios *old)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       unsigned long flags;
+       unsigned int ucr2, old_ucr1, old_txrxen, baud, quot;
+       unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
+       unsigned int div, ufcr;
+       unsigned long num, denom;
+       uint64_t tdiv64;
+
+       /*
+        * If we don't support modem control lines, don't allow
+        * these to be set.
+        */
+       if (0) {
+               termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR);
+               termios->c_cflag |= CLOCAL;
+       }
+
+       /*
+        * We only support CS7 and CS8.
+        */
+       while ((termios->c_cflag & CSIZE) != CS7 &&
+              (termios->c_cflag & CSIZE) != CS8) {
+               termios->c_cflag &= ~CSIZE;
+               termios->c_cflag |= old_csize;
+               old_csize = CS8;
+       }
+
+       if ((termios->c_cflag & CSIZE) == CS8)
+               ucr2 = UCR2_WS | UCR2_SRST | UCR2_IRTS;
+       else
+               ucr2 = UCR2_SRST | UCR2_IRTS;
+
+       if (termios->c_cflag & CRTSCTS) {
+               if( sport->have_rtscts ) {
+                       ucr2 &= ~UCR2_IRTS;
+                       ucr2 |= UCR2_CTSC;
+               } else {
+                       termios->c_cflag &= ~CRTSCTS;
+               }
+       }
+
+       if (termios->c_cflag & CSTOPB)
+               ucr2 |= UCR2_STPB;
+       if (termios->c_cflag & PARENB) {
+               ucr2 |= UCR2_PREN;
+               if (termios->c_cflag & PARODD)
+                       ucr2 |= UCR2_PROE;
+       }
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16);
+       quot = uart_get_divisor(port, baud);
+
+       spin_lock_irqsave(&sport->port.lock, flags);
+
+       sport->port.read_status_mask = 0;
+       if (termios->c_iflag & INPCK)
+               sport->port.read_status_mask |= (URXD_FRMERR | URXD_PRERR);
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               sport->port.read_status_mask |= URXD_BRK;
+
+       /*
+        * Characters to ignore
+        */
+       sport->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               sport->port.ignore_status_mask |= URXD_PRERR;
+       if (termios->c_iflag & IGNBRK) {
+               sport->port.ignore_status_mask |= URXD_BRK;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       sport->port.ignore_status_mask |= URXD_OVRRUN;
+       }
+
+       del_timer_sync(&sport->timer);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       /*
+        * disable interrupts and drain transmitter
+        */
+       old_ucr1 = readl(sport->port.membase + UCR1);
+       writel(old_ucr1 & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN),
+                       sport->port.membase + UCR1);
+
+       while ( !(readl(sport->port.membase + USR2) & USR2_TXDC))
+               barrier();
+
+       /* then, disable everything */
+       old_txrxen = readl(sport->port.membase + UCR2);
+       writel(old_txrxen & ~( UCR2_TXEN | UCR2_RXEN),
+                       sport->port.membase + UCR2);
+       old_txrxen &= (UCR2_TXEN | UCR2_RXEN);
+
+       if (USE_IRDA(sport)) {
+               /*
+                * use maximum available submodule frequency to
+                * avoid missing short pulses due to low sampling rate
+                */
+               div = 1;
+       } else {
+               div = sport->port.uartclk / (baud * 16);
+               if (div > 7)
+                       div = 7;
+               if (!div)
+                       div = 1;
+       }
+
+       rational_best_approximation(16 * div * baud, sport->port.uartclk,
+               1 << 16, 1 << 16, &num, &denom);
+
+       tdiv64 = sport->port.uartclk;
+       tdiv64 *= num;
+       do_div(tdiv64, denom * 16 * div);
+       tty_termios_encode_baud_rate(termios,
+                               (speed_t)tdiv64, (speed_t)tdiv64);
+
+       num -= 1;
+       denom -= 1;
+
+       ufcr = readl(sport->port.membase + UFCR);
+       ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div);
+       writel(ufcr, sport->port.membase + UFCR);
+
+       writel(num, sport->port.membase + UBIR);
+       writel(denom, sport->port.membase + UBMR);
+
+       if (!cpu_is_mx1())
+               writel(sport->port.uartclk / div / 1000,
+                               sport->port.membase + MX2_ONEMS);
+
+       writel(old_ucr1, sport->port.membase + UCR1);
+
+       /* set the parity, stop bits and data size */
+       writel(ucr2 | old_txrxen, sport->port.membase + UCR2);
+
+       if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
+               imx_enable_ms(&sport->port);
+
+       spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static const char *imx_type(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+
+       return sport->port.type == PORT_IMX ? "IMX" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'.
+ */
+static void imx_release_port(struct uart_port *port)
+{
+       struct platform_device *pdev = to_platform_device(port->dev);
+       struct resource *mmres;
+
+       mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(mmres->start, mmres->end - mmres->start + 1);
+}
+
+/*
+ * Request the memory region(s) being used by 'port'.
+ */
+static int imx_request_port(struct uart_port *port)
+{
+       struct platform_device *pdev = to_platform_device(port->dev);
+       struct resource *mmres;
+       void *ret;
+
+       mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mmres)
+               return -ENODEV;
+
+       ret = request_mem_region(mmres->start, mmres->end - mmres->start + 1,
+                       "imx-uart");
+
+       return  ret ? 0 : -EBUSY;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void imx_config_port(struct uart_port *port, int flags)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+
+       if (flags & UART_CONFIG_TYPE &&
+           imx_request_port(&sport->port) == 0)
+               sport->port.type = PORT_IMX;
+}
+
+/*
+ * Verify the new serial_struct (for TIOCSSERIAL).
+ * The only change we allow are to the flags and type, and
+ * even then only between PORT_IMX and PORT_UNKNOWN
+ */
+static int
+imx_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       int ret = 0;
+
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_IMX)
+               ret = -EINVAL;
+       if (sport->port.irq != ser->irq)
+               ret = -EINVAL;
+       if (ser->io_type != UPIO_MEM)
+               ret = -EINVAL;
+       if (sport->port.uartclk / 16 != ser->baud_base)
+               ret = -EINVAL;
+       if ((void *)sport->port.mapbase != ser->iomem_base)
+               ret = -EINVAL;
+       if (sport->port.iobase != ser->port)
+               ret = -EINVAL;
+       if (ser->hub6 != 0)
+               ret = -EINVAL;
+       return ret;
+}
+
+static struct uart_ops imx_pops = {
+       .tx_empty       = imx_tx_empty,
+       .set_mctrl      = imx_set_mctrl,
+       .get_mctrl      = imx_get_mctrl,
+       .stop_tx        = imx_stop_tx,
+       .start_tx       = imx_start_tx,
+       .stop_rx        = imx_stop_rx,
+       .enable_ms      = imx_enable_ms,
+       .break_ctl      = imx_break_ctl,
+       .startup        = imx_startup,
+       .shutdown       = imx_shutdown,
+       .set_termios    = imx_set_termios,
+       .type           = imx_type,
+       .release_port   = imx_release_port,
+       .request_port   = imx_request_port,
+       .config_port    = imx_config_port,
+       .verify_port    = imx_verify_port,
+};
+
+static struct imx_port *imx_ports[UART_NR];
+
+#ifdef CONFIG_SERIAL_IMX_CONSOLE
+static void imx_console_putchar(struct uart_port *port, int ch)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+
+       while (readl(sport->port.membase + UTS) & UTS_TXFULL)
+               barrier();
+
+       writel(ch, sport->port.membase + URTX0);
+}
+
+/*
+ * Interrupts are disabled on entering
+ */
+static void
+imx_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct imx_port *sport = imx_ports[co->index];
+       unsigned int old_ucr1, old_ucr2, ucr1;
+
+       /*
+        *      First, save UCR1/2 and then disable interrupts
+        */
+       ucr1 = old_ucr1 = readl(sport->port.membase + UCR1);
+       old_ucr2 = readl(sport->port.membase + UCR2);
+
+       if (cpu_is_mx1())
+               ucr1 |= MX1_UCR1_UARTCLKEN;
+       ucr1 |= UCR1_UARTEN;
+       ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN);
+
+       writel(ucr1, sport->port.membase + UCR1);
+
+       writel(old_ucr2 | UCR2_TXEN, sport->port.membase + UCR2);
+
+       uart_console_write(&sport->port, s, count, imx_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore UCR1/2
+        */
+       while (!(readl(sport->port.membase + USR2) & USR2_TXDC));
+
+       writel(old_ucr1, sport->port.membase + UCR1);
+       writel(old_ucr2, sport->port.membase + UCR2);
+}
+
+/*
+ * If the port was already initialised (eg, by a boot loader),
+ * try to determine the current setup.
+ */
+static void __init
+imx_console_get_options(struct imx_port *sport, int *baud,
+                          int *parity, int *bits)
+{
+
+       if (readl(sport->port.membase + UCR1) & UCR1_UARTEN) {
+               /* ok, the port was enabled */
+               unsigned int ucr2, ubir,ubmr, uartclk;
+               unsigned int baud_raw;
+               unsigned int ucfr_rfdiv;
+
+               ucr2 = readl(sport->port.membase + UCR2);
+
+               *parity = 'n';
+               if (ucr2 & UCR2_PREN) {
+                       if (ucr2 & UCR2_PROE)
+                               *parity = 'o';
+                       else
+                               *parity = 'e';
+               }
+
+               if (ucr2 & UCR2_WS)
+                       *bits = 8;
+               else
+                       *bits = 7;
+
+               ubir = readl(sport->port.membase + UBIR) & 0xffff;
+               ubmr = readl(sport->port.membase + UBMR) & 0xffff;
+
+               ucfr_rfdiv = (readl(sport->port.membase + UFCR) & UFCR_RFDIV) >> 7;
+               if (ucfr_rfdiv == 6)
+                       ucfr_rfdiv = 7;
+               else
+                       ucfr_rfdiv = 6 - ucfr_rfdiv;
+
+               uartclk = clk_get_rate(sport->clk);
+               uartclk /= ucfr_rfdiv;
+
+               {       /*
+                        * The next code provides exact computation of
+                        *   baud_raw = round(((uartclk/16) * (ubir + 1)) / (ubmr + 1))
+                        * without need of float support or long long division,
+                        * which would be required to prevent 32bit arithmetic overflow
+                        */
+                       unsigned int mul = ubir + 1;
+                       unsigned int div = 16 * (ubmr + 1);
+                       unsigned int rem = uartclk % div;
+
+                       baud_raw = (uartclk / div) * mul;
+                       baud_raw += (rem * mul + div / 2) / div;
+                       *baud = (baud_raw + 50) / 100 * 100;
+               }
+
+               if(*baud != baud_raw)
+                       printk(KERN_INFO "Serial: Console IMX rounded baud rate from %d to %d\n",
+                               baud_raw, *baud);
+       }
+}
+
+static int __init
+imx_console_setup(struct console *co, char *options)
+{
+       struct imx_port *sport;
+       int baud = 9600;
+       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.
+        */
+       if (co->index == -1 || co->index >= ARRAY_SIZE(imx_ports))
+               co->index = 0;
+       sport = imx_ports[co->index];
+       if(sport == NULL)
+               return -ENODEV;
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               imx_console_get_options(sport, &baud, &parity, &bits);
+
+       imx_setup_ufcr(sport, 0);
+
+       return uart_set_options(&sport->port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver imx_reg;
+static struct console imx_console = {
+       .name           = DEV_NAME,
+       .write          = imx_console_write,
+       .device         = uart_console_device,
+       .setup          = imx_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &imx_reg,
+};
+
+#define IMX_CONSOLE    &imx_console
+#else
+#define IMX_CONSOLE    NULL
+#endif
+
+static struct uart_driver imx_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = DRIVER_NAME,
+       .dev_name       = DEV_NAME,
+       .major          = SERIAL_IMX_MAJOR,
+       .minor          = MINOR_START,
+       .nr             = ARRAY_SIZE(imx_ports),
+       .cons           = IMX_CONSOLE,
+};
+
+static int serial_imx_suspend(struct platform_device *dev, pm_message_t state)
+{
+       struct imx_port *sport = platform_get_drvdata(dev);
+
+       if (sport)
+               uart_suspend_port(&imx_reg, &sport->port);
+
+       return 0;
+}
+
+static int serial_imx_resume(struct platform_device *dev)
+{
+       struct imx_port *sport = platform_get_drvdata(dev);
+
+       if (sport)
+               uart_resume_port(&imx_reg, &sport->port);
+
+       return 0;
+}
+
+static int serial_imx_probe(struct platform_device *pdev)
+{
+       struct imx_port *sport;
+       struct imxuart_platform_data *pdata;
+       void __iomem *base;
+       int ret = 0;
+       struct resource *res;
+
+       sport = kzalloc(sizeof(*sport), GFP_KERNEL);
+       if (!sport)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               ret = -ENODEV;
+               goto free;
+       }
+
+       base = ioremap(res->start, PAGE_SIZE);
+       if (!base) {
+               ret = -ENOMEM;
+               goto free;
+       }
+
+       sport->port.dev = &pdev->dev;
+       sport->port.mapbase = res->start;
+       sport->port.membase = base;
+       sport->port.type = PORT_IMX,
+       sport->port.iotype = UPIO_MEM;
+       sport->port.irq = platform_get_irq(pdev, 0);
+       sport->rxirq = platform_get_irq(pdev, 0);
+       sport->txirq = platform_get_irq(pdev, 1);
+       sport->rtsirq = platform_get_irq(pdev, 2);
+       sport->port.fifosize = 32;
+       sport->port.ops = &imx_pops;
+       sport->port.flags = UPF_BOOT_AUTOCONF;
+       sport->port.line = pdev->id;
+       init_timer(&sport->timer);
+       sport->timer.function = imx_timeout;
+       sport->timer.data     = (unsigned long)sport;
+
+       sport->clk = clk_get(&pdev->dev, "uart");
+       if (IS_ERR(sport->clk)) {
+               ret = PTR_ERR(sport->clk);
+               goto unmap;
+       }
+       clk_enable(sport->clk);
+
+       sport->port.uartclk = clk_get_rate(sport->clk);
+
+       imx_ports[pdev->id] = sport;
+
+       pdata = pdev->dev.platform_data;
+       if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS))
+               sport->have_rtscts = 1;
+
+#ifdef CONFIG_IRDA
+       if (pdata && (pdata->flags & IMXUART_IRDA))
+               sport->use_irda = 1;
+#endif
+
+       if (pdata && pdata->init) {
+               ret = pdata->init(pdev);
+               if (ret)
+                       goto clkput;
+       }
+
+       ret = uart_add_one_port(&imx_reg, &sport->port);
+       if (ret)
+               goto deinit;
+       platform_set_drvdata(pdev, &sport->port);
+
+       return 0;
+deinit:
+       if (pdata && pdata->exit)
+               pdata->exit(pdev);
+clkput:
+       clk_put(sport->clk);
+       clk_disable(sport->clk);
+unmap:
+       iounmap(sport->port.membase);
+free:
+       kfree(sport);
+
+       return ret;
+}
+
+static int serial_imx_remove(struct platform_device *pdev)
+{
+       struct imxuart_platform_data *pdata;
+       struct imx_port *sport = platform_get_drvdata(pdev);
+
+       pdata = pdev->dev.platform_data;
+
+       platform_set_drvdata(pdev, NULL);
+
+       if (sport) {
+               uart_remove_one_port(&imx_reg, &sport->port);
+               clk_put(sport->clk);
+       }
+
+       clk_disable(sport->clk);
+
+       if (pdata && pdata->exit)
+               pdata->exit(pdev);
+
+       iounmap(sport->port.membase);
+       kfree(sport);
+
+       return 0;
+}
+
+static struct platform_driver serial_imx_driver = {
+       .probe          = serial_imx_probe,
+       .remove         = serial_imx_remove,
+
+       .suspend        = serial_imx_suspend,
+       .resume         = serial_imx_resume,
+       .driver         = {
+               .name   = "imx-uart",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init imx_serial_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "Serial: IMX driver\n");
+
+       ret = uart_register_driver(&imx_reg);
+       if (ret)
+               return ret;
+
+       ret = platform_driver_register(&serial_imx_driver);
+       if (ret != 0)
+               uart_unregister_driver(&imx_reg);
+
+       return 0;
+}
+
+static void __exit imx_serial_exit(void)
+{
+       platform_driver_unregister(&serial_imx_driver);
+       uart_unregister_driver(&imx_reg);
+}
+
+module_init(imx_serial_init);
+module_exit(imx_serial_exit);
+
+MODULE_AUTHOR("Sascha Hauer");
+MODULE_DESCRIPTION("IMX generic serial port driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx-uart");
diff --git a/drivers/tty/serial/ioc3_serial.c b/drivers/tty/serial/ioc3_serial.c
new file mode 100644 (file)
index 0000000..ee43efc
--- /dev/null
@@ -0,0 +1,2199 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2005 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+/*
+ * This file contains a module version of the ioc3 serial driver. This
+ * includes all the support functions needed (support functions, etc.)
+ * and the serial driver itself.
+ */
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/circ_buf.h>
+#include <linux/serial_reg.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/serial_core.h>
+#include <linux/ioc3.h>
+#include <linux/slab.h>
+
+/*
+ * Interesting things about the ioc3
+ */
+
+#define LOGICAL_PORTS          2       /* rs232(0) and rs422(1) */
+#define PORTS_PER_CARD         2
+#define LOGICAL_PORTS_PER_CARD (PORTS_PER_CARD * LOGICAL_PORTS)
+#define MAX_CARDS              8
+#define MAX_LOGICAL_PORTS      (LOGICAL_PORTS_PER_CARD * MAX_CARDS)
+
+/* determine given the sio_ir what port it applies to */
+#define GET_PORT_FROM_SIO_IR(_x)       (_x & SIO_IR_SA) ? 0 : 1
+
+
+/*
+ * we have 2 logical ports (rs232, rs422) for each physical port
+ * evens are rs232, odds are rs422
+ */
+#define GET_PHYSICAL_PORT(_x)  ((_x) >> 1)
+#define GET_LOGICAL_PORT(_x)   ((_x) & 1)
+#define IS_PHYSICAL_PORT(_x)   !((_x) & 1)
+#define IS_RS232(_x)           !((_x) & 1)
+
+static unsigned int Num_of_ioc3_cards;
+static unsigned int Submodule_slot;
+
+/* defining this will get you LOTS of great debug info */
+//#define DEBUG_INTERRUPTS
+#define DPRINT_CONFIG(_x...)   ;
+//#define DPRINT_CONFIG(_x...)  printk _x
+#define NOT_PROGRESS() ;
+//#define NOT_PROGRESS()       printk("%s : fails %d\n", __func__, __LINE__)
+
+/* number of characters we want to transmit to the lower level at a time */
+#define MAX_CHARS              256
+#define FIFO_SIZE              (MAX_CHARS-1)   /* it's a uchar */
+
+/* Device name we're using */
+#define DEVICE_NAME            "ttySIOC"
+#define DEVICE_MAJOR           204
+#define DEVICE_MINOR           116
+
+/* flags for next_char_state */
+#define NCS_BREAK              0x1
+#define NCS_PARITY             0x2
+#define NCS_FRAMING            0x4
+#define NCS_OVERRUN            0x8
+
+/* cause we need SOME parameters ... */
+#define MIN_BAUD_SUPPORTED     1200
+#define MAX_BAUD_SUPPORTED     115200
+
+/* protocol types supported */
+#define PROTO_RS232            0
+#define PROTO_RS422            1
+
+/* Notification types */
+#define N_DATA_READY           0x01
+#define N_OUTPUT_LOWAT         0x02
+#define N_BREAK                        0x04
+#define N_PARITY_ERROR         0x08
+#define N_FRAMING_ERROR                0x10
+#define N_OVERRUN_ERROR                0x20
+#define N_DDCD                 0x40
+#define N_DCTS                 0x80
+
+#define N_ALL_INPUT            (N_DATA_READY | N_BREAK                    \
+                                       | N_PARITY_ERROR | N_FRAMING_ERROR \
+                                       | N_OVERRUN_ERROR | N_DDCD | N_DCTS)
+
+#define N_ALL_OUTPUT           N_OUTPUT_LOWAT
+
+#define N_ALL_ERRORS           (N_PARITY_ERROR | N_FRAMING_ERROR \
+                                               | N_OVERRUN_ERROR)
+
+#define N_ALL                  (N_DATA_READY | N_OUTPUT_LOWAT | N_BREAK    \
+                                       | N_PARITY_ERROR | N_FRAMING_ERROR  \
+                                       | N_OVERRUN_ERROR | N_DDCD | N_DCTS)
+
+#define SER_CLK_SPEED(prediv)  ((22000000 << 1) / prediv)
+#define SER_DIVISOR(x, clk)    (((clk) + (x) * 8) / ((x) * 16))
+#define DIVISOR_TO_BAUD(div, clk) ((clk) / 16 / (div))
+
+/* Some masks */
+#define LCR_MASK_BITS_CHAR     (UART_LCR_WLEN5 | UART_LCR_WLEN6 \
+                                       | UART_LCR_WLEN7 | UART_LCR_WLEN8)
+#define LCR_MASK_STOP_BITS     (UART_LCR_STOP)
+
+#define PENDING(_a, _p)                (readl(&(_p)->vma->sio_ir) & (_a)->ic_enable)
+
+#define RING_BUF_SIZE          4096
+#define BUF_SIZE_BIT           SBBR_L_SIZE
+#define PROD_CONS_MASK         PROD_CONS_PTR_4K
+
+#define TOTAL_RING_BUF_SIZE    (RING_BUF_SIZE * 4)
+
+/* driver specific - one per card */
+struct ioc3_card {
+       struct {
+               /* uart ports are allocated here */
+               struct uart_port icp_uart_port[LOGICAL_PORTS];
+               /* the ioc3_port used for this port */
+               struct ioc3_port *icp_port;
+       } ic_port[PORTS_PER_CARD];
+       /* currently enabled interrupts */
+       uint32_t ic_enable;
+};
+
+/* Local port info for each IOC3 serial port */
+struct ioc3_port {
+       /* handy reference material */
+       struct uart_port *ip_port;
+       struct ioc3_card *ip_card;
+       struct ioc3_driver_data *ip_idd;
+       struct ioc3_submodule *ip_is;
+
+       /* pci mem addresses for this port */
+       struct ioc3_serialregs __iomem *ip_serial_regs;
+       struct ioc3_uartregs __iomem *ip_uart_regs;
+
+       /* Ring buffer page for this port */
+       dma_addr_t ip_dma_ringbuf;
+       /* vaddr of ring buffer */
+       struct ring_buffer *ip_cpu_ringbuf;
+
+       /* Rings for this port */
+       struct ring *ip_inring;
+       struct ring *ip_outring;
+
+       /* Hook to port specific values */
+       struct port_hooks *ip_hooks;
+
+       spinlock_t ip_lock;
+
+       /* Various rx/tx parameters */
+       int ip_baud;
+       int ip_tx_lowat;
+       int ip_rx_timeout;
+
+       /* Copy of notification bits */
+       int ip_notify;
+
+       /* Shadow copies of various registers so we don't need to PIO
+        * read them constantly
+        */
+       uint32_t ip_sscr;
+       uint32_t ip_tx_prod;
+       uint32_t ip_rx_cons;
+       unsigned char ip_flags;
+};
+
+/* tx low water mark.  We need to notify the driver whenever tx is getting
+ * close to empty so it can refill the tx buffer and keep things going.
+ * Let's assume that if we interrupt 1 ms before the tx goes idle, we'll
+ * have no trouble getting in more chars in time (I certainly hope so).
+ */
+#define TX_LOWAT_LATENCY      1000
+#define TX_LOWAT_HZ          (1000000 / TX_LOWAT_LATENCY)
+#define TX_LOWAT_CHARS(baud) (baud / 10 / TX_LOWAT_HZ)
+
+/* Flags per port */
+#define INPUT_HIGH             0x01
+       /* used to signify that we have turned off the rx_high
+        * temporarily - we need to drain the fifo and don't
+        * want to get blasted with interrupts.
+        */
+#define DCD_ON                 0x02
+       /* DCD state is on */
+#define LOWAT_WRITTEN          0x04
+#define READ_ABORTED           0x08
+       /* the read was aborted - used to avaoid infinate looping
+        * in the interrupt handler
+        */
+#define INPUT_ENABLE           0x10
+
+/* Since each port has different register offsets and bitmasks
+ * for everything, we'll store those that we need in tables so we
+ * don't have to be constantly checking the port we are dealing with.
+ */
+struct port_hooks {
+       uint32_t intr_delta_dcd;
+       uint32_t intr_delta_cts;
+       uint32_t intr_tx_mt;
+       uint32_t intr_rx_timer;
+       uint32_t intr_rx_high;
+       uint32_t intr_tx_explicit;
+       uint32_t intr_clear;
+       uint32_t intr_all;
+       char rs422_select_pin;
+};
+
+static struct port_hooks hooks_array[PORTS_PER_CARD] = {
+       /* values for port A */
+       {
+       .intr_delta_dcd = SIO_IR_SA_DELTA_DCD,
+       .intr_delta_cts = SIO_IR_SA_DELTA_CTS,
+       .intr_tx_mt = SIO_IR_SA_TX_MT,
+       .intr_rx_timer = SIO_IR_SA_RX_TIMER,
+       .intr_rx_high = SIO_IR_SA_RX_HIGH,
+       .intr_tx_explicit = SIO_IR_SA_TX_EXPLICIT,
+       .intr_clear = (SIO_IR_SA_TX_MT | SIO_IR_SA_RX_FULL
+                               | SIO_IR_SA_RX_HIGH
+                               | SIO_IR_SA_RX_TIMER
+                               | SIO_IR_SA_DELTA_DCD
+                               | SIO_IR_SA_DELTA_CTS
+                               | SIO_IR_SA_INT
+                               | SIO_IR_SA_TX_EXPLICIT
+                               | SIO_IR_SA_MEMERR),
+       .intr_all =  SIO_IR_SA,
+       .rs422_select_pin = GPPR_UARTA_MODESEL_PIN,
+        },
+
+       /* values for port B */
+       {
+       .intr_delta_dcd = SIO_IR_SB_DELTA_DCD,
+       .intr_delta_cts = SIO_IR_SB_DELTA_CTS,
+       .intr_tx_mt = SIO_IR_SB_TX_MT,
+       .intr_rx_timer = SIO_IR_SB_RX_TIMER,
+       .intr_rx_high = SIO_IR_SB_RX_HIGH,
+       .intr_tx_explicit = SIO_IR_SB_TX_EXPLICIT,
+       .intr_clear = (SIO_IR_SB_TX_MT | SIO_IR_SB_RX_FULL
+                               | SIO_IR_SB_RX_HIGH
+                               | SIO_IR_SB_RX_TIMER
+                               | SIO_IR_SB_DELTA_DCD
+                               | SIO_IR_SB_DELTA_CTS
+                               | SIO_IR_SB_INT
+                               | SIO_IR_SB_TX_EXPLICIT
+                               | SIO_IR_SB_MEMERR),
+       .intr_all = SIO_IR_SB,
+       .rs422_select_pin = GPPR_UARTB_MODESEL_PIN,
+        }
+};
+
+struct ring_entry {
+       union {
+               struct {
+                       uint32_t alldata;
+                       uint32_t allsc;
+               } all;
+               struct {
+                       char data[4];   /* data bytes */
+                       char sc[4];     /* status/control */
+               } s;
+       } u;
+};
+
+/* Test the valid bits in any of the 4 sc chars using "allsc" member */
+#define RING_ANY_VALID \
+       ((uint32_t)(RXSB_MODEM_VALID | RXSB_DATA_VALID) * 0x01010101)
+
+#define ring_sc                u.s.sc
+#define ring_data      u.s.data
+#define ring_allsc     u.all.allsc
+
+/* Number of entries per ring buffer. */
+#define ENTRIES_PER_RING (RING_BUF_SIZE / (int) sizeof(struct ring_entry))
+
+/* An individual ring */
+struct ring {
+       struct ring_entry entries[ENTRIES_PER_RING];
+};
+
+/* The whole enchilada */
+struct ring_buffer {
+       struct ring TX_A;
+       struct ring RX_A;
+       struct ring TX_B;
+       struct ring RX_B;
+};
+
+/* Get a ring from a port struct */
+#define RING(_p, _wh)  &(((struct ring_buffer *)((_p)->ip_cpu_ringbuf))->_wh)
+
+/* for Infinite loop detection  */
+#define MAXITER                10000000
+
+
+/**
+ * set_baud - Baud rate setting code
+ * @port: port to set
+ * @baud: baud rate to use
+ */
+static int set_baud(struct ioc3_port *port, int baud)
+{
+       int divisor;
+       int actual_baud;
+       int diff;
+       int lcr, prediv;
+       struct ioc3_uartregs __iomem *uart;
+
+       for (prediv = 6; prediv < 64; prediv++) {
+               divisor = SER_DIVISOR(baud, SER_CLK_SPEED(prediv));
+               if (!divisor)
+                       continue;       /* invalid divisor */
+               actual_baud = DIVISOR_TO_BAUD(divisor, SER_CLK_SPEED(prediv));
+
+               diff = actual_baud - baud;
+               if (diff < 0)
+                       diff = -diff;
+
+               /* if we're within 1% we've found a match */
+               if (diff * 100 <= actual_baud)
+                       break;
+       }
+
+       /* if the above loop completed, we didn't match
+        * the baud rate.  give up.
+        */
+       if (prediv == 64) {
+               NOT_PROGRESS();
+               return 1;
+       }
+
+       uart = port->ip_uart_regs;
+       lcr = readb(&uart->iu_lcr);
+
+       writeb(lcr | UART_LCR_DLAB, &uart->iu_lcr);
+       writeb((unsigned char)divisor, &uart->iu_dll);
+       writeb((unsigned char)(divisor >> 8), &uart->iu_dlm);
+       writeb((unsigned char)prediv, &uart->iu_scr);
+       writeb((unsigned char)lcr, &uart->iu_lcr);
+
+       return 0;
+}
+
+/**
+ * get_ioc3_port - given a uart port, return the control structure
+ * @the_port: uart port to find
+ */
+static struct ioc3_port *get_ioc3_port(struct uart_port *the_port)
+{
+       struct ioc3_driver_data *idd = dev_get_drvdata(the_port->dev);
+       struct ioc3_card *card_ptr = idd->data[Submodule_slot];
+       int ii, jj;
+
+       if (!card_ptr) {
+               NOT_PROGRESS();
+               return NULL;
+       }
+       for (ii = 0; ii < PORTS_PER_CARD; ii++) {
+               for (jj = 0; jj < LOGICAL_PORTS; jj++) {
+                       if (the_port == &card_ptr->ic_port[ii].icp_uart_port[jj])
+                               return card_ptr->ic_port[ii].icp_port;
+               }
+       }
+       NOT_PROGRESS();
+       return NULL;
+}
+
+/**
+ * port_init - Initialize the sio and ioc3 hardware for a given port
+ *                     called per port from attach...
+ * @port: port to initialize
+ */
+static int inline port_init(struct ioc3_port *port)
+{
+       uint32_t sio_cr;
+       struct port_hooks *hooks = port->ip_hooks;
+       struct ioc3_uartregs __iomem *uart;
+       int reset_loop_counter = 0xfffff;
+       struct ioc3_driver_data *idd = port->ip_idd;
+
+       /* Idle the IOC3 serial interface */
+       writel(SSCR_RESET, &port->ip_serial_regs->sscr);
+
+       /* Wait until any pending bus activity for this port has ceased */
+       do {
+               sio_cr = readl(&idd->vma->sio_cr);
+               if (reset_loop_counter-- <= 0) {
+                       printk(KERN_WARNING
+                              "IOC3 unable to come out of reset"
+                               " scr 0x%x\n", sio_cr);
+                       return -1;
+               }
+       } while (!(sio_cr & SIO_CR_ARB_DIAG_IDLE) &&
+              (((sio_cr &= SIO_CR_ARB_DIAG) == SIO_CR_ARB_DIAG_TXA)
+               || sio_cr == SIO_CR_ARB_DIAG_TXB
+               || sio_cr == SIO_CR_ARB_DIAG_RXA
+               || sio_cr == SIO_CR_ARB_DIAG_RXB));
+
+       /* Finish reset sequence */
+       writel(0, &port->ip_serial_regs->sscr);
+
+       /* Once RESET is done, reload cached tx_prod and rx_cons values
+        * and set rings to empty by making prod == cons
+        */
+       port->ip_tx_prod = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
+       writel(port->ip_tx_prod, &port->ip_serial_regs->stpir);
+       port->ip_rx_cons = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
+       writel(port->ip_rx_cons | SRCIR_ARM, &port->ip_serial_regs->srcir);
+
+       /* Disable interrupts for this 16550 */
+       uart = port->ip_uart_regs;
+       writeb(0, &uart->iu_lcr);
+       writeb(0, &uart->iu_ier);
+
+       /* Set the default baud */
+       set_baud(port, port->ip_baud);
+
+       /* Set line control to 8 bits no parity */
+       writeb(UART_LCR_WLEN8 | 0, &uart->iu_lcr);
+       /* UART_LCR_STOP == 1 stop */
+
+       /* Enable the FIFOs */
+       writeb(UART_FCR_ENABLE_FIFO, &uart->iu_fcr);
+       /* then reset 16550 FIFOs */
+       writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
+              &uart->iu_fcr);
+
+       /* Clear modem control register */
+       writeb(0, &uart->iu_mcr);
+
+       /* Clear deltas in modem status register */
+       writel(0, &port->ip_serial_regs->shadow);
+
+       /* Only do this once per port pair */
+       if (port->ip_hooks == &hooks_array[0]) {
+               unsigned long ring_pci_addr;
+               uint32_t __iomem *sbbr_l, *sbbr_h;
+
+               sbbr_l = &idd->vma->sbbr_l;
+               sbbr_h = &idd->vma->sbbr_h;
+               ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf;
+               DPRINT_CONFIG(("%s: ring_pci_addr 0x%p\n",
+                              __func__, (void *)ring_pci_addr));
+
+               writel((unsigned int)((uint64_t) ring_pci_addr >> 32), sbbr_h);
+               writel((unsigned int)ring_pci_addr | BUF_SIZE_BIT, sbbr_l);
+       }
+
+       /* Set the receive timeout value to 10 msec */
+       writel(SRTR_HZ / 100, &port->ip_serial_regs->srtr);
+
+       /* Set rx threshold, enable DMA */
+       /* Set high water mark at 3/4 of full ring */
+       port->ip_sscr = (ENTRIES_PER_RING * 3 / 4);
+
+       /* uart experiences pauses at high baud rate reducing actual
+        * throughput by 10% or so unless we enable high speed polling
+        * XXX when this hardware bug is resolved we should revert to
+        * normal polling speed
+        */
+       port->ip_sscr |= SSCR_HIGH_SPD;
+
+       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+
+       /* Disable and clear all serial related interrupt bits */
+       port->ip_card->ic_enable &= ~hooks->intr_clear;
+       ioc3_disable(port->ip_is, idd, hooks->intr_clear);
+       ioc3_ack(port->ip_is, idd, hooks->intr_clear);
+       return 0;
+}
+
+/**
+ * enable_intrs - enable interrupts
+ * @port: port to enable
+ * @mask: mask to use
+ */
+static void enable_intrs(struct ioc3_port *port, uint32_t mask)
+{
+       if ((port->ip_card->ic_enable & mask) != mask) {
+               port->ip_card->ic_enable |= mask;
+               ioc3_enable(port->ip_is, port->ip_idd, mask);
+       }
+}
+
+/**
+ * local_open - local open a port
+ * @port: port to open
+ */
+static inline int local_open(struct ioc3_port *port)
+{
+       int spiniter = 0;
+
+       port->ip_flags = INPUT_ENABLE;
+
+       /* Pause the DMA interface if necessary */
+       if (port->ip_sscr & SSCR_DMA_EN) {
+               writel(port->ip_sscr | SSCR_DMA_PAUSE,
+                      &port->ip_serial_regs->sscr);
+               while ((readl(&port->ip_serial_regs->sscr)
+                       & SSCR_PAUSE_STATE) == 0) {
+                       spiniter++;
+                       if (spiniter > MAXITER) {
+                               NOT_PROGRESS();
+                               return -1;
+                       }
+               }
+       }
+
+       /* Reset the input fifo.  If the uart received chars while the port
+        * was closed and DMA is not enabled, the uart may have a bunch of
+        * chars hanging around in its rx fifo which will not be discarded
+        * by rclr in the upper layer. We must get rid of them here.
+        */
+       writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR,
+              &port->ip_uart_regs->iu_fcr);
+
+       writeb(UART_LCR_WLEN8, &port->ip_uart_regs->iu_lcr);
+       /* UART_LCR_STOP == 1 stop */
+
+       /* Re-enable DMA, set default threshold to intr whenever there is
+        * data available.
+        */
+       port->ip_sscr &= ~SSCR_RX_THRESHOLD;
+       port->ip_sscr |= 1;     /* default threshold */
+
+       /* Plug in the new sscr.  This implicitly clears the DMA_PAUSE
+        * flag if it was set above
+        */
+       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+       port->ip_tx_lowat = 1;
+       return 0;
+}
+
+/**
+ * set_rx_timeout - Set rx timeout and threshold values.
+ * @port: port to use
+ * @timeout: timeout value in ticks
+ */
+static inline int set_rx_timeout(struct ioc3_port *port, int timeout)
+{
+       int threshold;
+
+       port->ip_rx_timeout = timeout;
+
+       /* Timeout is in ticks.  Let's figure out how many chars we
+        * can receive at the current baud rate in that interval
+        * and set the rx threshold to that amount.  There are 4 chars
+        * per ring entry, so we'll divide the number of chars that will
+        * arrive in timeout by 4.
+        * So .... timeout * baud / 10 / HZ / 4, with HZ = 100.
+        */
+       threshold = timeout * port->ip_baud / 4000;
+       if (threshold == 0)
+               threshold = 1;  /* otherwise we'll intr all the time! */
+
+       if ((unsigned)threshold > (unsigned)SSCR_RX_THRESHOLD)
+               return 1;
+
+       port->ip_sscr &= ~SSCR_RX_THRESHOLD;
+       port->ip_sscr |= threshold;
+       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+
+       /* Now set the rx timeout to the given value
+        * again timeout * SRTR_HZ / HZ
+        */
+       timeout = timeout * SRTR_HZ / 100;
+       if (timeout > SRTR_CNT)
+               timeout = SRTR_CNT;
+       writel(timeout, &port->ip_serial_regs->srtr);
+       return 0;
+}
+
+/**
+ * config_port - config the hardware
+ * @port: port to config
+ * @baud: baud rate for the port
+ * @byte_size: data size
+ * @stop_bits: number of stop bits
+ * @parenb: parity enable ?
+ * @parodd: odd parity ?
+ */
+static inline int
+config_port(struct ioc3_port *port,
+           int baud, int byte_size, int stop_bits, int parenb, int parodd)
+{
+       char lcr, sizebits;
+       int spiniter = 0;
+
+       DPRINT_CONFIG(("%s: line %d baud %d byte_size %d stop %d parenb %d "
+                       "parodd %d\n",
+                      __func__, ((struct uart_port *)port->ip_port)->line,
+                       baud, byte_size, stop_bits, parenb, parodd));
+
+       if (set_baud(port, baud))
+               return 1;
+
+       switch (byte_size) {
+       case 5:
+               sizebits = UART_LCR_WLEN5;
+               break;
+       case 6:
+               sizebits = UART_LCR_WLEN6;
+               break;
+       case 7:
+               sizebits = UART_LCR_WLEN7;
+               break;
+       case 8:
+               sizebits = UART_LCR_WLEN8;
+               break;
+       default:
+               return 1;
+       }
+
+       /* Pause the DMA interface if necessary */
+       if (port->ip_sscr & SSCR_DMA_EN) {
+               writel(port->ip_sscr | SSCR_DMA_PAUSE,
+                      &port->ip_serial_regs->sscr);
+               while ((readl(&port->ip_serial_regs->sscr)
+                       & SSCR_PAUSE_STATE) == 0) {
+                       spiniter++;
+                       if (spiniter > MAXITER)
+                               return -1;
+               }
+       }
+
+       /* Clear relevant fields in lcr */
+       lcr = readb(&port->ip_uart_regs->iu_lcr);
+       lcr &= ~(LCR_MASK_BITS_CHAR | UART_LCR_EPAR |
+                UART_LCR_PARITY | LCR_MASK_STOP_BITS);
+
+       /* Set byte size in lcr */
+       lcr |= sizebits;
+
+       /* Set parity */
+       if (parenb) {
+               lcr |= UART_LCR_PARITY;
+               if (!parodd)
+                       lcr |= UART_LCR_EPAR;
+       }
+
+       /* Set stop bits */
+       if (stop_bits)
+               lcr |= UART_LCR_STOP /* 2 stop bits */ ;
+
+       writeb(lcr, &port->ip_uart_regs->iu_lcr);
+
+       /* Re-enable the DMA interface if necessary */
+       if (port->ip_sscr & SSCR_DMA_EN) {
+               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+       }
+       port->ip_baud = baud;
+
+       /* When we get within this number of ring entries of filling the
+        * entire ring on tx, place an EXPLICIT intr to generate a lowat
+        * notification when output has drained.
+        */
+       port->ip_tx_lowat = (TX_LOWAT_CHARS(baud) + 3) / 4;
+       if (port->ip_tx_lowat == 0)
+               port->ip_tx_lowat = 1;
+
+       set_rx_timeout(port, 2);
+       return 0;
+}
+
+/**
+ * do_write - Write bytes to the port.  Returns the number of bytes
+ *                     actually written. Called from transmit_chars
+ * @port: port to use
+ * @buf: the stuff to write
+ * @len: how many bytes in 'buf'
+ */
+static inline int do_write(struct ioc3_port *port, char *buf, int len)
+{
+       int prod_ptr, cons_ptr, total = 0;
+       struct ring *outring;
+       struct ring_entry *entry;
+       struct port_hooks *hooks = port->ip_hooks;
+
+       BUG_ON(!(len >= 0));
+
+       prod_ptr = port->ip_tx_prod;
+       cons_ptr = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
+       outring = port->ip_outring;
+
+       /* Maintain a 1-entry red-zone.  The ring buffer is full when
+        * (cons - prod) % ring_size is 1.  Rather than do this subtraction
+        * in the body of the loop, I'll do it now.
+        */
+       cons_ptr = (cons_ptr - (int)sizeof(struct ring_entry)) & PROD_CONS_MASK;
+
+       /* Stuff the bytes into the output */
+       while ((prod_ptr != cons_ptr) && (len > 0)) {
+               int xx;
+
+               /* Get 4 bytes (one ring entry) at a time */
+               entry = (struct ring_entry *)((caddr_t) outring + prod_ptr);
+
+               /* Invalidate all entries */
+               entry->ring_allsc = 0;
+
+               /* Copy in some bytes */
+               for (xx = 0; (xx < 4) && (len > 0); xx++) {
+                       entry->ring_data[xx] = *buf++;
+                       entry->ring_sc[xx] = TXCB_VALID;
+                       len--;
+                       total++;
+               }
+
+               /* If we are within some small threshold of filling up the
+                * entire ring buffer, we must place an EXPLICIT intr here
+                * to generate a lowat interrupt in case we subsequently
+                * really do fill up the ring and the caller goes to sleep.
+                * No need to place more than one though.
+                */
+               if (!(port->ip_flags & LOWAT_WRITTEN) &&
+                   ((cons_ptr - prod_ptr) & PROD_CONS_MASK)
+                   <= port->ip_tx_lowat * (int)sizeof(struct ring_entry)) {
+                       port->ip_flags |= LOWAT_WRITTEN;
+                       entry->ring_sc[0] |= TXCB_INT_WHEN_DONE;
+               }
+
+               /* Go on to next entry */
+               prod_ptr += sizeof(struct ring_entry);
+               prod_ptr &= PROD_CONS_MASK;
+       }
+
+       /* If we sent something, start DMA if necessary */
+       if (total > 0 && !(port->ip_sscr & SSCR_DMA_EN)) {
+               port->ip_sscr |= SSCR_DMA_EN;
+               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+       }
+
+       /* Store the new producer pointer.  If tx is disabled, we stuff the
+        * data into the ring buffer, but we don't actually start tx.
+        */
+       if (!uart_tx_stopped(port->ip_port)) {
+               writel(prod_ptr, &port->ip_serial_regs->stpir);
+
+               /* If we are now transmitting, enable tx_mt interrupt so we
+                * can disable DMA if necessary when the tx finishes.
+                */
+               if (total > 0)
+                       enable_intrs(port, hooks->intr_tx_mt);
+       }
+       port->ip_tx_prod = prod_ptr;
+
+       return total;
+}
+
+/**
+ * disable_intrs - disable interrupts
+ * @port: port to enable
+ * @mask: mask to use
+ */
+static inline void disable_intrs(struct ioc3_port *port, uint32_t mask)
+{
+       if (port->ip_card->ic_enable & mask) {
+               ioc3_disable(port->ip_is, port->ip_idd, mask);
+               port->ip_card->ic_enable &= ~mask;
+       }
+}
+
+/**
+ * set_notification - Modify event notification
+ * @port: port to use
+ * @mask: events mask
+ * @set_on: set ?
+ */
+static int set_notification(struct ioc3_port *port, int mask, int set_on)
+{
+       struct port_hooks *hooks = port->ip_hooks;
+       uint32_t intrbits, sscrbits;
+
+       BUG_ON(!mask);
+
+       intrbits = sscrbits = 0;
+
+       if (mask & N_DATA_READY)
+               intrbits |= (hooks->intr_rx_timer | hooks->intr_rx_high);
+       if (mask & N_OUTPUT_LOWAT)
+               intrbits |= hooks->intr_tx_explicit;
+       if (mask & N_DDCD) {
+               intrbits |= hooks->intr_delta_dcd;
+               sscrbits |= SSCR_RX_RING_DCD;
+       }
+       if (mask & N_DCTS)
+               intrbits |= hooks->intr_delta_cts;
+
+       if (set_on) {
+               enable_intrs(port, intrbits);
+               port->ip_notify |= mask;
+               port->ip_sscr |= sscrbits;
+       } else {
+               disable_intrs(port, intrbits);
+               port->ip_notify &= ~mask;
+               port->ip_sscr &= ~sscrbits;
+       }
+
+       /* We require DMA if either DATA_READY or DDCD notification is
+        * currently requested. If neither of these is requested and
+        * there is currently no tx in progress, DMA may be disabled.
+        */
+       if (port->ip_notify & (N_DATA_READY | N_DDCD))
+               port->ip_sscr |= SSCR_DMA_EN;
+       else if (!(port->ip_card->ic_enable & hooks->intr_tx_mt))
+               port->ip_sscr &= ~SSCR_DMA_EN;
+
+       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+       return 0;
+}
+
+/**
+ * set_mcr - set the master control reg
+ * @the_port: port to use
+ * @mask1: mcr mask
+ * @mask2: shadow mask
+ */
+static inline int set_mcr(struct uart_port *the_port,
+                         int mask1, int mask2)
+{
+       struct ioc3_port *port = get_ioc3_port(the_port);
+       uint32_t shadow;
+       int spiniter = 0;
+       char mcr;
+
+       if (!port)
+               return -1;
+
+       /* Pause the DMA interface if necessary */
+       if (port->ip_sscr & SSCR_DMA_EN) {
+               writel(port->ip_sscr | SSCR_DMA_PAUSE,
+                      &port->ip_serial_regs->sscr);
+               while ((readl(&port->ip_serial_regs->sscr)
+                       & SSCR_PAUSE_STATE) == 0) {
+                       spiniter++;
+                       if (spiniter > MAXITER)
+                               return -1;
+               }
+       }
+       shadow = readl(&port->ip_serial_regs->shadow);
+       mcr = (shadow & 0xff000000) >> 24;
+
+       /* Set new value */
+       mcr |= mask1;
+       shadow |= mask2;
+       writeb(mcr, &port->ip_uart_regs->iu_mcr);
+       writel(shadow, &port->ip_serial_regs->shadow);
+
+       /* Re-enable the DMA interface if necessary */
+       if (port->ip_sscr & SSCR_DMA_EN) {
+               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+       }
+       return 0;
+}
+
+/**
+ * ioc3_set_proto - set the protocol for the port
+ * @port: port to use
+ * @proto: protocol to use
+ */
+static int ioc3_set_proto(struct ioc3_port *port, int proto)
+{
+       struct port_hooks *hooks = port->ip_hooks;
+
+       switch (proto) {
+       default:
+       case PROTO_RS232:
+               /* Clear the appropriate GIO pin */
+               DPRINT_CONFIG(("%s: rs232\n", __func__));
+               writel(0, (&port->ip_idd->vma->gppr[0]
+                                       + hooks->rs422_select_pin));
+               break;
+
+       case PROTO_RS422:
+               /* Set the appropriate GIO pin */
+               DPRINT_CONFIG(("%s: rs422\n", __func__));
+               writel(1, (&port->ip_idd->vma->gppr[0]
+                                       + hooks->rs422_select_pin));
+               break;
+       }
+       return 0;
+}
+
+/**
+ * transmit_chars - upper level write, called with the_port->lock
+ * @the_port: port to write
+ */
+static void transmit_chars(struct uart_port *the_port)
+{
+       int xmit_count, tail, head;
+       int result;
+       char *start;
+       struct tty_struct *tty;
+       struct ioc3_port *port = get_ioc3_port(the_port);
+       struct uart_state *state;
+
+       if (!the_port)
+               return;
+       if (!port)
+               return;
+
+       state = the_port->state;
+       tty = state->port.tty;
+
+       if (uart_circ_empty(&state->xmit) || uart_tx_stopped(the_port)) {
+               /* Nothing to do or hw stopped */
+               set_notification(port, N_ALL_OUTPUT, 0);
+               return;
+       }
+
+       head = state->xmit.head;
+       tail = state->xmit.tail;
+       start = (char *)&state->xmit.buf[tail];
+
+       /* write out all the data or until the end of the buffer */
+       xmit_count = (head < tail) ? (UART_XMIT_SIZE - tail) : (head - tail);
+       if (xmit_count > 0) {
+               result = do_write(port, start, xmit_count);
+               if (result > 0) {
+                       /* booking */
+                       xmit_count -= result;
+                       the_port->icount.tx += result;
+                       /* advance the pointers */
+                       tail += result;
+                       tail &= UART_XMIT_SIZE - 1;
+                       state->xmit.tail = tail;
+                       start = (char *)&state->xmit.buf[tail];
+               }
+       }
+       if (uart_circ_chars_pending(&state->xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(the_port);
+
+       if (uart_circ_empty(&state->xmit)) {
+               set_notification(port, N_OUTPUT_LOWAT, 0);
+       } else {
+               set_notification(port, N_OUTPUT_LOWAT, 1);
+       }
+}
+
+/**
+ * ioc3_change_speed - change the speed of the port
+ * @the_port: port to change
+ * @new_termios: new termios settings
+ * @old_termios: old termios settings
+ */
+static void
+ioc3_change_speed(struct uart_port *the_port,
+                 struct ktermios *new_termios, struct ktermios *old_termios)
+{
+       struct ioc3_port *port = get_ioc3_port(the_port);
+       unsigned int cflag, iflag;
+       int baud;
+       int new_parity = 0, new_parity_enable = 0, new_stop = 0, new_data = 8;
+       struct uart_state *state = the_port->state;
+
+       cflag = new_termios->c_cflag;
+       iflag = new_termios->c_iflag;
+
+       switch (cflag & CSIZE) {
+       case CS5:
+               new_data = 5;
+               break;
+       case CS6:
+               new_data = 6;
+               break;
+       case CS7:
+               new_data = 7;
+               break;
+       case CS8:
+               new_data = 8;
+               break;
+       default:
+               /* cuz we always need a default ... */
+               new_data = 5;
+               break;
+       }
+       if (cflag & CSTOPB) {
+               new_stop = 1;
+       }
+       if (cflag & PARENB) {
+               new_parity_enable = 1;
+               if (cflag & PARODD)
+                       new_parity = 1;
+       }
+       baud = uart_get_baud_rate(the_port, new_termios, old_termios,
+                                 MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED);
+       DPRINT_CONFIG(("%s: returned baud %d for line %d\n", __func__, baud,
+                               the_port->line));
+
+       if (!the_port->fifosize)
+               the_port->fifosize = FIFO_SIZE;
+       uart_update_timeout(the_port, cflag, baud);
+
+       the_port->ignore_status_mask = N_ALL_INPUT;
+
+       state->port.tty->low_latency = 1;
+
+       if (iflag & IGNPAR)
+               the_port->ignore_status_mask &= ~(N_PARITY_ERROR
+                                                 | N_FRAMING_ERROR);
+       if (iflag & IGNBRK) {
+               the_port->ignore_status_mask &= ~N_BREAK;
+               if (iflag & IGNPAR)
+                       the_port->ignore_status_mask &= ~N_OVERRUN_ERROR;
+       }
+       if (!(cflag & CREAD)) {
+               /* ignore everything */
+               the_port->ignore_status_mask &= ~N_DATA_READY;
+       }
+
+       if (cflag & CRTSCTS) {
+               /* enable hardware flow control */
+               port->ip_sscr |= SSCR_HFC_EN;
+       }
+       else {
+               /* disable hardware flow control */
+               port->ip_sscr &= ~SSCR_HFC_EN;
+       }
+       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+
+       /* Set the configuration and proper notification call */
+       DPRINT_CONFIG(("%s : port 0x%p line %d cflag 0%o "
+                      "config_port(baud %d data %d stop %d penable %d "
+                       " parity %d), notification 0x%x\n",
+                      __func__, (void *)port, the_port->line, cflag, baud,
+                      new_data, new_stop, new_parity_enable, new_parity,
+                      the_port->ignore_status_mask));
+
+       if ((config_port(port, baud,    /* baud */
+                        new_data,      /* byte size */
+                        new_stop,      /* stop bits */
+                        new_parity_enable,     /* set parity */
+                        new_parity)) >= 0) {   /* parity 1==odd */
+               set_notification(port, the_port->ignore_status_mask, 1);
+       }
+}
+
+/**
+ * ic3_startup_local - Start up the serial port - returns >= 0 if no errors
+ * @the_port: Port to operate on
+ */
+static inline int ic3_startup_local(struct uart_port *the_port)
+{
+       struct ioc3_port *port;
+
+       if (!the_port) {
+               NOT_PROGRESS();
+               return -1;
+       }
+
+       port = get_ioc3_port(the_port);
+       if (!port) {
+               NOT_PROGRESS();
+               return -1;
+       }
+
+       local_open(port);
+
+       /* set the protocol */
+       ioc3_set_proto(port, IS_RS232(the_port->line) ? PROTO_RS232 :
+                                                       PROTO_RS422);
+       return 0;
+}
+
+/*
+ * ioc3_cb_output_lowat - called when the output low water mark is hit
+ * @port: port to output
+ */
+static void ioc3_cb_output_lowat(struct ioc3_port *port)
+{
+       unsigned long pflags;
+
+       /* the_port->lock is set on the call here */
+       if (port->ip_port) {
+               spin_lock_irqsave(&port->ip_port->lock, pflags);
+               transmit_chars(port->ip_port);
+               spin_unlock_irqrestore(&port->ip_port->lock, pflags);
+       }
+}
+
+/*
+ * ioc3_cb_post_ncs - called for some basic errors
+ * @port: port to use
+ * @ncs: event
+ */
+static void ioc3_cb_post_ncs(struct uart_port *the_port, int ncs)
+{
+       struct uart_icount *icount;
+
+       icount = &the_port->icount;
+
+       if (ncs & NCS_BREAK)
+               icount->brk++;
+       if (ncs & NCS_FRAMING)
+               icount->frame++;
+       if (ncs & NCS_OVERRUN)
+               icount->overrun++;
+       if (ncs & NCS_PARITY)
+               icount->parity++;
+}
+
+/**
+ * do_read - Read in bytes from the port.  Return the number of bytes
+ *                     actually read.
+ * @the_port: port to use
+ * @buf: place to put the stuff we read
+ * @len: how big 'buf' is
+ */
+
+static inline int do_read(struct uart_port *the_port, char *buf, int len)
+{
+       int prod_ptr, cons_ptr, total;
+       struct ioc3_port *port = get_ioc3_port(the_port);
+       struct ring *inring;
+       struct ring_entry *entry;
+       struct port_hooks *hooks = port->ip_hooks;
+       int byte_num;
+       char *sc;
+       int loop_counter;
+
+       BUG_ON(!(len >= 0));
+       BUG_ON(!port);
+
+       /* There is a nasty timing issue in the IOC3. When the rx_timer
+        * expires or the rx_high condition arises, we take an interrupt.
+        * At some point while servicing the interrupt, we read bytes from
+        * the ring buffer and re-arm the rx_timer.  However the rx_timer is
+        * not started until the first byte is received *after* it is armed,
+        * and any bytes pending in the rx construction buffers are not drained
+        * to memory until either there are 4 bytes available or the rx_timer
+        * expires.  This leads to a potential situation where data is left
+        * in the construction buffers forever - 1 to 3 bytes were received
+        * after the interrupt was generated but before the rx_timer was
+        * re-armed. At that point as long as no subsequent bytes are received
+        * the timer will never be started and the bytes will remain in the
+        * construction buffer forever.  The solution is to execute a DRAIN
+        * command after rearming the timer.  This way any bytes received before
+        * the DRAIN will be drained to memory, and any bytes received after
+        * the DRAIN will start the TIMER and be drained when it expires.
+        * Luckily, this only needs to be done when the DMA buffer is empty
+        * since there is no requirement that this function return all
+        * available data as long as it returns some.
+        */
+       /* Re-arm the timer */
+
+       writel(port->ip_rx_cons | SRCIR_ARM, &port->ip_serial_regs->srcir);
+
+       prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
+       cons_ptr = port->ip_rx_cons;
+
+       if (prod_ptr == cons_ptr) {
+               int reset_dma = 0;
+
+               /* Input buffer appears empty, do a flush. */
+
+               /* DMA must be enabled for this to work. */
+               if (!(port->ip_sscr & SSCR_DMA_EN)) {
+                       port->ip_sscr |= SSCR_DMA_EN;
+                       reset_dma = 1;
+               }
+
+               /* Potential race condition: we must reload the srpir after
+                * issuing the drain command, otherwise we could think the rx
+                * buffer is empty, then take a very long interrupt, and when
+                * we come back it's full and we wait forever for the drain to
+                * complete.
+                */
+               writel(port->ip_sscr | SSCR_RX_DRAIN,
+                      &port->ip_serial_regs->sscr);
+               prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
+
+               /* We must not wait for the DRAIN to complete unless there are
+                * at least 8 bytes (2 ring entries) available to receive the
+                * data otherwise the DRAIN will never complete and we'll
+                * deadlock here.
+                * In fact, to make things easier, I'll just ignore the flush if
+                * there is any data at all now available.
+                */
+               if (prod_ptr == cons_ptr) {
+                       loop_counter = 0;
+                       while (readl(&port->ip_serial_regs->sscr) &
+                              SSCR_RX_DRAIN) {
+                               loop_counter++;
+                               if (loop_counter > MAXITER)
+                                       return -1;
+                       }
+
+                       /* SIGH. We have to reload the prod_ptr *again* since
+                        * the drain may have caused it to change
+                        */
+                       prod_ptr = readl(&port->ip_serial_regs->srpir)
+                           & PROD_CONS_MASK;
+               }
+               if (reset_dma) {
+                       port->ip_sscr &= ~SSCR_DMA_EN;
+                       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+               }
+       }
+       inring = port->ip_inring;
+       port->ip_flags &= ~READ_ABORTED;
+
+       total = 0;
+       loop_counter = 0xfffff; /* to avoid hangs */
+
+       /* Grab bytes from the hardware */
+       while ((prod_ptr != cons_ptr) && (len > 0)) {
+               entry = (struct ring_entry *)((caddr_t) inring + cons_ptr);
+
+               if (loop_counter-- <= 0) {
+                       printk(KERN_WARNING "IOC3 serial: "
+                              "possible hang condition/"
+                              "port stuck on read (line %d).\n",
+                               the_port->line);
+                       break;
+               }
+
+               /* According to the producer pointer, this ring entry
+                * must contain some data.  But if the PIO happened faster
+                * than the DMA, the data may not be available yet, so let's
+                * wait until it arrives.
+                */
+               if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
+                       /* Indicate the read is aborted so we don't disable
+                        * the interrupt thinking that the consumer is
+                        * congested.
+                        */
+                       port->ip_flags |= READ_ABORTED;
+                       len = 0;
+                       break;
+               }
+
+               /* Load the bytes/status out of the ring entry */
+               for (byte_num = 0; byte_num < 4 && len > 0; byte_num++) {
+                       sc = &(entry->ring_sc[byte_num]);
+
+                       /* Check for change in modem state or overrun */
+                       if ((*sc & RXSB_MODEM_VALID)
+                           && (port->ip_notify & N_DDCD)) {
+                               /* Notify upper layer if DCD dropped */
+                               if ((port->ip_flags & DCD_ON)
+                                   && !(*sc & RXSB_DCD)) {
+                                       /* If we have already copied some data,
+                                        * return it.  We'll pick up the carrier
+                                        * drop on the next pass.  That way we
+                                        * don't throw away the data that has
+                                        * already been copied back to
+                                        * the caller's buffer.
+                                        */
+                                       if (total > 0) {
+                                               len = 0;
+                                               break;
+                                       }
+                                       port->ip_flags &= ~DCD_ON;
+
+                                       /* Turn off this notification so the
+                                        * carrier drop protocol won't see it
+                                        * again when it does a read.
+                                        */
+                                       *sc &= ~RXSB_MODEM_VALID;
+
+                                       /* To keep things consistent, we need
+                                        * to update the consumer pointer so
+                                        * the next reader won't come in and
+                                        * try to read the same ring entries
+                                        * again. This must be done here before
+                                        * the dcd change.
+                                        */
+
+                                       if ((entry->ring_allsc & RING_ANY_VALID)
+                                           == 0) {
+                                               cons_ptr += (int)sizeof
+                                                   (struct ring_entry);
+                                               cons_ptr &= PROD_CONS_MASK;
+                                       }
+                                       writel(cons_ptr,
+                                              &port->ip_serial_regs->srcir);
+                                       port->ip_rx_cons = cons_ptr;
+
+                                       /* Notify upper layer of carrier drop */
+                                       if ((port->ip_notify & N_DDCD)
+                                           && port->ip_port) {
+                                               uart_handle_dcd_change
+                                                       (port->ip_port, 0);
+                                               wake_up_interruptible
+                                                   (&the_port->state->
+                                                    port.delta_msr_wait);
+                                       }
+
+                                       /* If we had any data to return, we
+                                        * would have returned it above.
+                                        */
+                                       return 0;
+                               }
+                       }
+                       if (*sc & RXSB_MODEM_VALID) {
+                               /* Notify that an input overrun occurred */
+                               if ((*sc & RXSB_OVERRUN)
+                                   && (port->ip_notify & N_OVERRUN_ERROR)) {
+                                       ioc3_cb_post_ncs(the_port, NCS_OVERRUN);
+                               }
+                               /* Don't look at this byte again */
+                               *sc &= ~RXSB_MODEM_VALID;
+                       }
+
+                       /* Check for valid data or RX errors */
+                       if ((*sc & RXSB_DATA_VALID) &&
+                           ((*sc & (RXSB_PAR_ERR
+                                    | RXSB_FRAME_ERR | RXSB_BREAK))
+                            && (port->ip_notify & (N_PARITY_ERROR
+                                                   | N_FRAMING_ERROR
+                                                   | N_BREAK)))) {
+                               /* There is an error condition on the next byte.
+                                * If we have already transferred some bytes,
+                                * we'll stop here. Otherwise if this is the
+                                * first byte to be read, we'll just transfer
+                                * it alone after notifying the
+                                * upper layer of its status.
+                                */
+                               if (total > 0) {
+                                       len = 0;
+                                       break;
+                               } else {
+                                       if ((*sc & RXSB_PAR_ERR) &&
+                                           (port->
+                                            ip_notify & N_PARITY_ERROR)) {
+                                               ioc3_cb_post_ncs(the_port,
+                                                                NCS_PARITY);
+                                       }
+                                       if ((*sc & RXSB_FRAME_ERR) &&
+                                           (port->
+                                            ip_notify & N_FRAMING_ERROR)) {
+                                               ioc3_cb_post_ncs(the_port,
+                                                                NCS_FRAMING);
+                                       }
+                                       if ((*sc & RXSB_BREAK)
+                                           && (port->ip_notify & N_BREAK)) {
+                                               ioc3_cb_post_ncs
+                                                   (the_port, NCS_BREAK);
+                                       }
+                                       len = 1;
+                               }
+                       }
+                       if (*sc & RXSB_DATA_VALID) {
+                               *sc &= ~RXSB_DATA_VALID;
+                               *buf = entry->ring_data[byte_num];
+                               buf++;
+                               len--;
+                               total++;
+                       }
+               }
+
+               /* If we used up this entry entirely, go on to the next one,
+                * otherwise we must have run out of buffer space, so
+                * leave the consumer pointer here for the next read in case
+                * there are still unread bytes in this entry.
+                */
+               if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
+                       cons_ptr += (int)sizeof(struct ring_entry);
+                       cons_ptr &= PROD_CONS_MASK;
+               }
+       }
+
+       /* Update consumer pointer and re-arm rx timer interrupt */
+       writel(cons_ptr, &port->ip_serial_regs->srcir);
+       port->ip_rx_cons = cons_ptr;
+
+       /* If we have now dipped below the rx high water mark and we have
+        * rx_high interrupt turned off, we can now turn it back on again.
+        */
+       if ((port->ip_flags & INPUT_HIGH) && (((prod_ptr - cons_ptr)
+                                              & PROD_CONS_MASK) <
+                                             ((port->
+                                               ip_sscr &
+                                               SSCR_RX_THRESHOLD)
+                                              << PROD_CONS_PTR_OFF))) {
+               port->ip_flags &= ~INPUT_HIGH;
+               enable_intrs(port, hooks->intr_rx_high);
+       }
+       return total;
+}
+
+/**
+ * receive_chars - upper level read.
+ * @the_port: port to read from
+ */
+static int receive_chars(struct uart_port *the_port)
+{
+       struct tty_struct *tty;
+       unsigned char ch[MAX_CHARS];
+       int read_count = 0, read_room, flip = 0;
+       struct uart_state *state = the_port->state;
+       struct ioc3_port *port = get_ioc3_port(the_port);
+       unsigned long pflags;
+
+       /* Make sure all the pointers are "good" ones */
+       if (!state)
+               return 0;
+       if (!state->port.tty)
+               return 0;
+
+       if (!(port->ip_flags & INPUT_ENABLE))
+               return 0;
+
+       spin_lock_irqsave(&the_port->lock, pflags);
+       tty = state->port.tty;
+
+       read_count = do_read(the_port, ch, MAX_CHARS);
+       if (read_count > 0) {
+               flip = 1;
+               read_room = tty_insert_flip_string(tty, ch, read_count);
+               the_port->icount.rx += read_count;
+       }
+       spin_unlock_irqrestore(&the_port->lock, pflags);
+
+       if (flip)
+               tty_flip_buffer_push(tty);
+
+       return read_count;
+}
+
+/**
+ * ioc3uart_intr_one - lowest level (per port) interrupt handler.
+ * @is : submodule
+ * @idd: driver data
+ * @pending: interrupts to handle
+ */
+
+static int inline
+ioc3uart_intr_one(struct ioc3_submodule *is,
+                       struct ioc3_driver_data *idd,
+                       unsigned int pending)
+{
+       int port_num = GET_PORT_FROM_SIO_IR(pending);
+       struct port_hooks *hooks;
+       unsigned int rx_high_rd_aborted = 0;
+       unsigned long flags;
+       struct uart_port *the_port;
+       struct ioc3_port *port;
+       int loop_counter;
+       struct ioc3_card *card_ptr;
+       unsigned int sio_ir;
+
+       card_ptr = idd->data[is->id];
+       port = card_ptr->ic_port[port_num].icp_port;
+       hooks = port->ip_hooks;
+
+       /* Possible race condition here: The tx_mt interrupt bit may be
+        * cleared without the intervention of the interrupt handler,
+        * e.g. by a write.  If the top level interrupt handler reads a
+        * tx_mt, then some other processor does a write, starting up
+        * output, then we come in here, see the tx_mt and stop DMA, the
+        * output started by the other processor will hang.  Thus we can
+        * only rely on tx_mt being legitimate if it is read while the
+        * port lock is held.  Therefore this bit must be ignored in the
+        * passed in interrupt mask which was read by the top level
+        * interrupt handler since the port lock was not held at the time
+        * it was read.  We can only rely on this bit being accurate if it
+        * is read while the port lock is held.  So we'll clear it for now,
+        * and reload it later once we have the port lock.
+        */
+
+       sio_ir = pending & ~(hooks->intr_tx_mt);
+       spin_lock_irqsave(&port->ip_lock, flags);
+
+       loop_counter = MAXITER; /* to avoid hangs */
+
+       do {
+               uint32_t shadow;
+
+               if (loop_counter-- <= 0) {
+                       printk(KERN_WARNING "IOC3 serial: "
+                              "possible hang condition/"
+                              "port stuck on interrupt (line %d).\n",
+                               ((struct uart_port *)port->ip_port)->line);
+                       break;
+               }
+               /* Handle a DCD change */
+               if (sio_ir & hooks->intr_delta_dcd) {
+                       ioc3_ack(is, idd, hooks->intr_delta_dcd);
+                       shadow = readl(&port->ip_serial_regs->shadow);
+
+                       if ((port->ip_notify & N_DDCD)
+                           && (shadow & SHADOW_DCD)
+                           && (port->ip_port)) {
+                               the_port = port->ip_port;
+                               uart_handle_dcd_change(the_port,
+                                               shadow & SHADOW_DCD);
+                               wake_up_interruptible
+                                   (&the_port->state->port.delta_msr_wait);
+                       } else if ((port->ip_notify & N_DDCD)
+                                  && !(shadow & SHADOW_DCD)) {
+                               /* Flag delta DCD/no DCD */
+                               uart_handle_dcd_change(port->ip_port,
+                                               shadow & SHADOW_DCD);
+                               port->ip_flags |= DCD_ON;
+                       }
+               }
+
+               /* Handle a CTS change */
+               if (sio_ir & hooks->intr_delta_cts) {
+                       ioc3_ack(is, idd, hooks->intr_delta_cts);
+                       shadow = readl(&port->ip_serial_regs->shadow);
+
+                       if ((port->ip_notify & N_DCTS) && (port->ip_port)) {
+                               the_port = port->ip_port;
+                               uart_handle_cts_change(the_port, shadow
+                                               & SHADOW_CTS);
+                               wake_up_interruptible
+                                   (&the_port->state->port.delta_msr_wait);
+                       }
+               }
+
+               /* rx timeout interrupt.  Must be some data available.  Put this
+                * before the check for rx_high since servicing this condition
+                * may cause that condition to clear.
+                */
+               if (sio_ir & hooks->intr_rx_timer) {
+                       ioc3_ack(is, idd, hooks->intr_rx_timer);
+                       if ((port->ip_notify & N_DATA_READY)
+                                               && (port->ip_port)) {
+                               receive_chars(port->ip_port);
+                       }
+               }
+
+               /* rx high interrupt. Must be after rx_timer.  */
+               else if (sio_ir & hooks->intr_rx_high) {
+                       /* Data available, notify upper layer */
+                       if ((port->ip_notify & N_DATA_READY) && port->ip_port) {
+                               receive_chars(port->ip_port);
+                       }
+
+                       /* We can't ACK this interrupt.  If receive_chars didn't
+                        * cause the condition to clear, we'll have to disable
+                        * the interrupt until the data is drained.
+                        * If the read was aborted, don't disable the interrupt
+                        * as this may cause us to hang indefinitely.  An
+                        * aborted read generally means that this interrupt
+                        * hasn't been delivered to the cpu yet anyway, even
+                        * though we see it as asserted when we read the sio_ir.
+                        */
+                       if ((sio_ir = PENDING(card_ptr, idd))
+                                       & hooks->intr_rx_high) {
+                               if (port->ip_flags & READ_ABORTED) {
+                                       rx_high_rd_aborted++;
+                               }
+                               else {
+                                       card_ptr->ic_enable &= ~hooks->intr_rx_high;
+                                       port->ip_flags |= INPUT_HIGH;
+                               }
+                       }
+               }
+
+               /* We got a low water interrupt: notify upper layer to
+                * send more data.  Must come before tx_mt since servicing
+                * this condition may cause that condition to clear.
+                */
+               if (sio_ir & hooks->intr_tx_explicit) {
+                       port->ip_flags &= ~LOWAT_WRITTEN;
+                       ioc3_ack(is, idd, hooks->intr_tx_explicit);
+                       if (port->ip_notify & N_OUTPUT_LOWAT)
+                               ioc3_cb_output_lowat(port);
+               }
+
+               /* Handle tx_mt.  Must come after tx_explicit.  */
+               else if (sio_ir & hooks->intr_tx_mt) {
+                       /* If we are expecting a lowat notification
+                        * and we get to this point it probably means that for
+                        * some reason the tx_explicit didn't work as expected
+                        * (that can legitimately happen if the output buffer is
+                        * filled up in just the right way).
+                        * So send the notification now.
+                        */
+                       if (port->ip_notify & N_OUTPUT_LOWAT) {
+                               ioc3_cb_output_lowat(port);
+
+                               /* We need to reload the sio_ir since the lowat
+                                * call may have caused another write to occur,
+                                * clearing the tx_mt condition.
+                                */
+                               sio_ir = PENDING(card_ptr, idd);
+                       }
+
+                       /* If the tx_mt condition still persists even after the
+                        * lowat call, we've got some work to do.
+                        */
+                       if (sio_ir & hooks->intr_tx_mt) {
+                               /* If we are not currently expecting DMA input,
+                                * and the transmitter has just gone idle,
+                                * there is no longer any reason for DMA, so
+                                * disable it.
+                                */
+                               if (!(port->ip_notify
+                                     & (N_DATA_READY | N_DDCD))) {
+                                       BUG_ON(!(port->ip_sscr
+                                                & SSCR_DMA_EN));
+                                       port->ip_sscr &= ~SSCR_DMA_EN;
+                                       writel(port->ip_sscr,
+                                              &port->ip_serial_regs->sscr);
+                               }
+                               /* Prevent infinite tx_mt interrupt */
+                               card_ptr->ic_enable &= ~hooks->intr_tx_mt;
+                       }
+               }
+               sio_ir = PENDING(card_ptr, idd);
+
+               /* if the read was aborted and only hooks->intr_rx_high,
+                * clear hooks->intr_rx_high, so we do not loop forever.
+                */
+
+               if (rx_high_rd_aborted && (sio_ir == hooks->intr_rx_high)) {
+                       sio_ir &= ~hooks->intr_rx_high;
+               }
+       } while (sio_ir & hooks->intr_all);
+
+       spin_unlock_irqrestore(&port->ip_lock, flags);
+       ioc3_enable(is, idd, card_ptr->ic_enable);
+       return 0;
+}
+
+/**
+ * ioc3uart_intr - field all serial interrupts
+ * @is : submodule
+ * @idd: driver data
+ * @pending: interrupts to handle
+ *
+ */
+
+static int ioc3uart_intr(struct ioc3_submodule *is,
+                       struct ioc3_driver_data *idd,
+                       unsigned int pending)
+{
+       int ret = 0;
+
+       /*
+        * The upper level interrupt handler sends interrupts for both ports
+        * here. So we need to call for each port with its interrupts.
+        */
+
+       if (pending & SIO_IR_SA)
+               ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SA);
+       if (pending & SIO_IR_SB)
+               ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SB);
+
+       return ret;
+}
+
+/**
+ * ic3_type
+ * @port: Port to operate with (we ignore since we only have one port)
+ *
+ */
+static const char *ic3_type(struct uart_port *the_port)
+{
+       if (IS_RS232(the_port->line))
+               return "SGI IOC3 Serial [rs232]";
+       else
+               return "SGI IOC3 Serial [rs422]";
+}
+
+/**
+ * ic3_tx_empty - Is the transmitter empty?
+ * @port: Port to operate on
+ *
+ */
+static unsigned int ic3_tx_empty(struct uart_port *the_port)
+{
+       unsigned int ret = 0;
+       struct ioc3_port *port = get_ioc3_port(the_port);
+
+       if (readl(&port->ip_serial_regs->shadow) & SHADOW_TEMT)
+               ret = TIOCSER_TEMT;
+       return ret;
+}
+
+/**
+ * ic3_stop_tx - stop the transmitter
+ * @port: Port to operate on
+ *
+ */
+static void ic3_stop_tx(struct uart_port *the_port)
+{
+       struct ioc3_port *port = get_ioc3_port(the_port);
+
+       if (port)
+               set_notification(port, N_OUTPUT_LOWAT, 0);
+}
+
+/**
+ * ic3_stop_rx - stop the receiver
+ * @port: Port to operate on
+ *
+ */
+static void ic3_stop_rx(struct uart_port *the_port)
+{
+       struct ioc3_port *port = get_ioc3_port(the_port);
+
+       if (port)
+               port->ip_flags &= ~INPUT_ENABLE;
+}
+
+/**
+ * null_void_function
+ * @port: Port to operate on
+ *
+ */
+static void null_void_function(struct uart_port *the_port)
+{
+}
+
+/**
+ * ic3_shutdown - shut down the port - free irq and disable
+ * @port: port to shut down
+ *
+ */
+static void ic3_shutdown(struct uart_port *the_port)
+{
+       unsigned long port_flags;
+       struct ioc3_port *port;
+       struct uart_state *state;
+
+       port = get_ioc3_port(the_port);
+       if (!port)
+               return;
+
+       state = the_port->state;
+       wake_up_interruptible(&state->port.delta_msr_wait);
+
+       spin_lock_irqsave(&the_port->lock, port_flags);
+       set_notification(port, N_ALL, 0);
+       spin_unlock_irqrestore(&the_port->lock, port_flags);
+}
+
+/**
+ * ic3_set_mctrl - set control lines (dtr, rts, etc)
+ * @port: Port to operate on
+ * @mctrl: Lines to set/unset
+ *
+ */
+static void ic3_set_mctrl(struct uart_port *the_port, unsigned int mctrl)
+{
+       unsigned char mcr = 0;
+
+       if (mctrl & TIOCM_RTS)
+               mcr |= UART_MCR_RTS;
+       if (mctrl & TIOCM_DTR)
+               mcr |= UART_MCR_DTR;
+       if (mctrl & TIOCM_OUT1)
+               mcr |= UART_MCR_OUT1;
+       if (mctrl & TIOCM_OUT2)
+               mcr |= UART_MCR_OUT2;
+       if (mctrl & TIOCM_LOOP)
+               mcr |= UART_MCR_LOOP;
+
+       set_mcr(the_port, mcr, SHADOW_DTR);
+}
+
+/**
+ * ic3_get_mctrl - get control line info
+ * @port: port to operate on
+ *
+ */
+static unsigned int ic3_get_mctrl(struct uart_port *the_port)
+{
+       struct ioc3_port *port = get_ioc3_port(the_port);
+       uint32_t shadow;
+       unsigned int ret = 0;
+
+       if (!port)
+               return 0;
+
+       shadow = readl(&port->ip_serial_regs->shadow);
+       if (shadow & SHADOW_DCD)
+               ret |= TIOCM_CD;
+       if (shadow & SHADOW_DR)
+               ret |= TIOCM_DSR;
+       if (shadow & SHADOW_CTS)
+               ret |= TIOCM_CTS;
+       return ret;
+}
+
+/**
+ * ic3_start_tx - Start transmitter. Called with the_port->lock
+ * @port: Port to operate on
+ *
+ */
+static void ic3_start_tx(struct uart_port *the_port)
+{
+       struct ioc3_port *port = get_ioc3_port(the_port);
+
+       if (port) {
+               set_notification(port, N_OUTPUT_LOWAT, 1);
+               enable_intrs(port, port->ip_hooks->intr_tx_mt);
+       }
+}
+
+/**
+ * ic3_break_ctl - handle breaks
+ * @port: Port to operate on
+ * @break_state: Break state
+ *
+ */
+static void ic3_break_ctl(struct uart_port *the_port, int break_state)
+{
+}
+
+/**
+ * ic3_startup - Start up the serial port - always return 0 (We're always on)
+ * @port: Port to operate on
+ *
+ */
+static int ic3_startup(struct uart_port *the_port)
+{
+       int retval;
+       struct ioc3_port *port;
+       struct ioc3_card *card_ptr;
+       unsigned long port_flags;
+
+       if (!the_port) {
+               NOT_PROGRESS();
+               return -ENODEV;
+       }
+       port = get_ioc3_port(the_port);
+       if (!port) {
+               NOT_PROGRESS();
+               return -ENODEV;
+       }
+       card_ptr = port->ip_card;
+       port->ip_port = the_port;
+
+       if (!card_ptr) {
+               NOT_PROGRESS();
+               return -ENODEV;
+       }
+
+       /* Start up the serial port */
+       spin_lock_irqsave(&the_port->lock, port_flags);
+       retval = ic3_startup_local(the_port);
+       spin_unlock_irqrestore(&the_port->lock, port_flags);
+       return retval;
+}
+
+/**
+ * ic3_set_termios - set termios stuff
+ * @port: port to operate on
+ * @termios: New settings
+ * @termios: Old
+ *
+ */
+static void
+ic3_set_termios(struct uart_port *the_port,
+               struct ktermios *termios, struct ktermios *old_termios)
+{
+       unsigned long port_flags;
+
+       spin_lock_irqsave(&the_port->lock, port_flags);
+       ioc3_change_speed(the_port, termios, old_termios);
+       spin_unlock_irqrestore(&the_port->lock, port_flags);
+}
+
+/**
+ * ic3_request_port - allocate resources for port - no op....
+ * @port: port to operate on
+ *
+ */
+static int ic3_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+/* Associate the uart functions above - given to serial core */
+static struct uart_ops ioc3_ops = {
+       .tx_empty = ic3_tx_empty,
+       .set_mctrl = ic3_set_mctrl,
+       .get_mctrl = ic3_get_mctrl,
+       .stop_tx = ic3_stop_tx,
+       .start_tx = ic3_start_tx,
+       .stop_rx = ic3_stop_rx,
+       .enable_ms = null_void_function,
+       .break_ctl = ic3_break_ctl,
+       .startup = ic3_startup,
+       .shutdown = ic3_shutdown,
+       .set_termios = ic3_set_termios,
+       .type = ic3_type,
+       .release_port = null_void_function,
+       .request_port = ic3_request_port,
+};
+
+/*
+ * Boot-time initialization code
+ */
+
+static struct uart_driver ioc3_uart = {
+       .owner = THIS_MODULE,
+       .driver_name = "ioc3_serial",
+       .dev_name = DEVICE_NAME,
+       .major = DEVICE_MAJOR,
+       .minor = DEVICE_MINOR,
+       .nr = MAX_LOGICAL_PORTS
+};
+
+/**
+ * ioc3_serial_core_attach - register with serial core
+ *             This is done during pci probing
+ * @is: submodule struct for this
+ * @idd: handle for this card
+ */
+static inline int ioc3_serial_core_attach( struct ioc3_submodule *is,
+                               struct ioc3_driver_data *idd)
+{
+       struct ioc3_port *port;
+       struct uart_port *the_port;
+       struct ioc3_card *card_ptr = idd->data[is->id];
+       int ii, phys_port;
+       struct pci_dev *pdev = idd->pdev;
+
+       DPRINT_CONFIG(("%s: attach pdev 0x%p - card_ptr 0x%p\n",
+                      __func__, pdev, (void *)card_ptr));
+
+       if (!card_ptr)
+               return -ENODEV;
+
+       /* once around for each logical port on this card */
+       for (ii = 0; ii < LOGICAL_PORTS_PER_CARD; ii++) {
+               phys_port = GET_PHYSICAL_PORT(ii);
+               the_port = &card_ptr->ic_port[phys_port].
+                               icp_uart_port[GET_LOGICAL_PORT(ii)];
+               port = card_ptr->ic_port[phys_port].icp_port;
+               port->ip_port = the_port;
+
+               DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p [%d/%d]\n",
+                       __func__, (void *)the_port, (void *)port,
+                               phys_port, ii));
+
+               /* membase, iobase and mapbase just need to be non-0 */
+               the_port->membase = (unsigned char __iomem *)1;
+               the_port->iobase = (pdev->bus->number << 16) |  ii;
+               the_port->line = (Num_of_ioc3_cards << 2) | ii;
+               the_port->mapbase = 1;
+               the_port->type = PORT_16550A;
+               the_port->fifosize = FIFO_SIZE;
+               the_port->ops = &ioc3_ops;
+               the_port->irq = idd->irq_io;
+               the_port->dev = &pdev->dev;
+
+               if (uart_add_one_port(&ioc3_uart, the_port) < 0) {
+                       printk(KERN_WARNING
+                         "%s: unable to add port %d bus %d\n",
+                              __func__, the_port->line, pdev->bus->number);
+               } else {
+                       DPRINT_CONFIG(("IOC3 serial port %d irq %d bus %d\n",
+                         the_port->line, the_port->irq, pdev->bus->number));
+               }
+
+               /* all ports are rs232 for now */
+               if (IS_PHYSICAL_PORT(ii))
+                       ioc3_set_proto(port, PROTO_RS232);
+       }
+       return 0;
+}
+
+/**
+ * ioc3uart_remove - register detach function
+ * @is: submodule struct for this submodule
+ * @idd: ioc3 driver data for this submodule
+ */
+
+static int ioc3uart_remove(struct ioc3_submodule *is,
+                       struct ioc3_driver_data *idd)
+{
+       struct ioc3_card *card_ptr = idd->data[is->id];
+       struct uart_port *the_port;
+       struct ioc3_port *port;
+       int ii;
+
+       if (card_ptr) {
+               for (ii = 0; ii < LOGICAL_PORTS_PER_CARD; ii++) {
+                       the_port = &card_ptr->ic_port[GET_PHYSICAL_PORT(ii)].
+                                       icp_uart_port[GET_LOGICAL_PORT(ii)];
+                       if (the_port)
+                               uart_remove_one_port(&ioc3_uart, the_port);
+                       port = card_ptr->ic_port[GET_PHYSICAL_PORT(ii)].icp_port;
+                       if (port && IS_PHYSICAL_PORT(ii)
+                                       && (GET_PHYSICAL_PORT(ii) == 0)) {
+                               pci_free_consistent(port->ip_idd->pdev,
+                                       TOTAL_RING_BUF_SIZE,
+                                       (void *)port->ip_cpu_ringbuf,
+                                       port->ip_dma_ringbuf);
+                               kfree(port);
+                               card_ptr->ic_port[GET_PHYSICAL_PORT(ii)].
+                                                       icp_port = NULL;
+                       }
+               }
+               kfree(card_ptr);
+               idd->data[is->id] = NULL;
+       }
+       return 0;
+}
+
+/**
+ * ioc3uart_probe - card probe function called from shim driver
+ * @is: submodule struct for this submodule
+ * @idd: ioc3 driver data for this card
+ */
+
+static int __devinit
+ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
+{
+       struct pci_dev *pdev = idd->pdev;
+       struct ioc3_card *card_ptr;
+       int ret = 0;
+       struct ioc3_port *port;
+       struct ioc3_port *ports[PORTS_PER_CARD];
+       int phys_port;
+       int cnt;
+
+       DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, is, idd));
+
+       card_ptr = kzalloc(sizeof(struct ioc3_card), GFP_KERNEL);
+       if (!card_ptr) {
+               printk(KERN_WARNING "ioc3_attach_one"
+                      ": unable to get memory for the IOC3\n");
+               return -ENOMEM;
+       }
+       idd->data[is->id] = card_ptr;
+       Submodule_slot = is->id;
+
+       writel(((UARTA_BASE >> 3) << SIO_CR_SER_A_BASE_SHIFT) |
+               ((UARTB_BASE >> 3) << SIO_CR_SER_B_BASE_SHIFT) |
+               (0xf << SIO_CR_CMD_PULSE_SHIFT), &idd->vma->sio_cr);
+
+       pci_write_config_dword(pdev, PCI_LAT, 0xff00);
+
+       /* Enable serial port mode select generic PIO pins as outputs */
+       ioc3_gpcr_set(idd, GPCR_UARTA_MODESEL | GPCR_UARTB_MODESEL);
+
+       /* Create port structures for each port */
+       for (phys_port = 0; phys_port < PORTS_PER_CARD; phys_port++) {
+               port = kzalloc(sizeof(struct ioc3_port), GFP_KERNEL);
+               if (!port) {
+                       printk(KERN_WARNING
+                              "IOC3 serial memory not available for port\n");
+                       ret = -ENOMEM;
+                       goto out4;
+               }
+               spin_lock_init(&port->ip_lock);
+
+               /* we need to remember the previous ones, to point back to
+                * them farther down - setting up the ring buffers.
+                */
+               ports[phys_port] = port;
+
+               /* init to something useful */
+               card_ptr->ic_port[phys_port].icp_port = port;
+               port->ip_is = is;
+               port->ip_idd = idd;
+               port->ip_baud = 9600;
+               port->ip_card = card_ptr;
+               port->ip_hooks = &hooks_array[phys_port];
+
+               /* Setup each port */
+               if (phys_port == 0) {
+                       port->ip_serial_regs = &idd->vma->port_a;
+                       port->ip_uart_regs = &idd->vma->sregs.uarta;
+
+                       DPRINT_CONFIG(("%s : Port A ip_serial_regs 0x%p "
+                                      "ip_uart_regs 0x%p\n",
+                                      __func__,
+                                      (void *)port->ip_serial_regs,
+                                      (void *)port->ip_uart_regs));
+
+                       /* setup ring buffers */
+                       port->ip_cpu_ringbuf = pci_alloc_consistent(pdev,
+                               TOTAL_RING_BUF_SIZE, &port->ip_dma_ringbuf);
+
+                       BUG_ON(!((((int64_t) port->ip_dma_ringbuf) &
+                                 (TOTAL_RING_BUF_SIZE - 1)) == 0));
+                       port->ip_inring = RING(port, RX_A);
+                       port->ip_outring = RING(port, TX_A);
+                       DPRINT_CONFIG(("%s : Port A ip_cpu_ringbuf 0x%p "
+                                      "ip_dma_ringbuf 0x%p, ip_inring 0x%p "
+                                       "ip_outring 0x%p\n",
+                                      __func__,
+                                      (void *)port->ip_cpu_ringbuf,
+                                      (void *)port->ip_dma_ringbuf,
+                                      (void *)port->ip_inring,
+                                      (void *)port->ip_outring));
+               }
+               else {
+                       port->ip_serial_regs = &idd->vma->port_b;
+                       port->ip_uart_regs = &idd->vma->sregs.uartb;
+
+                       DPRINT_CONFIG(("%s : Port B ip_serial_regs 0x%p "
+                                      "ip_uart_regs 0x%p\n",
+                                      __func__,
+                                      (void *)port->ip_serial_regs,
+                                      (void *)port->ip_uart_regs));
+
+                       /* share the ring buffers */
+                       port->ip_dma_ringbuf =
+                           ports[phys_port - 1]->ip_dma_ringbuf;
+                       port->ip_cpu_ringbuf =
+                           ports[phys_port - 1]->ip_cpu_ringbuf;
+                       port->ip_inring = RING(port, RX_B);
+                       port->ip_outring = RING(port, TX_B);
+                       DPRINT_CONFIG(("%s : Port B ip_cpu_ringbuf 0x%p "
+                                      "ip_dma_ringbuf 0x%p, ip_inring 0x%p "
+                                       "ip_outring 0x%p\n",
+                                      __func__,
+                                      (void *)port->ip_cpu_ringbuf,
+                                      (void *)port->ip_dma_ringbuf,
+                                      (void *)port->ip_inring,
+                                      (void *)port->ip_outring));
+               }
+
+               DPRINT_CONFIG(("%s : port %d [addr 0x%p] card_ptr 0x%p",
+                              __func__,
+                              phys_port, (void *)port, (void *)card_ptr));
+               DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n",
+                              (void *)port->ip_serial_regs,
+                              (void *)port->ip_uart_regs));
+
+               /* Initialize the hardware for IOC3 */
+               port_init(port);
+
+               DPRINT_CONFIG(("%s: phys_port %d port 0x%p inring 0x%p "
+                              "outring 0x%p\n",
+                              __func__,
+                              phys_port, (void *)port,
+                              (void *)port->ip_inring,
+                              (void *)port->ip_outring));
+
+       }
+
+       /* register port with the serial core */
+
+       if ((ret = ioc3_serial_core_attach(is, idd)))
+               goto out4;
+
+       Num_of_ioc3_cards++;
+
+       return ret;
+
+       /* error exits that give back resources */
+out4:
+       for (cnt = 0; cnt < phys_port; cnt++)
+               kfree(ports[cnt]);
+
+       kfree(card_ptr);
+       return ret;
+}
+
+static struct ioc3_submodule ioc3uart_ops = {
+       .name = "IOC3uart",
+       .probe = ioc3uart_probe,
+       .remove = ioc3uart_remove,
+       /* call .intr for both ports initially */
+       .irq_mask = SIO_IR_SA | SIO_IR_SB,
+       .intr = ioc3uart_intr,
+       .owner = THIS_MODULE,
+};
+
+/**
+ * ioc3_detect - module init called,
+ */
+static int __init ioc3uart_init(void)
+{
+       int ret;
+
+       /* register with serial core */
+       if ((ret = uart_register_driver(&ioc3_uart)) < 0) {
+               printk(KERN_WARNING
+                      "%s: Couldn't register IOC3 uart serial driver\n",
+                      __func__);
+               return ret;
+       }
+       ret = ioc3_register_submodule(&ioc3uart_ops);
+       if (ret)
+               uart_unregister_driver(&ioc3_uart);
+       return ret;
+}
+
+static void __exit ioc3uart_exit(void)
+{
+       ioc3_unregister_submodule(&ioc3uart_ops);
+       uart_unregister_driver(&ioc3_uart);
+}
+
+module_init(ioc3uart_init);
+module_exit(ioc3uart_exit);
+
+MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) <pfg@sgi.com>");
+MODULE_DESCRIPTION("Serial PCI driver module for SGI IOC3 card");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/ioc4_serial.c b/drivers/tty/serial/ioc4_serial.c
new file mode 100644 (file)
index 0000000..fcfe826
--- /dev/null
@@ -0,0 +1,2953 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2003-2006 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+
+/*
+ * This file contains a module version of the ioc4 serial driver. This
+ * includes all the support functions needed (support functions, etc.)
+ * and the serial driver itself.
+ */
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/circ_buf.h>
+#include <linux/serial_reg.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/ioc4.h>
+#include <linux/serial_core.h>
+#include <linux/slab.h>
+
+/*
+ * interesting things about the ioc4
+ */
+
+#define IOC4_NUM_SERIAL_PORTS  4       /* max ports per card */
+#define IOC4_NUM_CARDS         8       /* max cards per partition */
+
+#define        GET_SIO_IR(_n)  (_n == 0) ? (IOC4_SIO_IR_S0) : \
+                               (_n == 1) ? (IOC4_SIO_IR_S1) : \
+                               (_n == 2) ? (IOC4_SIO_IR_S2) : \
+                               (IOC4_SIO_IR_S3)
+
+#define        GET_OTHER_IR(_n)  (_n == 0) ? (IOC4_OTHER_IR_S0_MEMERR) : \
+                               (_n == 1) ? (IOC4_OTHER_IR_S1_MEMERR) : \
+                               (_n == 2) ? (IOC4_OTHER_IR_S2_MEMERR) : \
+                               (IOC4_OTHER_IR_S3_MEMERR)
+
+
+/*
+ * All IOC4 registers are 32 bits wide.
+ */
+
+/*
+ * PCI Memory Space Map
+ */
+#define IOC4_PCI_ERR_ADDR_L     0x000  /* Low Error Address */
+#define IOC4_PCI_ERR_ADDR_VLD          (0x1 << 0)
+#define IOC4_PCI_ERR_ADDR_MST_ID_MSK    (0xf << 1)
+#define IOC4_PCI_ERR_ADDR_MST_NUM_MSK   (0xe << 1)
+#define IOC4_PCI_ERR_ADDR_MST_TYP_MSK   (0x1 << 1)
+#define IOC4_PCI_ERR_ADDR_MUL_ERR       (0x1 << 5)
+#define IOC4_PCI_ERR_ADDR_ADDR_MSK      (0x3ffffff << 6)
+
+/* Interrupt types */
+#define        IOC4_SIO_INTR_TYPE      0
+#define        IOC4_OTHER_INTR_TYPE    1
+#define        IOC4_NUM_INTR_TYPES     2
+
+/* Bitmasks for IOC4_SIO_IR, IOC4_SIO_IEC, and IOC4_SIO_IES  */
+#define IOC4_SIO_IR_S0_TX_MT      0x00000001   /* Serial port 0 TX empty */
+#define IOC4_SIO_IR_S0_RX_FULL    0x00000002   /* Port 0 RX buf full */
+#define IOC4_SIO_IR_S0_RX_HIGH    0x00000004   /* Port 0 RX hiwat */
+#define IOC4_SIO_IR_S0_RX_TIMER           0x00000008   /* Port 0 RX timeout */
+#define IOC4_SIO_IR_S0_DELTA_DCD   0x00000010  /* Port 0 delta DCD */
+#define IOC4_SIO_IR_S0_DELTA_CTS   0x00000020  /* Port 0 delta CTS */
+#define IOC4_SIO_IR_S0_INT        0x00000040   /* Port 0 pass-thru intr */
+#define IOC4_SIO_IR_S0_TX_EXPLICIT 0x00000080  /* Port 0 explicit TX thru */
+#define IOC4_SIO_IR_S1_TX_MT      0x00000100   /* Serial port 1 */
+#define IOC4_SIO_IR_S1_RX_FULL    0x00000200   /* */
+#define IOC4_SIO_IR_S1_RX_HIGH    0x00000400   /* */
+#define IOC4_SIO_IR_S1_RX_TIMER           0x00000800   /* */
+#define IOC4_SIO_IR_S1_DELTA_DCD   0x00001000  /* */
+#define IOC4_SIO_IR_S1_DELTA_CTS   0x00002000  /* */
+#define IOC4_SIO_IR_S1_INT        0x00004000   /* */
+#define IOC4_SIO_IR_S1_TX_EXPLICIT 0x00008000  /* */
+#define IOC4_SIO_IR_S2_TX_MT      0x00010000   /* Serial port 2 */
+#define IOC4_SIO_IR_S2_RX_FULL    0x00020000   /* */
+#define IOC4_SIO_IR_S2_RX_HIGH    0x00040000   /* */
+#define IOC4_SIO_IR_S2_RX_TIMER           0x00080000   /* */
+#define IOC4_SIO_IR_S2_DELTA_DCD   0x00100000  /* */
+#define IOC4_SIO_IR_S2_DELTA_CTS   0x00200000  /* */
+#define IOC4_SIO_IR_S2_INT        0x00400000   /* */
+#define IOC4_SIO_IR_S2_TX_EXPLICIT 0x00800000  /* */
+#define IOC4_SIO_IR_S3_TX_MT      0x01000000   /* Serial port 3 */
+#define IOC4_SIO_IR_S3_RX_FULL    0x02000000   /* */
+#define IOC4_SIO_IR_S3_RX_HIGH    0x04000000   /* */
+#define IOC4_SIO_IR_S3_RX_TIMER           0x08000000   /* */
+#define IOC4_SIO_IR_S3_DELTA_DCD   0x10000000  /* */
+#define IOC4_SIO_IR_S3_DELTA_CTS   0x20000000  /* */
+#define IOC4_SIO_IR_S3_INT        0x40000000   /* */
+#define IOC4_SIO_IR_S3_TX_EXPLICIT 0x80000000  /* */
+
+/* Per device interrupt masks */
+#define IOC4_SIO_IR_S0         (IOC4_SIO_IR_S0_TX_MT | \
+                                IOC4_SIO_IR_S0_RX_FULL | \
+                                IOC4_SIO_IR_S0_RX_HIGH | \
+                                IOC4_SIO_IR_S0_RX_TIMER | \
+                                IOC4_SIO_IR_S0_DELTA_DCD | \
+                                IOC4_SIO_IR_S0_DELTA_CTS | \
+                                IOC4_SIO_IR_S0_INT | \
+                                IOC4_SIO_IR_S0_TX_EXPLICIT)
+#define IOC4_SIO_IR_S1         (IOC4_SIO_IR_S1_TX_MT | \
+                                IOC4_SIO_IR_S1_RX_FULL | \
+                                IOC4_SIO_IR_S1_RX_HIGH | \
+                                IOC4_SIO_IR_S1_RX_TIMER | \
+                                IOC4_SIO_IR_S1_DELTA_DCD | \
+                                IOC4_SIO_IR_S1_DELTA_CTS | \
+                                IOC4_SIO_IR_S1_INT | \
+                                IOC4_SIO_IR_S1_TX_EXPLICIT)
+#define IOC4_SIO_IR_S2         (IOC4_SIO_IR_S2_TX_MT | \
+                                IOC4_SIO_IR_S2_RX_FULL | \
+                                IOC4_SIO_IR_S2_RX_HIGH | \
+                                IOC4_SIO_IR_S2_RX_TIMER | \
+                                IOC4_SIO_IR_S2_DELTA_DCD | \
+                                IOC4_SIO_IR_S2_DELTA_CTS | \
+                                IOC4_SIO_IR_S2_INT | \
+                                IOC4_SIO_IR_S2_TX_EXPLICIT)
+#define IOC4_SIO_IR_S3         (IOC4_SIO_IR_S3_TX_MT | \
+                                IOC4_SIO_IR_S3_RX_FULL | \
+                                IOC4_SIO_IR_S3_RX_HIGH | \
+                                IOC4_SIO_IR_S3_RX_TIMER | \
+                                IOC4_SIO_IR_S3_DELTA_DCD | \
+                                IOC4_SIO_IR_S3_DELTA_CTS | \
+                                IOC4_SIO_IR_S3_INT | \
+                                IOC4_SIO_IR_S3_TX_EXPLICIT)
+
+/* Bitmasks for IOC4_OTHER_IR, IOC4_OTHER_IEC, and IOC4_OTHER_IES  */
+#define IOC4_OTHER_IR_ATA_INT          0x00000001  /* ATAPI intr pass-thru */
+#define IOC4_OTHER_IR_ATA_MEMERR       0x00000002  /* ATAPI DMA PCI error */
+#define IOC4_OTHER_IR_S0_MEMERR                0x00000004  /* Port 0 PCI error */
+#define IOC4_OTHER_IR_S1_MEMERR                0x00000008  /* Port 1 PCI error */
+#define IOC4_OTHER_IR_S2_MEMERR                0x00000010  /* Port 2 PCI error */
+#define IOC4_OTHER_IR_S3_MEMERR                0x00000020  /* Port 3 PCI error */
+#define IOC4_OTHER_IR_KBD_INT          0x00000040  /* Keyboard/mouse */
+#define IOC4_OTHER_IR_RESERVED         0x007fff80  /* Reserved */
+#define IOC4_OTHER_IR_RT_INT           0x00800000  /* INT_OUT section output */
+#define IOC4_OTHER_IR_GEN_INT          0xff000000  /* Generic pins */
+
+#define IOC4_OTHER_IR_SER_MEMERR (IOC4_OTHER_IR_S0_MEMERR | IOC4_OTHER_IR_S1_MEMERR | \
+                                 IOC4_OTHER_IR_S2_MEMERR | IOC4_OTHER_IR_S3_MEMERR)
+
+/* Bitmasks for IOC4_SIO_CR */
+#define IOC4_SIO_CR_CMD_PULSE_SHIFT              0  /* byte bus strobe shift */
+#define IOC4_SIO_CR_ARB_DIAG_TX0       0x00000000
+#define IOC4_SIO_CR_ARB_DIAG_RX0       0x00000010
+#define IOC4_SIO_CR_ARB_DIAG_TX1       0x00000020
+#define IOC4_SIO_CR_ARB_DIAG_RX1       0x00000030
+#define IOC4_SIO_CR_ARB_DIAG_TX2       0x00000040
+#define IOC4_SIO_CR_ARB_DIAG_RX2       0x00000050
+#define IOC4_SIO_CR_ARB_DIAG_TX3       0x00000060
+#define IOC4_SIO_CR_ARB_DIAG_RX3       0x00000070
+#define IOC4_SIO_CR_SIO_DIAG_IDLE      0x00000080  /* 0 -> active request among
+                                                          serial ports (ro) */
+/* Defs for some of the generic I/O pins */
+#define IOC4_GPCR_UART0_MODESEL           0x10 /* Pin is output to port 0
+                                                  mode sel */
+#define IOC4_GPCR_UART1_MODESEL           0x20 /* Pin is output to port 1
+                                                  mode sel */
+#define IOC4_GPCR_UART2_MODESEL           0x40 /* Pin is output to port 2
+                                                  mode sel */
+#define IOC4_GPCR_UART3_MODESEL           0x80 /* Pin is output to port 3
+                                                  mode sel */
+
+#define IOC4_GPPR_UART0_MODESEL_PIN   4        /* GIO pin controlling
+                                          uart 0 mode select */
+#define IOC4_GPPR_UART1_MODESEL_PIN   5        /* GIO pin controlling
+                                          uart 1 mode select */
+#define IOC4_GPPR_UART2_MODESEL_PIN   6        /* GIO pin controlling
+                                          uart 2 mode select */
+#define IOC4_GPPR_UART3_MODESEL_PIN   7        /* GIO pin controlling
+                                          uart 3 mode select */
+
+/* Bitmasks for serial RX status byte */
+#define IOC4_RXSB_OVERRUN       0x01   /* Char(s) lost */
+#define IOC4_RXSB_PAR_ERR      0x02    /* Parity error */
+#define IOC4_RXSB_FRAME_ERR    0x04    /* Framing error */
+#define IOC4_RXSB_BREAK                0x08    /* Break character */
+#define IOC4_RXSB_CTS          0x10    /* State of CTS */
+#define IOC4_RXSB_DCD          0x20    /* State of DCD */
+#define IOC4_RXSB_MODEM_VALID   0x40   /* DCD, CTS, and OVERRUN are valid */
+#define IOC4_RXSB_DATA_VALID    0x80   /* Data byte, FRAME_ERR PAR_ERR
+                                        * & BREAK valid */
+
+/* Bitmasks for serial TX control byte */
+#define IOC4_TXCB_INT_WHEN_DONE 0x20   /* Interrupt after this byte is sent */
+#define IOC4_TXCB_INVALID      0x00    /* Byte is invalid */
+#define IOC4_TXCB_VALID                0x40    /* Byte is valid */
+#define IOC4_TXCB_MCR          0x80    /* Data<7:0> to modem control reg */
+#define IOC4_TXCB_DELAY                0xc0    /* Delay data<7:0> mSec */
+
+/* Bitmasks for IOC4_SBBR_L */
+#define IOC4_SBBR_L_SIZE       0x00000001  /* 0 == 1KB rings, 1 == 4KB rings */
+
+/* Bitmasks for IOC4_SSCR_<3:0> */
+#define IOC4_SSCR_RX_THRESHOLD  0x000001ff  /* Hiwater mark */
+#define IOC4_SSCR_TX_TIMER_BUSY 0x00010000  /* TX timer in progress */
+#define IOC4_SSCR_HFC_EN       0x00020000  /* Hardware flow control enabled */
+#define IOC4_SSCR_RX_RING_DCD   0x00040000  /* Post RX record on delta-DCD */
+#define IOC4_SSCR_RX_RING_CTS   0x00080000  /* Post RX record on delta-CTS */
+#define IOC4_SSCR_DIAG         0x00200000  /* Bypass clock divider for sim */
+#define IOC4_SSCR_RX_DRAIN     0x08000000  /* Drain RX buffer to memory */
+#define IOC4_SSCR_DMA_EN       0x10000000  /* Enable ring buffer DMA */
+#define IOC4_SSCR_DMA_PAUSE    0x20000000  /* Pause DMA */
+#define IOC4_SSCR_PAUSE_STATE   0x40000000  /* Sets when PAUSE takes effect */
+#define IOC4_SSCR_RESET                0x80000000  /* Reset DMA channels */
+
+/* All producer/comsumer pointers are the same bitfield */
+#define IOC4_PROD_CONS_PTR_4K   0x00000ff8     /* For 4K buffers */
+#define IOC4_PROD_CONS_PTR_1K   0x000003f8     /* For 1K buffers */
+#define IOC4_PROD_CONS_PTR_OFF           3
+
+/* Bitmasks for IOC4_SRCIR_<3:0> */
+#define IOC4_SRCIR_ARM         0x80000000      /* Arm RX timer */
+
+/* Bitmasks for IOC4_SHADOW_<3:0> */
+#define IOC4_SHADOW_DR  0x00000001     /* Data ready */
+#define IOC4_SHADOW_OE  0x00000002     /* Overrun error */
+#define IOC4_SHADOW_PE  0x00000004     /* Parity error */
+#define IOC4_SHADOW_FE  0x00000008     /* Framing error */
+#define IOC4_SHADOW_BI  0x00000010     /* Break interrupt */
+#define IOC4_SHADOW_THRE 0x00000020    /* Xmit holding register empty */
+#define IOC4_SHADOW_TEMT 0x00000040    /* Xmit shift register empty */
+#define IOC4_SHADOW_RFCE 0x00000080    /* Char in RX fifo has an error */
+#define IOC4_SHADOW_DCTS 0x00010000    /* Delta clear to send */
+#define IOC4_SHADOW_DDCD 0x00080000    /* Delta data carrier detect */
+#define IOC4_SHADOW_CTS         0x00100000     /* Clear to send */
+#define IOC4_SHADOW_DCD         0x00800000     /* Data carrier detect */
+#define IOC4_SHADOW_DTR         0x01000000     /* Data terminal ready */
+#define IOC4_SHADOW_RTS         0x02000000     /* Request to send */
+#define IOC4_SHADOW_OUT1 0x04000000    /* 16550 OUT1 bit */
+#define IOC4_SHADOW_OUT2 0x08000000    /* 16550 OUT2 bit */
+#define IOC4_SHADOW_LOOP 0x10000000    /* Loopback enabled */
+
+/* Bitmasks for IOC4_SRTR_<3:0> */
+#define IOC4_SRTR_CNT          0x00000fff      /* Reload value for RX timer */
+#define IOC4_SRTR_CNT_VAL      0x0fff0000      /* Current value of RX timer */
+#define IOC4_SRTR_CNT_VAL_SHIFT         16
+#define IOC4_SRTR_HZ                 16000     /* SRTR clock frequency */
+
+/* Serial port register map used for DMA and PIO serial I/O */
+struct ioc4_serialregs {
+       uint32_t sscr;
+       uint32_t stpir;
+       uint32_t stcir;
+       uint32_t srpir;
+       uint32_t srcir;
+       uint32_t srtr;
+       uint32_t shadow;
+};
+
+/* IOC4 UART register map */
+struct ioc4_uartregs {
+       char i4u_lcr;
+       union {
+               char iir;       /* read only */
+               char fcr;       /* write only */
+       } u3;
+       union {
+               char ier;       /* DLAB == 0 */
+               char dlm;       /* DLAB == 1 */
+       } u2;
+       union {
+               char rbr;       /* read only, DLAB == 0 */
+               char thr;       /* write only, DLAB == 0 */
+               char dll;       /* DLAB == 1 */
+       } u1;
+       char i4u_scr;
+       char i4u_msr;
+       char i4u_lsr;
+       char i4u_mcr;
+};
+
+/* short names */
+#define i4u_dll u1.dll
+#define i4u_ier u2.ier
+#define i4u_dlm u2.dlm
+#define i4u_fcr u3.fcr
+
+/* Serial port registers used for DMA serial I/O */
+struct ioc4_serial {
+       uint32_t sbbr01_l;
+       uint32_t sbbr01_h;
+       uint32_t sbbr23_l;
+       uint32_t sbbr23_h;
+
+       struct ioc4_serialregs port_0;
+       struct ioc4_serialregs port_1;
+       struct ioc4_serialregs port_2;
+       struct ioc4_serialregs port_3;
+       struct ioc4_uartregs uart_0;
+       struct ioc4_uartregs uart_1;
+       struct ioc4_uartregs uart_2;
+       struct ioc4_uartregs uart_3;
+} ioc4_serial;
+
+/* UART clock speed */
+#define IOC4_SER_XIN_CLK_66     66666667
+#define IOC4_SER_XIN_CLK_33     33333333
+
+#define IOC4_W_IES             0
+#define IOC4_W_IEC             1
+
+typedef void ioc4_intr_func_f(void *, uint32_t);
+typedef ioc4_intr_func_f *ioc4_intr_func_t;
+
+static unsigned int Num_of_ioc4_cards;
+
+/* defining this will get you LOTS of great debug info */
+//#define DEBUG_INTERRUPTS
+#define DPRINT_CONFIG(_x...)   ;
+//#define DPRINT_CONFIG(_x...) printk _x
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS   256
+
+/* number of characters we want to transmit to the lower level at a time */
+#define IOC4_MAX_CHARS 256
+#define IOC4_FIFO_CHARS        255
+
+/* Device name we're using */
+#define DEVICE_NAME_RS232  "ttyIOC"
+#define DEVICE_NAME_RS422  "ttyAIOC"
+#define DEVICE_MAJOR      204
+#define DEVICE_MINOR_RS232 50
+#define DEVICE_MINOR_RS422 84
+
+
+/* register offsets */
+#define IOC4_SERIAL_OFFSET     0x300
+
+/* flags for next_char_state */
+#define NCS_BREAK      0x1
+#define NCS_PARITY     0x2
+#define NCS_FRAMING    0x4
+#define NCS_OVERRUN    0x8
+
+/* cause we need SOME parameters ... */
+#define MIN_BAUD_SUPPORTED     1200
+#define MAX_BAUD_SUPPORTED     115200
+
+/* protocol types supported */
+#define PROTO_RS232    3
+#define PROTO_RS422    7
+
+/* Notification types */
+#define N_DATA_READY   0x01
+#define N_OUTPUT_LOWAT 0x02
+#define N_BREAK                0x04
+#define N_PARITY_ERROR 0x08
+#define N_FRAMING_ERROR        0x10
+#define N_OVERRUN_ERROR        0x20
+#define N_DDCD         0x40
+#define N_DCTS         0x80
+
+#define N_ALL_INPUT    (N_DATA_READY | N_BREAK |                       \
+                        N_PARITY_ERROR | N_FRAMING_ERROR |             \
+                        N_OVERRUN_ERROR | N_DDCD | N_DCTS)
+
+#define N_ALL_OUTPUT   N_OUTPUT_LOWAT
+
+#define N_ALL_ERRORS   (N_PARITY_ERROR | N_FRAMING_ERROR | N_OVERRUN_ERROR)
+
+#define N_ALL          (N_DATA_READY | N_OUTPUT_LOWAT | N_BREAK |      \
+                        N_PARITY_ERROR | N_FRAMING_ERROR |             \
+                        N_OVERRUN_ERROR | N_DDCD | N_DCTS)
+
+#define SER_DIVISOR(_x, clk)           (((clk) + (_x) * 8) / ((_x) * 16))
+#define DIVISOR_TO_BAUD(div, clk)      ((clk) / 16 / (div))
+
+/* Some masks */
+#define LCR_MASK_BITS_CHAR     (UART_LCR_WLEN5 | UART_LCR_WLEN6 \
+                                       | UART_LCR_WLEN7 | UART_LCR_WLEN8)
+#define LCR_MASK_STOP_BITS     (UART_LCR_STOP)
+
+#define PENDING(_p)    (readl(&(_p)->ip_mem->sio_ir.raw) & _p->ip_ienb)
+#define READ_SIO_IR(_p) readl(&(_p)->ip_mem->sio_ir.raw)
+
+/* Default to 4k buffers */
+#ifdef IOC4_1K_BUFFERS
+#define RING_BUF_SIZE 1024
+#define IOC4_BUF_SIZE_BIT 0
+#define PROD_CONS_MASK IOC4_PROD_CONS_PTR_1K
+#else
+#define RING_BUF_SIZE 4096
+#define IOC4_BUF_SIZE_BIT IOC4_SBBR_L_SIZE
+#define PROD_CONS_MASK IOC4_PROD_CONS_PTR_4K
+#endif
+
+#define TOTAL_RING_BUF_SIZE (RING_BUF_SIZE * 4)
+
+/*
+ * This is the entry saved by the driver - one per card
+ */
+
+#define UART_PORT_MIN          0
+#define UART_PORT_RS232                UART_PORT_MIN
+#define UART_PORT_RS422                1
+#define UART_PORT_COUNT                2       /* one for each mode */
+
+struct ioc4_control {
+       int ic_irq;
+       struct {
+               /* uart ports are allocated here - 1 for rs232, 1 for rs422 */
+               struct uart_port icp_uart_port[UART_PORT_COUNT];
+               /* Handy reference material */
+               struct ioc4_port *icp_port;
+       } ic_port[IOC4_NUM_SERIAL_PORTS];
+       struct ioc4_soft *ic_soft;
+};
+
+/*
+ * per-IOC4 data structure
+ */
+#define MAX_IOC4_INTR_ENTS     (8 * sizeof(uint32_t))
+struct ioc4_soft {
+       struct ioc4_misc_regs __iomem *is_ioc4_misc_addr;
+       struct ioc4_serial __iomem *is_ioc4_serial_addr;
+
+       /* Each interrupt type has an entry in the array */
+       struct ioc4_intr_type {
+
+               /*
+                * Each in-use entry in this array contains at least
+                * one nonzero bit in sd_bits; no two entries in this
+                * array have overlapping sd_bits values.
+                */
+               struct ioc4_intr_info {
+                       uint32_t sd_bits;
+                       ioc4_intr_func_f *sd_intr;
+                       void *sd_info;
+               } is_intr_info[MAX_IOC4_INTR_ENTS];
+
+               /* Number of entries active in the above array */
+               atomic_t is_num_intrs;
+       } is_intr_type[IOC4_NUM_INTR_TYPES];
+
+       /* is_ir_lock must be held while
+        * modifying sio_ie values, so
+        * we can be sure that sio_ie is
+        * not changing when we read it
+        * along with sio_ir.
+        */
+       spinlock_t is_ir_lock;  /* SIO_IE[SC] mod lock */
+};
+
+/* Local port info for each IOC4 serial ports */
+struct ioc4_port {
+       struct uart_port *ip_port;      /* current active port ptr */
+       /* Ptrs for all ports */
+       struct uart_port *ip_all_ports[UART_PORT_COUNT];
+       /* Back ptrs for this port */
+       struct ioc4_control *ip_control;
+       struct pci_dev *ip_pdev;
+       struct ioc4_soft *ip_ioc4_soft;
+
+       /* pci mem addresses */
+       struct ioc4_misc_regs __iomem *ip_mem;
+       struct ioc4_serial __iomem *ip_serial;
+       struct ioc4_serialregs __iomem *ip_serial_regs;
+       struct ioc4_uartregs __iomem *ip_uart_regs;
+
+       /* Ring buffer page for this port */
+       dma_addr_t ip_dma_ringbuf;
+       /* vaddr of ring buffer */
+       struct ring_buffer *ip_cpu_ringbuf;
+
+       /* Rings for this port */
+       struct ring *ip_inring;
+       struct ring *ip_outring;
+
+       /* Hook to port specific values */
+       struct hooks *ip_hooks;
+
+       spinlock_t ip_lock;
+
+       /* Various rx/tx parameters */
+       int ip_baud;
+       int ip_tx_lowat;
+       int ip_rx_timeout;
+
+       /* Copy of notification bits */
+       int ip_notify;
+
+       /* Shadow copies of various registers so we don't need to PIO
+        * read them constantly
+        */
+       uint32_t ip_ienb;       /* Enabled interrupts */
+       uint32_t ip_sscr;
+       uint32_t ip_tx_prod;
+       uint32_t ip_rx_cons;
+       int ip_pci_bus_speed;
+       unsigned char ip_flags;
+};
+
+/* tx low water mark.  We need to notify the driver whenever tx is getting
+ * close to empty so it can refill the tx buffer and keep things going.
+ * Let's assume that if we interrupt 1 ms before the tx goes idle, we'll
+ * have no trouble getting in more chars in time (I certainly hope so).
+ */
+#define TX_LOWAT_LATENCY      1000
+#define TX_LOWAT_HZ          (1000000 / TX_LOWAT_LATENCY)
+#define TX_LOWAT_CHARS(baud) (baud / 10 / TX_LOWAT_HZ)
+
+/* Flags per port */
+#define INPUT_HIGH     0x01
+#define DCD_ON         0x02
+#define LOWAT_WRITTEN  0x04
+#define READ_ABORTED   0x08
+#define PORT_ACTIVE    0x10
+#define PORT_INACTIVE  0       /* This is the value when "off" */
+
+
+/* Since each port has different register offsets and bitmasks
+ * for everything, we'll store those that we need in tables so we
+ * don't have to be constantly checking the port we are dealing with.
+ */
+struct hooks {
+       uint32_t intr_delta_dcd;
+       uint32_t intr_delta_cts;
+       uint32_t intr_tx_mt;
+       uint32_t intr_rx_timer;
+       uint32_t intr_rx_high;
+       uint32_t intr_tx_explicit;
+       uint32_t intr_dma_error;
+       uint32_t intr_clear;
+       uint32_t intr_all;
+       int rs422_select_pin;
+};
+
+static struct hooks hooks_array[IOC4_NUM_SERIAL_PORTS] = {
+       /* Values for port 0 */
+       {
+        IOC4_SIO_IR_S0_DELTA_DCD, IOC4_SIO_IR_S0_DELTA_CTS,
+        IOC4_SIO_IR_S0_TX_MT, IOC4_SIO_IR_S0_RX_TIMER,
+        IOC4_SIO_IR_S0_RX_HIGH, IOC4_SIO_IR_S0_TX_EXPLICIT,
+        IOC4_OTHER_IR_S0_MEMERR,
+        (IOC4_SIO_IR_S0_TX_MT | IOC4_SIO_IR_S0_RX_FULL |
+         IOC4_SIO_IR_S0_RX_HIGH | IOC4_SIO_IR_S0_RX_TIMER |
+         IOC4_SIO_IR_S0_DELTA_DCD | IOC4_SIO_IR_S0_DELTA_CTS |
+         IOC4_SIO_IR_S0_INT | IOC4_SIO_IR_S0_TX_EXPLICIT),
+        IOC4_SIO_IR_S0, IOC4_GPPR_UART0_MODESEL_PIN,
+        },
+
+       /* Values for port 1 */
+       {
+        IOC4_SIO_IR_S1_DELTA_DCD, IOC4_SIO_IR_S1_DELTA_CTS,
+        IOC4_SIO_IR_S1_TX_MT, IOC4_SIO_IR_S1_RX_TIMER,
+        IOC4_SIO_IR_S1_RX_HIGH, IOC4_SIO_IR_S1_TX_EXPLICIT,
+        IOC4_OTHER_IR_S1_MEMERR,
+        (IOC4_SIO_IR_S1_TX_MT | IOC4_SIO_IR_S1_RX_FULL |
+         IOC4_SIO_IR_S1_RX_HIGH | IOC4_SIO_IR_S1_RX_TIMER |
+         IOC4_SIO_IR_S1_DELTA_DCD | IOC4_SIO_IR_S1_DELTA_CTS |
+         IOC4_SIO_IR_S1_INT | IOC4_SIO_IR_S1_TX_EXPLICIT),
+        IOC4_SIO_IR_S1, IOC4_GPPR_UART1_MODESEL_PIN,
+        },
+
+       /* Values for port 2 */
+       {
+        IOC4_SIO_IR_S2_DELTA_DCD, IOC4_SIO_IR_S2_DELTA_CTS,
+        IOC4_SIO_IR_S2_TX_MT, IOC4_SIO_IR_S2_RX_TIMER,
+        IOC4_SIO_IR_S2_RX_HIGH, IOC4_SIO_IR_S2_TX_EXPLICIT,
+        IOC4_OTHER_IR_S2_MEMERR,
+        (IOC4_SIO_IR_S2_TX_MT | IOC4_SIO_IR_S2_RX_FULL |
+         IOC4_SIO_IR_S2_RX_HIGH | IOC4_SIO_IR_S2_RX_TIMER |
+         IOC4_SIO_IR_S2_DELTA_DCD | IOC4_SIO_IR_S2_DELTA_CTS |
+         IOC4_SIO_IR_S2_INT | IOC4_SIO_IR_S2_TX_EXPLICIT),
+        IOC4_SIO_IR_S2, IOC4_GPPR_UART2_MODESEL_PIN,
+        },
+
+       /* Values for port 3 */
+       {
+        IOC4_SIO_IR_S3_DELTA_DCD, IOC4_SIO_IR_S3_DELTA_CTS,
+        IOC4_SIO_IR_S3_TX_MT, IOC4_SIO_IR_S3_RX_TIMER,
+        IOC4_SIO_IR_S3_RX_HIGH, IOC4_SIO_IR_S3_TX_EXPLICIT,
+        IOC4_OTHER_IR_S3_MEMERR,
+        (IOC4_SIO_IR_S3_TX_MT | IOC4_SIO_IR_S3_RX_FULL |
+         IOC4_SIO_IR_S3_RX_HIGH | IOC4_SIO_IR_S3_RX_TIMER |
+         IOC4_SIO_IR_S3_DELTA_DCD | IOC4_SIO_IR_S3_DELTA_CTS |
+         IOC4_SIO_IR_S3_INT | IOC4_SIO_IR_S3_TX_EXPLICIT),
+        IOC4_SIO_IR_S3, IOC4_GPPR_UART3_MODESEL_PIN,
+        }
+};
+
+/* A ring buffer entry */
+struct ring_entry {
+       union {
+               struct {
+                       uint32_t alldata;
+                       uint32_t allsc;
+               } all;
+               struct {
+                       char data[4];   /* data bytes */
+                       char sc[4];     /* status/control */
+               } s;
+       } u;
+};
+
+/* Test the valid bits in any of the 4 sc chars using "allsc" member */
+#define RING_ANY_VALID \
+       ((uint32_t)(IOC4_RXSB_MODEM_VALID | IOC4_RXSB_DATA_VALID) * 0x01010101)
+
+#define ring_sc     u.s.sc
+#define ring_data   u.s.data
+#define ring_allsc  u.all.allsc
+
+/* Number of entries per ring buffer. */
+#define ENTRIES_PER_RING (RING_BUF_SIZE / (int) sizeof(struct ring_entry))
+
+/* An individual ring */
+struct ring {
+       struct ring_entry entries[ENTRIES_PER_RING];
+};
+
+/* The whole enchilada */
+struct ring_buffer {
+       struct ring TX_0_OR_2;
+       struct ring RX_0_OR_2;
+       struct ring TX_1_OR_3;
+       struct ring RX_1_OR_3;
+};
+
+/* Get a ring from a port struct */
+#define RING(_p, _wh)  &(((struct ring_buffer *)((_p)->ip_cpu_ringbuf))->_wh)
+
+/* Infinite loop detection.
+ */
+#define MAXITER 10000000
+
+/* Prototypes */
+static void receive_chars(struct uart_port *);
+static void handle_intr(void *arg, uint32_t sio_ir);
+
+/*
+ * port_is_active - determines if this port is currently active
+ * @port: ptr to soft struct for this port
+ * @uart_port: uart port to test for
+ */
+static inline int port_is_active(struct ioc4_port *port,
+               struct uart_port *uart_port)
+{
+       if (port) {
+               if ((port->ip_flags & PORT_ACTIVE)
+                                       && (port->ip_port == uart_port))
+                       return 1;
+       }
+       return 0;
+}
+
+
+/**
+ * write_ireg - write the interrupt regs
+ * @ioc4_soft: ptr to soft struct for this port
+ * @val: value to write
+ * @which: which register
+ * @type: which ireg set
+ */
+static inline void
+write_ireg(struct ioc4_soft *ioc4_soft, uint32_t val, int which, int type)
+{
+       struct ioc4_misc_regs __iomem *mem = ioc4_soft->is_ioc4_misc_addr;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioc4_soft->is_ir_lock, flags);
+
+       switch (type) {
+       case IOC4_SIO_INTR_TYPE:
+               switch (which) {
+               case IOC4_W_IES:
+                       writel(val, &mem->sio_ies.raw);
+                       break;
+
+               case IOC4_W_IEC:
+                       writel(val, &mem->sio_iec.raw);
+                       break;
+               }
+               break;
+
+       case IOC4_OTHER_INTR_TYPE:
+               switch (which) {
+               case IOC4_W_IES:
+                       writel(val, &mem->other_ies.raw);
+                       break;
+
+               case IOC4_W_IEC:
+                       writel(val, &mem->other_iec.raw);
+                       break;
+               }
+               break;
+
+       default:
+               break;
+       }
+       spin_unlock_irqrestore(&ioc4_soft->is_ir_lock, flags);
+}
+
+/**
+ * set_baud - Baud rate setting code
+ * @port: port to set
+ * @baud: baud rate to use
+ */
+static int set_baud(struct ioc4_port *port, int baud)
+{
+       int actual_baud;
+       int diff;
+       int lcr;
+       unsigned short divisor;
+       struct ioc4_uartregs __iomem *uart;
+
+       divisor = SER_DIVISOR(baud, port->ip_pci_bus_speed);
+       if (!divisor)
+               return 1;
+       actual_baud = DIVISOR_TO_BAUD(divisor, port->ip_pci_bus_speed);
+
+       diff = actual_baud - baud;
+       if (diff < 0)
+               diff = -diff;
+
+       /* If we're within 1%, we've found a match */
+       if (diff * 100 > actual_baud)
+               return 1;
+
+       uart = port->ip_uart_regs;
+       lcr = readb(&uart->i4u_lcr);
+       writeb(lcr | UART_LCR_DLAB, &uart->i4u_lcr);
+       writeb((unsigned char)divisor, &uart->i4u_dll);
+       writeb((unsigned char)(divisor >> 8), &uart->i4u_dlm);
+       writeb(lcr, &uart->i4u_lcr);
+       return 0;
+}
+
+
+/**
+ * get_ioc4_port - given a uart port, return the control structure
+ * @port: uart port
+ * @set: set this port as current
+ */
+static struct ioc4_port *get_ioc4_port(struct uart_port *the_port, int set)
+{
+       struct ioc4_driver_data *idd = dev_get_drvdata(the_port->dev);
+       struct ioc4_control *control = idd->idd_serial_data;
+       struct ioc4_port *port;
+       int port_num, port_type;
+
+       if (control) {
+               for ( port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS;
+                                                       port_num++ ) {
+                       port = control->ic_port[port_num].icp_port;
+                       if (!port)
+                               continue;
+                       for (port_type = UART_PORT_MIN;
+                                               port_type < UART_PORT_COUNT;
+                                               port_type++) {
+                               if (the_port == port->ip_all_ports
+                                                       [port_type]) {
+                                       /* set local copy */
+                                       if (set) {
+                                               port->ip_port = the_port;
+                                       }
+                                       return port;
+                               }
+                       }
+               }
+       }
+       return NULL;
+}
+
+/* The IOC4 hardware provides no atomic way to determine if interrupts
+ * are pending since two reads are required to do so.  The handler must
+ * read the SIO_IR and the SIO_IES, and take the logical and of the
+ * two.  When this value is zero, all interrupts have been serviced and
+ * the handler may return.
+ *
+ * This has the unfortunate "hole" that, if some other CPU or
+ * some other thread or some higher level interrupt manages to
+ * modify SIO_IE between our reads of SIO_IR and SIO_IE, we may
+ * think we have observed SIO_IR&SIO_IE==0 when in fact this
+ * condition never really occurred.
+ *
+ * To solve this, we use a simple spinlock that must be held
+ * whenever modifying SIO_IE; holding this lock while observing
+ * both SIO_IR and SIO_IE guarantees that we do not falsely
+ * conclude that no enabled interrupts are pending.
+ */
+
+static inline uint32_t
+pending_intrs(struct ioc4_soft *soft, int type)
+{
+       struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr;
+       unsigned long flag;
+       uint32_t intrs = 0;
+
+       BUG_ON(!((type == IOC4_SIO_INTR_TYPE)
+              || (type == IOC4_OTHER_INTR_TYPE)));
+
+       spin_lock_irqsave(&soft->is_ir_lock, flag);
+
+       switch (type) {
+       case IOC4_SIO_INTR_TYPE:
+               intrs = readl(&mem->sio_ir.raw) & readl(&mem->sio_ies.raw);
+               break;
+
+       case IOC4_OTHER_INTR_TYPE:
+               intrs = readl(&mem->other_ir.raw) & readl(&mem->other_ies.raw);
+
+               /* Don't process any ATA interrupte */
+               intrs &= ~(IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR);
+               break;
+
+       default:
+               break;
+       }
+       spin_unlock_irqrestore(&soft->is_ir_lock, flag);
+       return intrs;
+}
+
+/**
+ * port_init - Initialize the sio and ioc4 hardware for a given port
+ *                     called per port from attach...
+ * @port: port to initialize
+ */
+static int inline port_init(struct ioc4_port *port)
+{
+       uint32_t sio_cr;
+       struct hooks *hooks = port->ip_hooks;
+       struct ioc4_uartregs __iomem *uart;
+
+       /* Idle the IOC4 serial interface */
+       writel(IOC4_SSCR_RESET, &port->ip_serial_regs->sscr);
+
+       /* Wait until any pending bus activity for this port has ceased */
+       do
+               sio_cr = readl(&port->ip_mem->sio_cr.raw);
+       while (!(sio_cr & IOC4_SIO_CR_SIO_DIAG_IDLE));
+
+       /* Finish reset sequence */
+       writel(0, &port->ip_serial_regs->sscr);
+
+       /* Once RESET is done, reload cached tx_prod and rx_cons values
+        * and set rings to empty by making prod == cons
+        */
+       port->ip_tx_prod = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
+       writel(port->ip_tx_prod, &port->ip_serial_regs->stpir);
+       port->ip_rx_cons = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
+       writel(port->ip_rx_cons | IOC4_SRCIR_ARM, &port->ip_serial_regs->srcir);
+
+       /* Disable interrupts for this 16550 */
+       uart = port->ip_uart_regs;
+       writeb(0, &uart->i4u_lcr);
+       writeb(0, &uart->i4u_ier);
+
+       /* Set the default baud */
+       set_baud(port, port->ip_baud);
+
+       /* Set line control to 8 bits no parity */
+       writeb(UART_LCR_WLEN8 | 0, &uart->i4u_lcr);
+                                       /* UART_LCR_STOP == 1 stop */
+
+       /* Enable the FIFOs */
+       writeb(UART_FCR_ENABLE_FIFO, &uart->i4u_fcr);
+       /* then reset 16550 FIFOs */
+       writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
+                       &uart->i4u_fcr);
+
+       /* Clear modem control register */
+       writeb(0, &uart->i4u_mcr);
+
+       /* Clear deltas in modem status register */
+       readb(&uart->i4u_msr);
+
+       /* Only do this once per port pair */
+       if (port->ip_hooks == &hooks_array[0]
+                           || port->ip_hooks == &hooks_array[2]) {
+               unsigned long ring_pci_addr;
+               uint32_t __iomem *sbbr_l;
+               uint32_t __iomem *sbbr_h;
+
+               if (port->ip_hooks == &hooks_array[0]) {
+                       sbbr_l = &port->ip_serial->sbbr01_l;
+                       sbbr_h = &port->ip_serial->sbbr01_h;
+               } else {
+                       sbbr_l = &port->ip_serial->sbbr23_l;
+                       sbbr_h = &port->ip_serial->sbbr23_h;
+               }
+
+               ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf;
+               DPRINT_CONFIG(("%s: ring_pci_addr 0x%lx\n",
+                                       __func__, ring_pci_addr));
+
+               writel((unsigned int)((uint64_t)ring_pci_addr >> 32), sbbr_h);
+               writel((unsigned int)ring_pci_addr | IOC4_BUF_SIZE_BIT, sbbr_l);
+       }
+
+       /* Set the receive timeout value to 10 msec */
+       writel(IOC4_SRTR_HZ / 100, &port->ip_serial_regs->srtr);
+
+       /* Set rx threshold, enable DMA */
+       /* Set high water mark at 3/4 of full ring */
+       port->ip_sscr = (ENTRIES_PER_RING * 3 / 4);
+       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+
+       /* Disable and clear all serial related interrupt bits */
+       write_ireg(port->ip_ioc4_soft, hooks->intr_clear,
+                      IOC4_W_IEC, IOC4_SIO_INTR_TYPE);
+       port->ip_ienb &= ~hooks->intr_clear;
+       writel(hooks->intr_clear, &port->ip_mem->sio_ir.raw);
+       return 0;
+}
+
+/**
+ * handle_dma_error_intr - service any pending DMA error interrupts for the
+ *                     given port - 2nd level called via sd_intr
+ * @arg: handler arg
+ * @other_ir: ioc4regs
+ */
+static void handle_dma_error_intr(void *arg, uint32_t other_ir)
+{
+       struct ioc4_port *port = (struct ioc4_port *)arg;
+       struct hooks *hooks = port->ip_hooks;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->ip_lock, flags);
+
+       /* ACK the interrupt */
+       writel(hooks->intr_dma_error, &port->ip_mem->other_ir.raw);
+
+       if (readl(&port->ip_mem->pci_err_addr_l.raw) & IOC4_PCI_ERR_ADDR_VLD) {
+               printk(KERN_ERR
+                       "PCI error address is 0x%llx, "
+                               "master is serial port %c %s\n",
+                    (((uint64_t)readl(&port->ip_mem->pci_err_addr_h)
+                                                        << 32)
+                               | readl(&port->ip_mem->pci_err_addr_l.raw))
+                                       & IOC4_PCI_ERR_ADDR_ADDR_MSK, '1' +
+                    ((char)(readl(&port->ip_mem->pci_err_addr_l.raw) &
+                            IOC4_PCI_ERR_ADDR_MST_NUM_MSK) >> 1),
+                    (readl(&port->ip_mem->pci_err_addr_l.raw)
+                               & IOC4_PCI_ERR_ADDR_MST_TYP_MSK)
+                               ? "RX" : "TX");
+
+               if (readl(&port->ip_mem->pci_err_addr_l.raw)
+                                               & IOC4_PCI_ERR_ADDR_MUL_ERR) {
+                       printk(KERN_ERR
+                               "Multiple errors occurred\n");
+               }
+       }
+       spin_unlock_irqrestore(&port->ip_lock, flags);
+
+       /* Re-enable DMA error interrupts */
+       write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error, IOC4_W_IES,
+                                               IOC4_OTHER_INTR_TYPE);
+}
+
+/**
+ * intr_connect - interrupt connect function
+ * @soft: soft struct for this card
+ * @type: interrupt type
+ * @intrbits: bit pattern to set
+ * @intr: handler function
+ * @info: handler arg
+ */
+static void
+intr_connect(struct ioc4_soft *soft, int type,
+                 uint32_t intrbits, ioc4_intr_func_f * intr, void *info)
+{
+       int i;
+       struct ioc4_intr_info *intr_ptr;
+
+       BUG_ON(!((type == IOC4_SIO_INTR_TYPE)
+              || (type == IOC4_OTHER_INTR_TYPE)));
+
+       i = atomic_inc(&soft-> is_intr_type[type].is_num_intrs) - 1;
+       BUG_ON(!(i < MAX_IOC4_INTR_ENTS || (printk("i %d\n", i), 0)));
+
+       /* Save off the lower level interrupt handler */
+       intr_ptr = &soft->is_intr_type[type].is_intr_info[i];
+       intr_ptr->sd_bits = intrbits;
+       intr_ptr->sd_intr = intr;
+       intr_ptr->sd_info = info;
+}
+
+/**
+ * ioc4_intr - Top level IOC4 interrupt handler.
+ * @irq: irq value
+ * @arg: handler arg
+ */
+
+static irqreturn_t ioc4_intr(int irq, void *arg)
+{
+       struct ioc4_soft *soft;
+       uint32_t this_ir, this_mir;
+       int xx, num_intrs = 0;
+       int intr_type;
+       int handled = 0;
+       struct ioc4_intr_info *intr_info;
+
+       soft = arg;
+       for (intr_type = 0; intr_type < IOC4_NUM_INTR_TYPES; intr_type++) {
+               num_intrs = (int)atomic_read(
+                               &soft->is_intr_type[intr_type].is_num_intrs);
+
+               this_mir = this_ir = pending_intrs(soft, intr_type);
+
+               /* Farm out the interrupt to the various drivers depending on
+                * which interrupt bits are set.
+                */
+               for (xx = 0; xx < num_intrs; xx++) {
+                       intr_info = &soft->is_intr_type[intr_type].is_intr_info[xx];
+                       if ((this_mir = this_ir & intr_info->sd_bits)) {
+                               /* Disable owned interrupts, call handler */
+                               handled++;
+                               write_ireg(soft, intr_info->sd_bits, IOC4_W_IEC,
+                                                               intr_type);
+                               intr_info->sd_intr(intr_info->sd_info, this_mir);
+                               this_ir &= ~this_mir;
+                       }
+               }
+       }
+#ifdef DEBUG_INTERRUPTS
+       {
+               struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr;
+               unsigned long flag;
+
+               spin_lock_irqsave(&soft->is_ir_lock, flag);
+               printk ("%s : %d : mem 0x%p sio_ir 0x%x sio_ies 0x%x "
+                               "other_ir 0x%x other_ies 0x%x mask 0x%x\n",
+                    __func__, __LINE__,
+                    (void *)mem, readl(&mem->sio_ir.raw),
+                    readl(&mem->sio_ies.raw),
+                    readl(&mem->other_ir.raw),
+                    readl(&mem->other_ies.raw),
+                    IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR);
+               spin_unlock_irqrestore(&soft->is_ir_lock, flag);
+       }
+#endif
+       return handled ? IRQ_HANDLED : IRQ_NONE;
+}
+
+/**
+ * ioc4_attach_local - Device initialization.
+ *                     Called at *_attach() time for each
+ *                     IOC4 with serial ports in the system.
+ * @idd: Master module data for this IOC4
+ */
+static int inline ioc4_attach_local(struct ioc4_driver_data *idd)
+{
+       struct ioc4_port *port;
+       struct ioc4_port *ports[IOC4_NUM_SERIAL_PORTS];
+       int port_number;
+       uint16_t ioc4_revid_min = 62;
+       uint16_t ioc4_revid;
+       struct pci_dev *pdev = idd->idd_pdev;
+       struct ioc4_control* control = idd->idd_serial_data;
+       struct ioc4_soft *soft = control->ic_soft;
+       void __iomem *ioc4_misc = idd->idd_misc_regs;
+       void __iomem *ioc4_serial = soft->is_ioc4_serial_addr;
+
+       /* IOC4 firmware must be at least rev 62 */
+       pci_read_config_word(pdev, PCI_COMMAND_SPECIAL, &ioc4_revid);
+
+       printk(KERN_INFO "IOC4 firmware revision %d\n", ioc4_revid);
+       if (ioc4_revid < ioc4_revid_min) {
+               printk(KERN_WARNING
+                   "IOC4 serial not supported on firmware rev %d, "
+                               "please upgrade to rev %d or higher\n",
+                               ioc4_revid, ioc4_revid_min);
+               return -EPERM;
+       }
+       BUG_ON(ioc4_misc == NULL);
+       BUG_ON(ioc4_serial == NULL);
+
+       /* Create port structures for each port */
+       for (port_number = 0; port_number < IOC4_NUM_SERIAL_PORTS;
+                                                       port_number++) {
+               port = kzalloc(sizeof(struct ioc4_port), GFP_KERNEL);
+               if (!port) {
+                       printk(KERN_WARNING
+                               "IOC4 serial memory not available for port\n");
+                       return -ENOMEM;
+               }
+               spin_lock_init(&port->ip_lock);
+
+               /* we need to remember the previous ones, to point back to
+                * them farther down - setting up the ring buffers.
+                */
+               ports[port_number] = port;
+
+               /* Allocate buffers and jumpstart the hardware.  */
+               control->ic_port[port_number].icp_port = port;
+               port->ip_ioc4_soft = soft;
+               port->ip_pdev = pdev;
+               port->ip_ienb = 0;
+               /* Use baud rate calculations based on detected PCI
+                * bus speed.  Simply test whether the PCI clock is
+                * running closer to 66MHz or 33MHz.
+                */
+               if (idd->count_period/IOC4_EXTINT_COUNT_DIVISOR < 20) {
+                       port->ip_pci_bus_speed = IOC4_SER_XIN_CLK_66;
+               } else {
+                       port->ip_pci_bus_speed = IOC4_SER_XIN_CLK_33;
+               }
+               port->ip_baud = 9600;
+               port->ip_control = control;
+               port->ip_mem = ioc4_misc;
+               port->ip_serial = ioc4_serial;
+
+               /* point to the right hook */
+               port->ip_hooks = &hooks_array[port_number];
+
+               /* Get direct hooks to the serial regs and uart regs
+                * for this port
+                */
+               switch (port_number) {
+               case 0:
+                       port->ip_serial_regs = &(port->ip_serial->port_0);
+                       port->ip_uart_regs = &(port->ip_serial->uart_0);
+                       break;
+               case 1:
+                       port->ip_serial_regs = &(port->ip_serial->port_1);
+                       port->ip_uart_regs = &(port->ip_serial->uart_1);
+                       break;
+               case 2:
+                       port->ip_serial_regs = &(port->ip_serial->port_2);
+                       port->ip_uart_regs = &(port->ip_serial->uart_2);
+                       break;
+               default:
+               case 3:
+                       port->ip_serial_regs = &(port->ip_serial->port_3);
+                       port->ip_uart_regs = &(port->ip_serial->uart_3);
+                       break;
+               }
+
+               /* ring buffers are 1 to a pair of ports */
+               if (port_number && (port_number & 1)) {
+                       /* odd use the evens buffer */
+                       port->ip_dma_ringbuf =
+                                       ports[port_number - 1]->ip_dma_ringbuf;
+                       port->ip_cpu_ringbuf =
+                                       ports[port_number - 1]->ip_cpu_ringbuf;
+                       port->ip_inring = RING(port, RX_1_OR_3);
+                       port->ip_outring = RING(port, TX_1_OR_3);
+
+               } else {
+                       if (port->ip_dma_ringbuf == 0) {
+                               port->ip_cpu_ringbuf = pci_alloc_consistent
+                                       (pdev, TOTAL_RING_BUF_SIZE,
+                                       &port->ip_dma_ringbuf);
+
+                       }
+                       BUG_ON(!((((int64_t)port->ip_dma_ringbuf) &
+                               (TOTAL_RING_BUF_SIZE - 1)) == 0));
+                       DPRINT_CONFIG(("%s : ip_cpu_ringbuf 0x%p "
+                                               "ip_dma_ringbuf 0x%p\n",
+                                       __func__,
+                                       (void *)port->ip_cpu_ringbuf,
+                                       (void *)port->ip_dma_ringbuf));
+                       port->ip_inring = RING(port, RX_0_OR_2);
+                       port->ip_outring = RING(port, TX_0_OR_2);
+               }
+               DPRINT_CONFIG(("%s : port %d [addr 0x%p] control 0x%p",
+                               __func__,
+                               port_number, (void *)port, (void *)control));
+               DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n",
+                               (void *)port->ip_serial_regs,
+                               (void *)port->ip_uart_regs));
+
+               /* Initialize the hardware for IOC4 */
+               port_init(port);
+
+               DPRINT_CONFIG(("%s: port_number %d port 0x%p inring 0x%p "
+                                               "outring 0x%p\n",
+                               __func__,
+                               port_number, (void *)port,
+                               (void *)port->ip_inring,
+                               (void *)port->ip_outring));
+
+               /* Attach interrupt handlers */
+               intr_connect(soft, IOC4_SIO_INTR_TYPE,
+                               GET_SIO_IR(port_number),
+                               handle_intr, port);
+
+               intr_connect(soft, IOC4_OTHER_INTR_TYPE,
+                               GET_OTHER_IR(port_number),
+                               handle_dma_error_intr, port);
+       }
+       return 0;
+}
+
+/**
+ * enable_intrs - enable interrupts
+ * @port: port to enable
+ * @mask: mask to use
+ */
+static void enable_intrs(struct ioc4_port *port, uint32_t mask)
+{
+       struct hooks *hooks = port->ip_hooks;
+
+       if ((port->ip_ienb & mask) != mask) {
+               write_ireg(port->ip_ioc4_soft, mask, IOC4_W_IES,
+                                               IOC4_SIO_INTR_TYPE);
+               port->ip_ienb |= mask;
+       }
+
+       if (port->ip_ienb)
+               write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error,
+                               IOC4_W_IES, IOC4_OTHER_INTR_TYPE);
+}
+
+/**
+ * local_open - local open a port
+ * @port: port to open
+ */
+static inline int local_open(struct ioc4_port *port)
+{
+       int spiniter = 0;
+
+       port->ip_flags = PORT_ACTIVE;
+
+       /* Pause the DMA interface if necessary */
+       if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
+               writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE,
+                       &port->ip_serial_regs->sscr);
+               while((readl(&port->ip_serial_regs-> sscr)
+                               & IOC4_SSCR_PAUSE_STATE) == 0) {
+                       spiniter++;
+                       if (spiniter > MAXITER) {
+                               port->ip_flags = PORT_INACTIVE;
+                               return -1;
+                       }
+               }
+       }
+
+       /* Reset the input fifo.  If the uart received chars while the port
+        * was closed and DMA is not enabled, the uart may have a bunch of
+        * chars hanging around in its rx fifo which will not be discarded
+        * by rclr in the upper layer. We must get rid of them here.
+        */
+       writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR,
+                               &port->ip_uart_regs->i4u_fcr);
+
+       writeb(UART_LCR_WLEN8, &port->ip_uart_regs->i4u_lcr);
+                                       /* UART_LCR_STOP == 1 stop */
+
+       /* Re-enable DMA, set default threshold to intr whenever there is
+        * data available.
+        */
+       port->ip_sscr &= ~IOC4_SSCR_RX_THRESHOLD;
+       port->ip_sscr |= 1;     /* default threshold */
+
+       /* Plug in the new sscr.  This implicitly clears the DMA_PAUSE
+        * flag if it was set above
+        */
+       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+       port->ip_tx_lowat = 1;
+       return 0;
+}
+
+/**
+ * set_rx_timeout - Set rx timeout and threshold values.
+ * @port: port to use
+ * @timeout: timeout value in ticks
+ */
+static inline int set_rx_timeout(struct ioc4_port *port, int timeout)
+{
+       int threshold;
+
+       port->ip_rx_timeout = timeout;
+
+       /* Timeout is in ticks.  Let's figure out how many chars we
+        * can receive at the current baud rate in that interval
+        * and set the rx threshold to that amount.  There are 4 chars
+        * per ring entry, so we'll divide the number of chars that will
+        * arrive in timeout by 4.
+        * So .... timeout * baud / 10 / HZ / 4, with HZ = 100.
+        */
+       threshold = timeout * port->ip_baud / 4000;
+       if (threshold == 0)
+               threshold = 1;  /* otherwise we'll intr all the time! */
+
+       if ((unsigned)threshold > (unsigned)IOC4_SSCR_RX_THRESHOLD)
+               return 1;
+
+       port->ip_sscr &= ~IOC4_SSCR_RX_THRESHOLD;
+       port->ip_sscr |= threshold;
+
+       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+
+       /* Now set the rx timeout to the given value
+        * again timeout * IOC4_SRTR_HZ / HZ
+        */
+       timeout = timeout * IOC4_SRTR_HZ / 100;
+       if (timeout > IOC4_SRTR_CNT)
+               timeout = IOC4_SRTR_CNT;
+
+       writel(timeout, &port->ip_serial_regs->srtr);
+       return 0;
+}
+
+/**
+ * config_port - config the hardware
+ * @port: port to config
+ * @baud: baud rate for the port
+ * @byte_size: data size
+ * @stop_bits: number of stop bits
+ * @parenb: parity enable ?
+ * @parodd: odd parity ?
+ */
+static inline int
+config_port(struct ioc4_port *port,
+           int baud, int byte_size, int stop_bits, int parenb, int parodd)
+{
+       char lcr, sizebits;
+       int spiniter = 0;
+
+       DPRINT_CONFIG(("%s: baud %d byte_size %d stop %d parenb %d parodd %d\n",
+               __func__, baud, byte_size, stop_bits, parenb, parodd));
+
+       if (set_baud(port, baud))
+               return 1;
+
+       switch (byte_size) {
+       case 5:
+               sizebits = UART_LCR_WLEN5;
+               break;
+       case 6:
+               sizebits = UART_LCR_WLEN6;
+               break;
+       case 7:
+               sizebits = UART_LCR_WLEN7;
+               break;
+       case 8:
+               sizebits = UART_LCR_WLEN8;
+               break;
+       default:
+               return 1;
+       }
+
+       /* Pause the DMA interface if necessary */
+       if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
+               writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE,
+                       &port->ip_serial_regs->sscr);
+               while((readl(&port->ip_serial_regs->sscr)
+                                               & IOC4_SSCR_PAUSE_STATE) == 0) {
+                       spiniter++;
+                       if (spiniter > MAXITER)
+                               return -1;
+               }
+       }
+
+       /* Clear relevant fields in lcr */
+       lcr = readb(&port->ip_uart_regs->i4u_lcr);
+       lcr &= ~(LCR_MASK_BITS_CHAR | UART_LCR_EPAR |
+                UART_LCR_PARITY | LCR_MASK_STOP_BITS);
+
+       /* Set byte size in lcr */
+       lcr |= sizebits;
+
+       /* Set parity */
+       if (parenb) {
+               lcr |= UART_LCR_PARITY;
+               if (!parodd)
+                       lcr |= UART_LCR_EPAR;
+       }
+
+       /* Set stop bits */
+       if (stop_bits)
+               lcr |= UART_LCR_STOP /* 2 stop bits */ ;
+
+       writeb(lcr, &port->ip_uart_regs->i4u_lcr);
+
+       /* Re-enable the DMA interface if necessary */
+       if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
+               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+       }
+       port->ip_baud = baud;
+
+       /* When we get within this number of ring entries of filling the
+        * entire ring on tx, place an EXPLICIT intr to generate a lowat
+        * notification when output has drained.
+        */
+       port->ip_tx_lowat = (TX_LOWAT_CHARS(baud) + 3) / 4;
+       if (port->ip_tx_lowat == 0)
+               port->ip_tx_lowat = 1;
+
+       set_rx_timeout(port, 2);
+
+       return 0;
+}
+
+/**
+ * do_write - Write bytes to the port.  Returns the number of bytes
+ *                     actually written. Called from transmit_chars
+ * @port: port to use
+ * @buf: the stuff to write
+ * @len: how many bytes in 'buf'
+ */
+static inline int do_write(struct ioc4_port *port, char *buf, int len)
+{
+       int prod_ptr, cons_ptr, total = 0;
+       struct ring *outring;
+       struct ring_entry *entry;
+       struct hooks *hooks = port->ip_hooks;
+
+       BUG_ON(!(len >= 0));
+
+       prod_ptr = port->ip_tx_prod;
+       cons_ptr = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
+       outring = port->ip_outring;
+
+       /* Maintain a 1-entry red-zone.  The ring buffer is full when
+        * (cons - prod) % ring_size is 1.  Rather than do this subtraction
+        * in the body of the loop, I'll do it now.
+        */
+       cons_ptr = (cons_ptr - (int)sizeof(struct ring_entry)) & PROD_CONS_MASK;
+
+       /* Stuff the bytes into the output */
+       while ((prod_ptr != cons_ptr) && (len > 0)) {
+               int xx;
+
+               /* Get 4 bytes (one ring entry) at a time */
+               entry = (struct ring_entry *)((caddr_t) outring + prod_ptr);
+
+               /* Invalidate all entries */
+               entry->ring_allsc = 0;
+
+               /* Copy in some bytes */
+               for (xx = 0; (xx < 4) && (len > 0); xx++) {
+                       entry->ring_data[xx] = *buf++;
+                       entry->ring_sc[xx] = IOC4_TXCB_VALID;
+                       len--;
+                       total++;
+               }
+
+               /* If we are within some small threshold of filling up the
+                * entire ring buffer, we must place an EXPLICIT intr here
+                * to generate a lowat interrupt in case we subsequently
+                * really do fill up the ring and the caller goes to sleep.
+                * No need to place more than one though.
+                */
+               if (!(port->ip_flags & LOWAT_WRITTEN) &&
+                       ((cons_ptr - prod_ptr) & PROD_CONS_MASK)
+                               <= port->ip_tx_lowat
+                                       * (int)sizeof(struct ring_entry)) {
+                       port->ip_flags |= LOWAT_WRITTEN;
+                       entry->ring_sc[0] |= IOC4_TXCB_INT_WHEN_DONE;
+               }
+
+               /* Go on to next entry */
+               prod_ptr += sizeof(struct ring_entry);
+               prod_ptr &= PROD_CONS_MASK;
+       }
+
+       /* If we sent something, start DMA if necessary */
+       if (total > 0 && !(port->ip_sscr & IOC4_SSCR_DMA_EN)) {
+               port->ip_sscr |= IOC4_SSCR_DMA_EN;
+               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+       }
+
+       /* Store the new producer pointer.  If tx is disabled, we stuff the
+        * data into the ring buffer, but we don't actually start tx.
+        */
+       if (!uart_tx_stopped(port->ip_port)) {
+               writel(prod_ptr, &port->ip_serial_regs->stpir);
+
+               /* If we are now transmitting, enable tx_mt interrupt so we
+                * can disable DMA if necessary when the tx finishes.
+                */
+               if (total > 0)
+                       enable_intrs(port, hooks->intr_tx_mt);
+       }
+       port->ip_tx_prod = prod_ptr;
+       return total;
+}
+
+/**
+ * disable_intrs - disable interrupts
+ * @port: port to enable
+ * @mask: mask to use
+ */
+static void disable_intrs(struct ioc4_port *port, uint32_t mask)
+{
+       struct hooks *hooks = port->ip_hooks;
+
+       if (port->ip_ienb & mask) {
+               write_ireg(port->ip_ioc4_soft, mask, IOC4_W_IEC,
+                                       IOC4_SIO_INTR_TYPE);
+               port->ip_ienb &= ~mask;
+       }
+
+       if (!port->ip_ienb)
+               write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error,
+                               IOC4_W_IEC, IOC4_OTHER_INTR_TYPE);
+}
+
+/**
+ * set_notification - Modify event notification
+ * @port: port to use
+ * @mask: events mask
+ * @set_on: set ?
+ */
+static int set_notification(struct ioc4_port *port, int mask, int set_on)
+{
+       struct hooks *hooks = port->ip_hooks;
+       uint32_t intrbits, sscrbits;
+
+       BUG_ON(!mask);
+
+       intrbits = sscrbits = 0;
+
+       if (mask & N_DATA_READY)
+               intrbits |= (hooks->intr_rx_timer | hooks->intr_rx_high);
+       if (mask & N_OUTPUT_LOWAT)
+               intrbits |= hooks->intr_tx_explicit;
+       if (mask & N_DDCD) {
+               intrbits |= hooks->intr_delta_dcd;
+               sscrbits |= IOC4_SSCR_RX_RING_DCD;
+       }
+       if (mask & N_DCTS)
+               intrbits |= hooks->intr_delta_cts;
+
+       if (set_on) {
+               enable_intrs(port, intrbits);
+               port->ip_notify |= mask;
+               port->ip_sscr |= sscrbits;
+       } else {
+               disable_intrs(port, intrbits);
+               port->ip_notify &= ~mask;
+               port->ip_sscr &= ~sscrbits;
+       }
+
+       /* We require DMA if either DATA_READY or DDCD notification is
+        * currently requested. If neither of these is requested and
+        * there is currently no tx in progress, DMA may be disabled.
+        */
+       if (port->ip_notify & (N_DATA_READY | N_DDCD))
+               port->ip_sscr |= IOC4_SSCR_DMA_EN;
+       else if (!(port->ip_ienb & hooks->intr_tx_mt))
+               port->ip_sscr &= ~IOC4_SSCR_DMA_EN;
+
+       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+       return 0;
+}
+
+/**
+ * set_mcr - set the master control reg
+ * @the_port: port to use
+ * @mask1: mcr mask
+ * @mask2: shadow mask
+ */
+static inline int set_mcr(struct uart_port *the_port,
+               int mask1, int mask2)
+{
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
+       uint32_t shadow;
+       int spiniter = 0;
+       char mcr;
+
+       if (!port)
+               return -1;
+
+       /* Pause the DMA interface if necessary */
+       if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
+               writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE,
+                       &port->ip_serial_regs->sscr);
+               while ((readl(&port->ip_serial_regs->sscr)
+                                       & IOC4_SSCR_PAUSE_STATE) == 0) {
+                       spiniter++;
+                       if (spiniter > MAXITER)
+                               return -1;
+               }
+       }
+       shadow = readl(&port->ip_serial_regs->shadow);
+       mcr = (shadow & 0xff000000) >> 24;
+
+       /* Set new value */
+       mcr |= mask1;
+       shadow |= mask2;
+
+       writeb(mcr, &port->ip_uart_regs->i4u_mcr);
+       writel(shadow, &port->ip_serial_regs->shadow);
+
+       /* Re-enable the DMA interface if necessary */
+       if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
+               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+       }
+       return 0;
+}
+
+/**
+ * ioc4_set_proto - set the protocol for the port
+ * @port: port to use
+ * @proto: protocol to use
+ */
+static int ioc4_set_proto(struct ioc4_port *port, int proto)
+{
+       struct hooks *hooks = port->ip_hooks;
+
+       switch (proto) {
+       case PROTO_RS232:
+               /* Clear the appropriate GIO pin */
+               writel(0, (&port->ip_mem->gppr[hooks->rs422_select_pin].raw));
+               break;
+
+       case PROTO_RS422:
+               /* Set the appropriate GIO pin */
+               writel(1, (&port->ip_mem->gppr[hooks->rs422_select_pin].raw));
+               break;
+
+       default:
+               return 1;
+       }
+       return 0;
+}
+
+/**
+ * transmit_chars - upper level write, called with ip_lock
+ * @the_port: port to write
+ */
+static void transmit_chars(struct uart_port *the_port)
+{
+       int xmit_count, tail, head;
+       int result;
+       char *start;
+       struct tty_struct *tty;
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
+       struct uart_state *state;
+
+       if (!the_port)
+               return;
+       if (!port)
+               return;
+
+       state = the_port->state;
+       tty = state->port.tty;
+
+       if (uart_circ_empty(&state->xmit) || uart_tx_stopped(the_port)) {
+               /* Nothing to do or hw stopped */
+               set_notification(port, N_ALL_OUTPUT, 0);
+               return;
+       }
+
+       head = state->xmit.head;
+       tail = state->xmit.tail;
+       start = (char *)&state->xmit.buf[tail];
+
+       /* write out all the data or until the end of the buffer */
+       xmit_count = (head < tail) ? (UART_XMIT_SIZE - tail) : (head - tail);
+       if (xmit_count > 0) {
+               result = do_write(port, start, xmit_count);
+               if (result > 0) {
+                       /* booking */
+                       xmit_count -= result;
+                       the_port->icount.tx += result;
+                       /* advance the pointers */
+                       tail += result;
+                       tail &= UART_XMIT_SIZE - 1;
+                       state->xmit.tail = tail;
+                       start = (char *)&state->xmit.buf[tail];
+               }
+       }
+       if (uart_circ_chars_pending(&state->xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(the_port);
+
+       if (uart_circ_empty(&state->xmit)) {
+               set_notification(port, N_OUTPUT_LOWAT, 0);
+       } else {
+               set_notification(port, N_OUTPUT_LOWAT, 1);
+       }
+}
+
+/**
+ * ioc4_change_speed - change the speed of the port
+ * @the_port: port to change
+ * @new_termios: new termios settings
+ * @old_termios: old termios settings
+ */
+static void
+ioc4_change_speed(struct uart_port *the_port,
+                 struct ktermios *new_termios, struct ktermios *old_termios)
+{
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
+       int baud, bits;
+       unsigned cflag, iflag;
+       int new_parity = 0, new_parity_enable = 0, new_stop = 0, new_data = 8;
+       struct uart_state *state = the_port->state;
+
+       cflag = new_termios->c_cflag;
+       iflag = new_termios->c_iflag;
+
+       switch (cflag & CSIZE) {
+       case CS5:
+               new_data = 5;
+               bits = 7;
+               break;
+       case CS6:
+               new_data = 6;
+               bits = 8;
+               break;
+       case CS7:
+               new_data = 7;
+               bits = 9;
+               break;
+       case CS8:
+               new_data = 8;
+               bits = 10;
+               break;
+       default:
+               /* cuz we always need a default ... */
+               new_data = 5;
+               bits = 7;
+               break;
+       }
+       if (cflag & CSTOPB) {
+               bits++;
+               new_stop = 1;
+       }
+       if (cflag & PARENB) {
+               bits++;
+               new_parity_enable = 1;
+               if (cflag & PARODD)
+                       new_parity = 1;
+       }
+       baud = uart_get_baud_rate(the_port, new_termios, old_termios,
+                               MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED);
+       DPRINT_CONFIG(("%s: returned baud %d\n", __func__, baud));
+
+       /* default is 9600 */
+       if (!baud)
+               baud = 9600;
+
+       if (!the_port->fifosize)
+               the_port->fifosize = IOC4_FIFO_CHARS;
+       the_port->timeout = ((the_port->fifosize * HZ * bits) / (baud / 10));
+       the_port->timeout += HZ / 50;   /* Add .02 seconds of slop */
+
+       the_port->ignore_status_mask = N_ALL_INPUT;
+
+       state->port.tty->low_latency = 1;
+
+       if (iflag & IGNPAR)
+               the_port->ignore_status_mask &= ~(N_PARITY_ERROR
+                                               | N_FRAMING_ERROR);
+       if (iflag & IGNBRK) {
+               the_port->ignore_status_mask &= ~N_BREAK;
+               if (iflag & IGNPAR)
+                       the_port->ignore_status_mask &= ~N_OVERRUN_ERROR;
+       }
+       if (!(cflag & CREAD)) {
+               /* ignore everything */
+               the_port->ignore_status_mask &= ~N_DATA_READY;
+       }
+
+       if (cflag & CRTSCTS) {
+               port->ip_sscr |= IOC4_SSCR_HFC_EN;
+       }
+       else {
+               port->ip_sscr &= ~IOC4_SSCR_HFC_EN;
+       }
+       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+
+       /* Set the configuration and proper notification call */
+       DPRINT_CONFIG(("%s : port 0x%p cflag 0%o "
+               "config_port(baud %d data %d stop %d p enable %d parity %d),"
+               " notification 0x%x\n",
+            __func__, (void *)port, cflag, baud, new_data, new_stop,
+            new_parity_enable, new_parity, the_port->ignore_status_mask));
+
+       if ((config_port(port, baud,            /* baud */
+                        new_data,              /* byte size */
+                        new_stop,              /* stop bits */
+                        new_parity_enable,     /* set parity */
+                        new_parity)) >= 0) {   /* parity 1==odd */
+               set_notification(port, the_port->ignore_status_mask, 1);
+       }
+}
+
+/**
+ * ic4_startup_local - Start up the serial port - returns >= 0 if no errors
+ * @the_port: Port to operate on
+ */
+static inline int ic4_startup_local(struct uart_port *the_port)
+{
+       struct ioc4_port *port;
+       struct uart_state *state;
+
+       if (!the_port)
+               return -1;
+
+       port = get_ioc4_port(the_port, 0);
+       if (!port)
+               return -1;
+
+       state = the_port->state;
+
+       local_open(port);
+
+       /* set the protocol - mapbase has the port type */
+       ioc4_set_proto(port, the_port->mapbase);
+
+       /* set the speed of the serial port */
+       ioc4_change_speed(the_port, state->port.tty->termios,
+                         (struct ktermios *)0);
+
+       return 0;
+}
+
+/*
+ * ioc4_cb_output_lowat - called when the output low water mark is hit
+ * @the_port: port to output
+ */
+static void ioc4_cb_output_lowat(struct uart_port *the_port)
+{
+       unsigned long pflags;
+
+       /* ip_lock is set on the call here */
+       if (the_port) {
+               spin_lock_irqsave(&the_port->lock, pflags);
+               transmit_chars(the_port);
+               spin_unlock_irqrestore(&the_port->lock, pflags);
+       }
+}
+
+/**
+ * handle_intr - service any interrupts for the given port - 2nd level
+ *                     called via sd_intr
+ * @arg: handler arg
+ * @sio_ir: ioc4regs
+ */
+static void handle_intr(void *arg, uint32_t sio_ir)
+{
+       struct ioc4_port *port = (struct ioc4_port *)arg;
+       struct hooks *hooks = port->ip_hooks;
+       unsigned int rx_high_rd_aborted = 0;
+       unsigned long flags;
+       struct uart_port *the_port;
+       int loop_counter;
+
+       /* Possible race condition here: The tx_mt interrupt bit may be
+        * cleared without the intervention of the interrupt handler,
+        * e.g. by a write.  If the top level interrupt handler reads a
+        * tx_mt, then some other processor does a write, starting up
+        * output, then we come in here, see the tx_mt and stop DMA, the
+        * output started by the other processor will hang.  Thus we can
+        * only rely on tx_mt being legitimate if it is read while the
+        * port lock is held.  Therefore this bit must be ignored in the
+        * passed in interrupt mask which was read by the top level
+        * interrupt handler since the port lock was not held at the time
+        * it was read.  We can only rely on this bit being accurate if it
+        * is read while the port lock is held.  So we'll clear it for now,
+        * and reload it later once we have the port lock.
+        */
+       sio_ir &= ~(hooks->intr_tx_mt);
+
+       spin_lock_irqsave(&port->ip_lock, flags);
+
+       loop_counter = MAXITER; /* to avoid hangs */
+
+       do {
+               uint32_t shadow;
+
+               if ( loop_counter-- <= 0 ) {
+                       printk(KERN_WARNING "IOC4 serial: "
+                                       "possible hang condition/"
+                                       "port stuck on interrupt.\n");
+                       break;
+               }
+
+               /* Handle a DCD change */
+               if (sio_ir & hooks->intr_delta_dcd) {
+                       /* ACK the interrupt */
+                       writel(hooks->intr_delta_dcd,
+                               &port->ip_mem->sio_ir.raw);
+
+                       shadow = readl(&port->ip_serial_regs->shadow);
+
+                       if ((port->ip_notify & N_DDCD)
+                                       && (shadow & IOC4_SHADOW_DCD)
+                                       && (port->ip_port)) {
+                               the_port = port->ip_port;
+                               the_port->icount.dcd = 1;
+                               wake_up_interruptible
+                                           (&the_port->state->port.delta_msr_wait);
+                       } else if ((port->ip_notify & N_DDCD)
+                                       && !(shadow & IOC4_SHADOW_DCD)) {
+                               /* Flag delta DCD/no DCD */
+                               port->ip_flags |= DCD_ON;
+                       }
+               }
+
+               /* Handle a CTS change */
+               if (sio_ir & hooks->intr_delta_cts) {
+                       /* ACK the interrupt */
+                       writel(hooks->intr_delta_cts,
+                                       &port->ip_mem->sio_ir.raw);
+
+                       shadow = readl(&port->ip_serial_regs->shadow);
+
+                       if ((port->ip_notify & N_DCTS)
+                                       && (port->ip_port)) {
+                               the_port = port->ip_port;
+                               the_port->icount.cts =
+                                       (shadow & IOC4_SHADOW_CTS) ? 1 : 0;
+                               wake_up_interruptible
+                                       (&the_port->state->port.delta_msr_wait);
+                       }
+               }
+
+               /* rx timeout interrupt.  Must be some data available.  Put this
+                * before the check for rx_high since servicing this condition
+                * may cause that condition to clear.
+                */
+               if (sio_ir & hooks->intr_rx_timer) {
+                       /* ACK the interrupt */
+                       writel(hooks->intr_rx_timer,
+                               &port->ip_mem->sio_ir.raw);
+
+                       if ((port->ip_notify & N_DATA_READY)
+                                       && (port->ip_port)) {
+                               /* ip_lock is set on call here */
+                               receive_chars(port->ip_port);
+                       }
+               }
+
+               /* rx high interrupt. Must be after rx_timer.  */
+               else if (sio_ir & hooks->intr_rx_high) {
+                       /* Data available, notify upper layer */
+                       if ((port->ip_notify & N_DATA_READY)
+                                               && port->ip_port) {
+                               /* ip_lock is set on call here */
+                               receive_chars(port->ip_port);
+                       }
+
+                       /* We can't ACK this interrupt.  If receive_chars didn't
+                        * cause the condition to clear, we'll have to disable
+                        * the interrupt until the data is drained.
+                        * If the read was aborted, don't disable the interrupt
+                        * as this may cause us to hang indefinitely.  An
+                        * aborted read generally means that this interrupt
+                        * hasn't been delivered to the cpu yet anyway, even
+                        * though we see it as asserted when we read the sio_ir.
+                        */
+                       if ((sio_ir = PENDING(port)) & hooks->intr_rx_high) {
+                               if ((port->ip_flags & READ_ABORTED) == 0) {
+                                       port->ip_ienb &= ~hooks->intr_rx_high;
+                                       port->ip_flags |= INPUT_HIGH;
+                               } else {
+                                       rx_high_rd_aborted++;
+                               }
+                       }
+               }
+
+               /* We got a low water interrupt: notify upper layer to
+                * send more data.  Must come before tx_mt since servicing
+                * this condition may cause that condition to clear.
+                */
+               if (sio_ir & hooks->intr_tx_explicit) {
+                       port->ip_flags &= ~LOWAT_WRITTEN;
+
+                       /* ACK the interrupt */
+                       writel(hooks->intr_tx_explicit,
+                                       &port->ip_mem->sio_ir.raw);
+
+                       if (port->ip_notify & N_OUTPUT_LOWAT)
+                               ioc4_cb_output_lowat(port->ip_port);
+               }
+
+               /* Handle tx_mt.  Must come after tx_explicit.  */
+               else if (sio_ir & hooks->intr_tx_mt) {
+                       /* If we are expecting a lowat notification
+                        * and we get to this point it probably means that for
+                        * some reason the tx_explicit didn't work as expected
+                        * (that can legitimately happen if the output buffer is
+                        * filled up in just the right way).
+                        * So send the notification now.
+                        */
+                       if (port->ip_notify & N_OUTPUT_LOWAT) {
+                               ioc4_cb_output_lowat(port->ip_port);
+
+                               /* We need to reload the sio_ir since the lowat
+                                * call may have caused another write to occur,
+                                * clearing the tx_mt condition.
+                                */
+                               sio_ir = PENDING(port);
+                       }
+
+                       /* If the tx_mt condition still persists even after the
+                        * lowat call, we've got some work to do.
+                        */
+                       if (sio_ir & hooks->intr_tx_mt) {
+
+                               /* If we are not currently expecting DMA input,
+                                * and the transmitter has just gone idle,
+                                * there is no longer any reason for DMA, so
+                                * disable it.
+                                */
+                               if (!(port->ip_notify
+                                               & (N_DATA_READY | N_DDCD))) {
+                                       BUG_ON(!(port->ip_sscr
+                                                       & IOC4_SSCR_DMA_EN));
+                                       port->ip_sscr &= ~IOC4_SSCR_DMA_EN;
+                                       writel(port->ip_sscr,
+                                          &port->ip_serial_regs->sscr);
+                               }
+
+                               /* Prevent infinite tx_mt interrupt */
+                               port->ip_ienb &= ~hooks->intr_tx_mt;
+                       }
+               }
+               sio_ir = PENDING(port);
+
+               /* if the read was aborted and only hooks->intr_rx_high,
+                * clear hooks->intr_rx_high, so we do not loop forever.
+                */
+
+               if (rx_high_rd_aborted && (sio_ir == hooks->intr_rx_high)) {
+                       sio_ir &= ~hooks->intr_rx_high;
+               }
+       } while (sio_ir & hooks->intr_all);
+
+       spin_unlock_irqrestore(&port->ip_lock, flags);
+
+       /* Re-enable interrupts before returning from interrupt handler.
+        * Getting interrupted here is okay.  It'll just v() our semaphore, and
+        * we'll come through the loop again.
+        */
+
+       write_ireg(port->ip_ioc4_soft, port->ip_ienb, IOC4_W_IES,
+                                                       IOC4_SIO_INTR_TYPE);
+}
+
+/*
+ * ioc4_cb_post_ncs - called for some basic errors
+ * @port: port to use
+ * @ncs: event
+ */
+static void ioc4_cb_post_ncs(struct uart_port *the_port, int ncs)
+{
+       struct uart_icount *icount;
+
+       icount = &the_port->icount;
+
+       if (ncs & NCS_BREAK)
+               icount->brk++;
+       if (ncs & NCS_FRAMING)
+               icount->frame++;
+       if (ncs & NCS_OVERRUN)
+               icount->overrun++;
+       if (ncs & NCS_PARITY)
+               icount->parity++;
+}
+
+/**
+ * do_read - Read in bytes from the port.  Return the number of bytes
+ *                     actually read.
+ * @the_port: port to use
+ * @buf: place to put the stuff we read
+ * @len: how big 'buf' is
+ */
+
+static inline int do_read(struct uart_port *the_port, unsigned char *buf,
+                               int len)
+{
+       int prod_ptr, cons_ptr, total;
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
+       struct ring *inring;
+       struct ring_entry *entry;
+       struct hooks *hooks = port->ip_hooks;
+       int byte_num;
+       char *sc;
+       int loop_counter;
+
+       BUG_ON(!(len >= 0));
+       BUG_ON(!port);
+
+       /* There is a nasty timing issue in the IOC4. When the rx_timer
+        * expires or the rx_high condition arises, we take an interrupt.
+        * At some point while servicing the interrupt, we read bytes from
+        * the ring buffer and re-arm the rx_timer.  However the rx_timer is
+        * not started until the first byte is received *after* it is armed,
+        * and any bytes pending in the rx construction buffers are not drained
+        * to memory until either there are 4 bytes available or the rx_timer
+        * expires.  This leads to a potential situation where data is left
+        * in the construction buffers forever - 1 to 3 bytes were received
+        * after the interrupt was generated but before the rx_timer was
+        * re-armed. At that point as long as no subsequent bytes are received
+        * the timer will never be started and the bytes will remain in the
+        * construction buffer forever.  The solution is to execute a DRAIN
+        * command after rearming the timer.  This way any bytes received before
+        * the DRAIN will be drained to memory, and any bytes received after
+        * the DRAIN will start the TIMER and be drained when it expires.
+        * Luckily, this only needs to be done when the DMA buffer is empty
+        * since there is no requirement that this function return all
+        * available data as long as it returns some.
+        */
+       /* Re-arm the timer */
+       writel(port->ip_rx_cons | IOC4_SRCIR_ARM, &port->ip_serial_regs->srcir);
+
+       prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
+       cons_ptr = port->ip_rx_cons;
+
+       if (prod_ptr == cons_ptr) {
+               int reset_dma = 0;
+
+               /* Input buffer appears empty, do a flush. */
+
+               /* DMA must be enabled for this to work. */
+               if (!(port->ip_sscr & IOC4_SSCR_DMA_EN)) {
+                       port->ip_sscr |= IOC4_SSCR_DMA_EN;
+                       reset_dma = 1;
+               }
+
+               /* Potential race condition: we must reload the srpir after
+                * issuing the drain command, otherwise we could think the rx
+                * buffer is empty, then take a very long interrupt, and when
+                * we come back it's full and we wait forever for the drain to
+                * complete.
+                */
+               writel(port->ip_sscr | IOC4_SSCR_RX_DRAIN,
+                               &port->ip_serial_regs->sscr);
+               prod_ptr = readl(&port->ip_serial_regs->srpir)
+                               & PROD_CONS_MASK;
+
+               /* We must not wait for the DRAIN to complete unless there are
+                * at least 8 bytes (2 ring entries) available to receive the
+                * data otherwise the DRAIN will never complete and we'll
+                * deadlock here.
+                * In fact, to make things easier, I'll just ignore the flush if
+                * there is any data at all now available.
+                */
+               if (prod_ptr == cons_ptr) {
+                       loop_counter = 0;
+                       while (readl(&port->ip_serial_regs->sscr) &
+                                               IOC4_SSCR_RX_DRAIN) {
+                               loop_counter++;
+                               if (loop_counter > MAXITER)
+                                       return -1;
+                       }
+
+                       /* SIGH. We have to reload the prod_ptr *again* since
+                        * the drain may have caused it to change
+                        */
+                       prod_ptr = readl(&port->ip_serial_regs->srpir)
+                                                       & PROD_CONS_MASK;
+               }
+               if (reset_dma) {
+                       port->ip_sscr &= ~IOC4_SSCR_DMA_EN;
+                       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+               }
+       }
+       inring = port->ip_inring;
+       port->ip_flags &= ~READ_ABORTED;
+
+       total = 0;
+       loop_counter = 0xfffff; /* to avoid hangs */
+
+       /* Grab bytes from the hardware */
+       while ((prod_ptr != cons_ptr) && (len > 0)) {
+               entry = (struct ring_entry *)((caddr_t)inring + cons_ptr);
+
+               if ( loop_counter-- <= 0 ) {
+                       printk(KERN_WARNING "IOC4 serial: "
+                                       "possible hang condition/"
+                                       "port stuck on read.\n");
+                       break;
+               }
+
+               /* According to the producer pointer, this ring entry
+                * must contain some data.  But if the PIO happened faster
+                * than the DMA, the data may not be available yet, so let's
+                * wait until it arrives.
+                */
+               if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
+                       /* Indicate the read is aborted so we don't disable
+                        * the interrupt thinking that the consumer is
+                        * congested.
+                        */
+                       port->ip_flags |= READ_ABORTED;
+                       len = 0;
+                       break;
+               }
+
+               /* Load the bytes/status out of the ring entry */
+               for (byte_num = 0; byte_num < 4 && len > 0; byte_num++) {
+                       sc = &(entry->ring_sc[byte_num]);
+
+                       /* Check for change in modem state or overrun */
+                       if ((*sc & IOC4_RXSB_MODEM_VALID)
+                                               && (port->ip_notify & N_DDCD)) {
+                               /* Notify upper layer if DCD dropped */
+
+                               if ((port->ip_flags & DCD_ON)
+                                               && !(*sc & IOC4_RXSB_DCD)) {
+
+                                       /* If we have already copied some data,
+                                        * return it.  We'll pick up the carrier
+                                        * drop on the next pass.  That way we
+                                        * don't throw away the data that has
+                                        * already been copied back to
+                                        * the caller's buffer.
+                                        */
+                                       if (total > 0) {
+                                               len = 0;
+                                               break;
+                                       }
+                                       port->ip_flags &= ~DCD_ON;
+
+                                       /* Turn off this notification so the
+                                        * carrier drop protocol won't see it
+                                        * again when it does a read.
+                                        */
+                                       *sc &= ~IOC4_RXSB_MODEM_VALID;
+
+                                       /* To keep things consistent, we need
+                                        * to update the consumer pointer so
+                                        * the next reader won't come in and
+                                        * try to read the same ring entries
+                                        * again. This must be done here before
+                                        * the dcd change.
+                                        */
+
+                                       if ((entry->ring_allsc & RING_ANY_VALID)
+                                                                       == 0) {
+                                               cons_ptr += (int)sizeof
+                                                       (struct ring_entry);
+                                               cons_ptr &= PROD_CONS_MASK;
+                                       }
+                                       writel(cons_ptr,
+                                               &port->ip_serial_regs->srcir);
+                                       port->ip_rx_cons = cons_ptr;
+
+                                       /* Notify upper layer of carrier drop */
+                                       if ((port->ip_notify & N_DDCD)
+                                                  && port->ip_port) {
+                                               the_port->icount.dcd = 0;
+                                               wake_up_interruptible
+                                                   (&the_port->state->
+                                                       port.delta_msr_wait);
+                                       }
+
+                                       /* If we had any data to return, we
+                                        * would have returned it above.
+                                        */
+                                       return 0;
+                               }
+                       }
+                       if (*sc & IOC4_RXSB_MODEM_VALID) {
+                               /* Notify that an input overrun occurred */
+                               if ((*sc & IOC4_RXSB_OVERRUN)
+                                   && (port->ip_notify & N_OVERRUN_ERROR)) {
+                                       ioc4_cb_post_ncs(the_port, NCS_OVERRUN);
+                               }
+                               /* Don't look at this byte again */
+                               *sc &= ~IOC4_RXSB_MODEM_VALID;
+                       }
+
+                       /* Check for valid data or RX errors */
+                       if ((*sc & IOC4_RXSB_DATA_VALID) &&
+                                       ((*sc & (IOC4_RXSB_PAR_ERR
+                                                       | IOC4_RXSB_FRAME_ERR
+                                                       | IOC4_RXSB_BREAK))
+                                       && (port->ip_notify & (N_PARITY_ERROR
+                                                       | N_FRAMING_ERROR
+                                                       | N_BREAK)))) {
+                               /* There is an error condition on the next byte.
+                                * If we have already transferred some bytes,
+                                * we'll stop here. Otherwise if this is the
+                                * first byte to be read, we'll just transfer
+                                * it alone after notifying the
+                                * upper layer of its status.
+                                */
+                               if (total > 0) {
+                                       len = 0;
+                                       break;
+                               } else {
+                                       if ((*sc & IOC4_RXSB_PAR_ERR) &&
+                                          (port->ip_notify & N_PARITY_ERROR)) {
+                                               ioc4_cb_post_ncs(the_port,
+                                                               NCS_PARITY);
+                                       }
+                                       if ((*sc & IOC4_RXSB_FRAME_ERR) &&
+                                          (port->ip_notify & N_FRAMING_ERROR)){
+                                               ioc4_cb_post_ncs(the_port,
+                                                               NCS_FRAMING);
+                                       }
+                                       if ((*sc & IOC4_RXSB_BREAK)
+                                           && (port->ip_notify & N_BREAK)) {
+                                                       ioc4_cb_post_ncs
+                                                                   (the_port,
+                                                                    NCS_BREAK);
+                                       }
+                                       len = 1;
+                               }
+                       }
+                       if (*sc & IOC4_RXSB_DATA_VALID) {
+                               *sc &= ~IOC4_RXSB_DATA_VALID;
+                               *buf = entry->ring_data[byte_num];
+                               buf++;
+                               len--;
+                               total++;
+                       }
+               }
+
+               /* If we used up this entry entirely, go on to the next one,
+                * otherwise we must have run out of buffer space, so
+                * leave the consumer pointer here for the next read in case
+                * there are still unread bytes in this entry.
+                */
+               if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
+                       cons_ptr += (int)sizeof(struct ring_entry);
+                       cons_ptr &= PROD_CONS_MASK;
+               }
+       }
+
+       /* Update consumer pointer and re-arm rx timer interrupt */
+       writel(cons_ptr, &port->ip_serial_regs->srcir);
+       port->ip_rx_cons = cons_ptr;
+
+       /* If we have now dipped below the rx high water mark and we have
+        * rx_high interrupt turned off, we can now turn it back on again.
+        */
+       if ((port->ip_flags & INPUT_HIGH) && (((prod_ptr - cons_ptr)
+                       & PROD_CONS_MASK) < ((port->ip_sscr &
+                               IOC4_SSCR_RX_THRESHOLD)
+                                       << IOC4_PROD_CONS_PTR_OFF))) {
+               port->ip_flags &= ~INPUT_HIGH;
+               enable_intrs(port, hooks->intr_rx_high);
+       }
+       return total;
+}
+
+/**
+ * receive_chars - upper level read. Called with ip_lock.
+ * @the_port: port to read from
+ */
+static void receive_chars(struct uart_port *the_port)
+{
+       struct tty_struct *tty;
+       unsigned char ch[IOC4_MAX_CHARS];
+       int read_count, request_count = IOC4_MAX_CHARS;
+       struct uart_icount *icount;
+       struct uart_state *state = the_port->state;
+       unsigned long pflags;
+
+       /* Make sure all the pointers are "good" ones */
+       if (!state)
+               return;
+       if (!state->port.tty)
+               return;
+
+       spin_lock_irqsave(&the_port->lock, pflags);
+       tty = state->port.tty;
+
+       request_count = tty_buffer_request_room(tty, IOC4_MAX_CHARS);
+
+       if (request_count > 0) {
+               icount = &the_port->icount;
+               read_count = do_read(the_port, ch, request_count);
+               if (read_count > 0) {
+                       tty_insert_flip_string(tty, ch, read_count);
+                       icount->rx += read_count;
+               }
+       }
+
+       spin_unlock_irqrestore(&the_port->lock, pflags);
+
+       tty_flip_buffer_push(tty);
+}
+
+/**
+ * ic4_type - What type of console are we?
+ * @port: Port to operate with (we ignore since we only have one port)
+ *
+ */
+static const char *ic4_type(struct uart_port *the_port)
+{
+       if (the_port->mapbase == PROTO_RS232)
+               return "SGI IOC4 Serial [rs232]";
+       else
+               return "SGI IOC4 Serial [rs422]";
+}
+
+/**
+ * ic4_tx_empty - Is the transmitter empty?
+ * @port: Port to operate on
+ *
+ */
+static unsigned int ic4_tx_empty(struct uart_port *the_port)
+{
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
+       unsigned int ret = 0;
+
+       if (port_is_active(port, the_port)) {
+               if (readl(&port->ip_serial_regs->shadow) & IOC4_SHADOW_TEMT)
+                       ret = TIOCSER_TEMT;
+       }
+       return ret;
+}
+
+/**
+ * ic4_stop_tx - stop the transmitter
+ * @port: Port to operate on
+ *
+ */
+static void ic4_stop_tx(struct uart_port *the_port)
+{
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
+
+       if (port_is_active(port, the_port))
+               set_notification(port, N_OUTPUT_LOWAT, 0);
+}
+
+/**
+ * null_void_function -
+ * @port: Port to operate on
+ *
+ */
+static void null_void_function(struct uart_port *the_port)
+{
+}
+
+/**
+ * ic4_shutdown - shut down the port - free irq and disable
+ * @port: Port to shut down
+ *
+ */
+static void ic4_shutdown(struct uart_port *the_port)
+{
+       unsigned long port_flags;
+       struct ioc4_port *port;
+       struct uart_state *state;
+
+       port = get_ioc4_port(the_port, 0);
+       if (!port)
+               return;
+
+       state = the_port->state;
+       port->ip_port = NULL;
+
+       wake_up_interruptible(&state->port.delta_msr_wait);
+
+       if (state->port.tty)
+               set_bit(TTY_IO_ERROR, &state->port.tty->flags);
+
+       spin_lock_irqsave(&the_port->lock, port_flags);
+       set_notification(port, N_ALL, 0);
+       port->ip_flags = PORT_INACTIVE;
+       spin_unlock_irqrestore(&the_port->lock, port_flags);
+}
+
+/**
+ * ic4_set_mctrl - set control lines (dtr, rts, etc)
+ * @port: Port to operate on
+ * @mctrl: Lines to set/unset
+ *
+ */
+static void ic4_set_mctrl(struct uart_port *the_port, unsigned int mctrl)
+{
+       unsigned char mcr = 0;
+       struct ioc4_port *port;
+
+       port = get_ioc4_port(the_port, 0);
+       if (!port_is_active(port, the_port))
+               return;
+
+       if (mctrl & TIOCM_RTS)
+               mcr |= UART_MCR_RTS;
+       if (mctrl & TIOCM_DTR)
+               mcr |= UART_MCR_DTR;
+       if (mctrl & TIOCM_OUT1)
+               mcr |= UART_MCR_OUT1;
+       if (mctrl & TIOCM_OUT2)
+               mcr |= UART_MCR_OUT2;
+       if (mctrl & TIOCM_LOOP)
+               mcr |= UART_MCR_LOOP;
+
+       set_mcr(the_port, mcr, IOC4_SHADOW_DTR);
+}
+
+/**
+ * ic4_get_mctrl - get control line info
+ * @port: port to operate on
+ *
+ */
+static unsigned int ic4_get_mctrl(struct uart_port *the_port)
+{
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
+       uint32_t shadow;
+       unsigned int ret = 0;
+
+       if (!port_is_active(port, the_port))
+               return 0;
+
+       shadow = readl(&port->ip_serial_regs->shadow);
+       if (shadow & IOC4_SHADOW_DCD)
+               ret |= TIOCM_CAR;
+       if (shadow & IOC4_SHADOW_DR)
+               ret |= TIOCM_DSR;
+       if (shadow & IOC4_SHADOW_CTS)
+               ret |= TIOCM_CTS;
+       return ret;
+}
+
+/**
+ * ic4_start_tx - Start transmitter, flush any output
+ * @port: Port to operate on
+ *
+ */
+static void ic4_start_tx(struct uart_port *the_port)
+{
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
+
+       if (port_is_active(port, the_port)) {
+               set_notification(port, N_OUTPUT_LOWAT, 1);
+               enable_intrs(port, port->ip_hooks->intr_tx_mt);
+       }
+}
+
+/**
+ * ic4_break_ctl - handle breaks
+ * @port: Port to operate on
+ * @break_state: Break state
+ *
+ */
+static void ic4_break_ctl(struct uart_port *the_port, int break_state)
+{
+}
+
+/**
+ * ic4_startup - Start up the serial port
+ * @port: Port to operate on
+ *
+ */
+static int ic4_startup(struct uart_port *the_port)
+{
+       int retval;
+       struct ioc4_port *port;
+       struct ioc4_control *control;
+       struct uart_state *state;
+       unsigned long port_flags;
+
+       if (!the_port)
+               return -ENODEV;
+       port = get_ioc4_port(the_port, 1);
+       if (!port)
+               return -ENODEV;
+       state = the_port->state;
+
+       control = port->ip_control;
+       if (!control) {
+               port->ip_port = NULL;
+               return -ENODEV;
+       }
+
+       /* Start up the serial port */
+       spin_lock_irqsave(&the_port->lock, port_flags);
+       retval = ic4_startup_local(the_port);
+       spin_unlock_irqrestore(&the_port->lock, port_flags);
+       return retval;
+}
+
+/**
+ * ic4_set_termios - set termios stuff
+ * @port: port to operate on
+ * @termios: New settings
+ * @termios: Old
+ *
+ */
+static void
+ic4_set_termios(struct uart_port *the_port,
+               struct ktermios *termios, struct ktermios *old_termios)
+{
+       unsigned long port_flags;
+
+       spin_lock_irqsave(&the_port->lock, port_flags);
+       ioc4_change_speed(the_port, termios, old_termios);
+       spin_unlock_irqrestore(&the_port->lock, port_flags);
+}
+
+/**
+ * ic4_request_port - allocate resources for port - no op....
+ * @port: port to operate on
+ *
+ */
+static int ic4_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+/* Associate the uart functions above - given to serial core */
+
+static struct uart_ops ioc4_ops = {
+       .tx_empty       = ic4_tx_empty,
+       .set_mctrl      = ic4_set_mctrl,
+       .get_mctrl      = ic4_get_mctrl,
+       .stop_tx        = ic4_stop_tx,
+       .start_tx       = ic4_start_tx,
+       .stop_rx        = null_void_function,
+       .enable_ms      = null_void_function,
+       .break_ctl      = ic4_break_ctl,
+       .startup        = ic4_startup,
+       .shutdown       = ic4_shutdown,
+       .set_termios    = ic4_set_termios,
+       .type           = ic4_type,
+       .release_port   = null_void_function,
+       .request_port   = ic4_request_port,
+};
+
+/*
+ * Boot-time initialization code
+ */
+
+static struct uart_driver ioc4_uart_rs232 = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "ioc4_serial_rs232",
+       .dev_name       = DEVICE_NAME_RS232,
+       .major          = DEVICE_MAJOR,
+       .minor          = DEVICE_MINOR_RS232,
+       .nr             = IOC4_NUM_CARDS * IOC4_NUM_SERIAL_PORTS,
+};
+
+static struct uart_driver ioc4_uart_rs422 = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "ioc4_serial_rs422",
+       .dev_name       = DEVICE_NAME_RS422,
+       .major          = DEVICE_MAJOR,
+       .minor          = DEVICE_MINOR_RS422,
+       .nr             = IOC4_NUM_CARDS * IOC4_NUM_SERIAL_PORTS,
+};
+
+
+/**
+ * ioc4_serial_remove_one - detach function
+ *
+ * @idd: IOC4 master module data for this IOC4
+ */
+
+static int ioc4_serial_remove_one(struct ioc4_driver_data *idd)
+{
+       int port_num, port_type;
+       struct ioc4_control *control;
+       struct uart_port *the_port;
+       struct ioc4_port *port;
+       struct ioc4_soft *soft;
+
+       /* If serial driver did not attach, don't try to detach */
+       control = idd->idd_serial_data;
+       if (!control)
+               return 0;
+
+       for (port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; port_num++) {
+               for (port_type = UART_PORT_MIN;
+                                       port_type < UART_PORT_COUNT;
+                                       port_type++) {
+                       the_port = &control->ic_port[port_num].icp_uart_port
+                                                       [port_type];
+                       if (the_port) {
+                               switch (port_type) {
+                               case UART_PORT_RS422:
+                                       uart_remove_one_port(&ioc4_uart_rs422,
+                                                       the_port);
+                                       break;
+                               default:
+                               case UART_PORT_RS232:
+                                       uart_remove_one_port(&ioc4_uart_rs232,
+                                                       the_port);
+                                       break;
+                               }
+                       }
+               }
+               port = control->ic_port[port_num].icp_port;
+               /* we allocate in pairs */
+               if (!(port_num & 1) && port) {
+                       pci_free_consistent(port->ip_pdev,
+                                       TOTAL_RING_BUF_SIZE,
+                                       port->ip_cpu_ringbuf,
+                                       port->ip_dma_ringbuf);
+                       kfree(port);
+               }
+       }
+       soft = control->ic_soft;
+       if (soft) {
+               free_irq(control->ic_irq, soft);
+               if (soft->is_ioc4_serial_addr) {
+                       iounmap(soft->is_ioc4_serial_addr);
+                       release_mem_region((unsigned long)
+                            soft->is_ioc4_serial_addr,
+                               sizeof(struct ioc4_serial));
+               }
+               kfree(soft);
+       }
+       kfree(control);
+       idd->idd_serial_data = NULL;
+
+       return 0;
+}
+
+
+/**
+ * ioc4_serial_core_attach_rs232 - register with serial core
+ *             This is done during pci probing
+ * @pdev: handle for this card
+ */
+static inline int
+ioc4_serial_core_attach(struct pci_dev *pdev, int port_type)
+{
+       struct ioc4_port *port;
+       struct uart_port *the_port;
+       struct ioc4_driver_data *idd = pci_get_drvdata(pdev);
+       struct ioc4_control *control = idd->idd_serial_data;
+       int port_num;
+       int port_type_idx;
+       struct uart_driver *u_driver;
+
+
+       DPRINT_CONFIG(("%s: attach pdev 0x%p - control 0x%p\n",
+                       __func__, pdev, (void *)control));
+
+       if (!control)
+               return -ENODEV;
+
+       port_type_idx = (port_type == PROTO_RS232) ? UART_PORT_RS232
+                                               : UART_PORT_RS422;
+
+       u_driver = (port_type == PROTO_RS232)   ? &ioc4_uart_rs232
+                                               : &ioc4_uart_rs422;
+
+       /* once around for each port on this card */
+       for (port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; port_num++) {
+               the_port = &control->ic_port[port_num].icp_uart_port
+                                                       [port_type_idx];
+               port = control->ic_port[port_num].icp_port;
+               port->ip_all_ports[port_type_idx] = the_port;
+
+               DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p : type %s\n",
+                               __func__, (void *)the_port,
+                               (void *)port,
+                               port_type == PROTO_RS232 ? "rs232" : "rs422"));
+
+               /* membase, iobase and mapbase just need to be non-0 */
+               the_port->membase = (unsigned char __iomem *)1;
+               the_port->iobase = (pdev->bus->number << 16) |  port_num;
+               the_port->line = (Num_of_ioc4_cards << 2) | port_num;
+               the_port->mapbase = port_type;
+               the_port->type = PORT_16550A;
+               the_port->fifosize = IOC4_FIFO_CHARS;
+               the_port->ops = &ioc4_ops;
+               the_port->irq = control->ic_irq;
+               the_port->dev = &pdev->dev;
+               spin_lock_init(&the_port->lock);
+               if (uart_add_one_port(u_driver, the_port) < 0) {
+                       printk(KERN_WARNING
+                          "%s: unable to add port %d bus %d\n",
+                              __func__, the_port->line, pdev->bus->number);
+               } else {
+                       DPRINT_CONFIG(
+                           ("IOC4 serial port %d irq = %d, bus %d\n",
+                              the_port->line, the_port->irq, pdev->bus->number));
+               }
+       }
+       return 0;
+}
+
+/**
+ * ioc4_serial_attach_one - register attach function
+ *             called per card found from IOC4 master module.
+ * @idd: Master module data for this IOC4
+ */
+int
+ioc4_serial_attach_one(struct ioc4_driver_data *idd)
+{
+       unsigned long tmp_addr1;
+       struct ioc4_serial __iomem *serial;
+       struct ioc4_soft *soft;
+       struct ioc4_control *control;
+       int ret = 0;
+
+
+       DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, idd->idd_pdev,
+                                                       idd->idd_pci_id));
+
+       /* PCI-RT does not bring out serial connections.
+        * Do not attach to this particular IOC4.
+        */
+       if (idd->idd_variant == IOC4_VARIANT_PCI_RT)
+               return 0;
+
+       /* request serial registers */
+       tmp_addr1 = idd->idd_bar0 + IOC4_SERIAL_OFFSET;
+
+       if (!request_mem_region(tmp_addr1, sizeof(struct ioc4_serial),
+                                       "sioc4_uart")) {
+               printk(KERN_WARNING
+                       "ioc4 (%p): unable to get request region for "
+                               "uart space\n", (void *)idd->idd_pdev);
+               ret = -ENODEV;
+               goto out1;
+       }
+       serial = ioremap(tmp_addr1, sizeof(struct ioc4_serial));
+       if (!serial) {
+               printk(KERN_WARNING
+                        "ioc4 (%p) : unable to remap ioc4 serial register\n",
+                               (void *)idd->idd_pdev);
+               ret = -ENODEV;
+               goto out2;
+       }
+       DPRINT_CONFIG(("%s : mem 0x%p, serial 0x%p\n",
+                               __func__, (void *)idd->idd_misc_regs,
+                               (void *)serial));
+
+       /* Get memory for the new card */
+       control = kzalloc(sizeof(struct ioc4_control), GFP_KERNEL);
+
+       if (!control) {
+               printk(KERN_WARNING "ioc4_attach_one"
+                      ": unable to get memory for the IOC4\n");
+               ret = -ENOMEM;
+               goto out2;
+       }
+       idd->idd_serial_data = control;
+
+       /* Allocate the soft structure */
+       soft = kzalloc(sizeof(struct ioc4_soft), GFP_KERNEL);
+       if (!soft) {
+               printk(KERN_WARNING
+                      "ioc4 (%p): unable to get memory for the soft struct\n",
+                      (void *)idd->idd_pdev);
+               ret = -ENOMEM;
+               goto out3;
+       }
+
+       spin_lock_init(&soft->is_ir_lock);
+       soft->is_ioc4_misc_addr = idd->idd_misc_regs;
+       soft->is_ioc4_serial_addr = serial;
+
+       /* Init the IOC4 */
+       writel(0xf << IOC4_SIO_CR_CMD_PULSE_SHIFT,
+              &idd->idd_misc_regs->sio_cr.raw);
+
+       /* Enable serial port mode select generic PIO pins as outputs */
+       writel(IOC4_GPCR_UART0_MODESEL | IOC4_GPCR_UART1_MODESEL
+               | IOC4_GPCR_UART2_MODESEL | IOC4_GPCR_UART3_MODESEL,
+               &idd->idd_misc_regs->gpcr_s.raw);
+
+       /* Clear and disable all serial interrupts */
+       write_ireg(soft, ~0, IOC4_W_IEC, IOC4_SIO_INTR_TYPE);
+       writel(~0, &idd->idd_misc_regs->sio_ir.raw);
+       write_ireg(soft, IOC4_OTHER_IR_SER_MEMERR, IOC4_W_IEC,
+                  IOC4_OTHER_INTR_TYPE);
+       writel(IOC4_OTHER_IR_SER_MEMERR, &idd->idd_misc_regs->other_ir.raw);
+       control->ic_soft = soft;
+
+       /* Hook up interrupt handler */
+       if (!request_irq(idd->idd_pdev->irq, ioc4_intr, IRQF_SHARED,
+                               "sgi-ioc4serial", soft)) {
+               control->ic_irq = idd->idd_pdev->irq;
+       } else {
+               printk(KERN_WARNING
+                   "%s : request_irq fails for IRQ 0x%x\n ",
+                       __func__, idd->idd_pdev->irq);
+       }
+       ret = ioc4_attach_local(idd);
+       if (ret)
+               goto out4;
+
+       /* register port with the serial core - 1 rs232, 1 rs422 */
+
+       if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS232)))
+               goto out4;
+
+       if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS422)))
+               goto out5;
+
+       Num_of_ioc4_cards++;
+
+       return ret;
+
+       /* error exits that give back resources */
+out5:
+       ioc4_serial_remove_one(idd);
+out4:
+       kfree(soft);
+out3:
+       kfree(control);
+out2:
+       if (serial)
+               iounmap(serial);
+       release_mem_region(tmp_addr1, sizeof(struct ioc4_serial));
+out1:
+
+       return ret;
+}
+
+
+static struct ioc4_submodule ioc4_serial_submodule = {
+       .is_name = "IOC4_serial",
+       .is_owner = THIS_MODULE,
+       .is_probe = ioc4_serial_attach_one,
+       .is_remove = ioc4_serial_remove_one,
+};
+
+/**
+ * ioc4_serial_init - module init
+ */
+static int __init ioc4_serial_init(void)
+{
+       int ret;
+
+       /* register with serial core */
+       if ((ret = uart_register_driver(&ioc4_uart_rs232)) < 0) {
+               printk(KERN_WARNING
+                       "%s: Couldn't register rs232 IOC4 serial driver\n",
+                       __func__);
+               goto out;
+       }
+       if ((ret = uart_register_driver(&ioc4_uart_rs422)) < 0) {
+               printk(KERN_WARNING
+                       "%s: Couldn't register rs422 IOC4 serial driver\n",
+                       __func__);
+               goto out_uart_rs232;
+       }
+
+       /* register with IOC4 main module */
+       ret = ioc4_register_submodule(&ioc4_serial_submodule);
+       if (ret)
+               goto out_uart_rs422;
+       return 0;
+
+out_uart_rs422:
+       uart_unregister_driver(&ioc4_uart_rs422);
+out_uart_rs232:
+       uart_unregister_driver(&ioc4_uart_rs232);
+out:
+       return ret;
+}
+
+static void __exit ioc4_serial_exit(void)
+{
+       ioc4_unregister_submodule(&ioc4_serial_submodule);
+       uart_unregister_driver(&ioc4_uart_rs232);
+       uart_unregister_driver(&ioc4_uart_rs422);
+}
+
+late_initcall(ioc4_serial_init); /* Call only after tty init is done */
+module_exit(ioc4_serial_exit);
+
+MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) <pfg@sgi.com>");
+MODULE_DESCRIPTION("Serial PCI driver module for SGI IOC4 Base-IO Card");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c
new file mode 100644 (file)
index 0000000..ebff4a1
--- /dev/null
@@ -0,0 +1,1221 @@
+/*
+ * Driver for Zilog serial chips found on SGI workstations and
+ * servers.  This driver could actually be made more generic.
+ *
+ * This is based on the drivers/serial/sunzilog.c code as of 2.6.0-test7 and the
+ * old drivers/sgi/char/sgiserial.c code which itself is based of the original
+ * drivers/sbus/char/zs.c code.  A lot of code has been simply moved over
+ * directly from there but much has been rewritten.  Credits therefore go out
+ * to David S. Miller, Eddie C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell
+ * for their work there.
+ *
+ *  Copyright (C) 2002 Ralf Baechle (ralf@linux-mips.org)
+ *  Copyright (C) 2002 David S. Miller (davem@redhat.com)
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/sgialib.h>
+#include <asm/sgi/ioc.h>
+#include <asm/sgi/hpc3.h>
+#include <asm/sgi/ip22.h>
+
+#if defined(CONFIG_SERIAL_IP22_ZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#include "ip22zilog.h"
+
+/*
+ * On IP22 we need to delay after register accesses but we do not need to
+ * flush writes.
+ */
+#define ZSDELAY()              udelay(5)
+#define ZSDELAY_LONG()         udelay(20)
+#define ZS_WSYNC(channel)      do { } while (0)
+
+#define NUM_IP22ZILOG          1
+#define NUM_CHANNELS           (NUM_IP22ZILOG * 2)
+
+#define ZS_CLOCK               3672000 /* Zilog input clock rate. */
+#define ZS_CLOCK_DIVISOR       16      /* Divisor this driver uses. */
+
+/*
+ * We wrap our port structure around the generic uart_port.
+ */
+struct uart_ip22zilog_port {
+       struct uart_port                port;
+
+       /* IRQ servicing chain.  */
+       struct uart_ip22zilog_port      *next;
+
+       /* Current values of Zilog write registers.  */
+       unsigned char                   curregs[NUM_ZSREGS];
+
+       unsigned int                    flags;
+#define IP22ZILOG_FLAG_IS_CONS         0x00000004
+#define IP22ZILOG_FLAG_IS_KGDB         0x00000008
+#define IP22ZILOG_FLAG_MODEM_STATUS    0x00000010
+#define IP22ZILOG_FLAG_IS_CHANNEL_A    0x00000020
+#define IP22ZILOG_FLAG_REGS_HELD       0x00000040
+#define IP22ZILOG_FLAG_TX_STOPPED      0x00000080
+#define IP22ZILOG_FLAG_TX_ACTIVE       0x00000100
+#define IP22ZILOG_FLAG_RESET_DONE      0x00000200
+
+       unsigned int                    tty_break;
+
+       unsigned char                   parity_mask;
+       unsigned char                   prev_status;
+};
+
+#define ZILOG_CHANNEL_FROM_PORT(PORT)  ((struct zilog_channel *)((PORT)->membase))
+#define UART_ZILOG(PORT)               ((struct uart_ip22zilog_port *)(PORT))
+#define IP22ZILOG_GET_CURR_REG(PORT, REGNUM)           \
+       (UART_ZILOG(PORT)->curregs[REGNUM])
+#define IP22ZILOG_SET_CURR_REG(PORT, REGNUM, REGVAL)   \
+       ((UART_ZILOG(PORT)->curregs[REGNUM]) = (REGVAL))
+#define ZS_IS_CONS(UP) ((UP)->flags & IP22ZILOG_FLAG_IS_CONS)
+#define ZS_IS_KGDB(UP) ((UP)->flags & IP22ZILOG_FLAG_IS_KGDB)
+#define ZS_WANTS_MODEM_STATUS(UP)      ((UP)->flags & IP22ZILOG_FLAG_MODEM_STATUS)
+#define ZS_IS_CHANNEL_A(UP)    ((UP)->flags & IP22ZILOG_FLAG_IS_CHANNEL_A)
+#define ZS_REGS_HELD(UP)       ((UP)->flags & IP22ZILOG_FLAG_REGS_HELD)
+#define ZS_TX_STOPPED(UP)      ((UP)->flags & IP22ZILOG_FLAG_TX_STOPPED)
+#define ZS_TX_ACTIVE(UP)       ((UP)->flags & IP22ZILOG_FLAG_TX_ACTIVE)
+
+/* Reading and writing Zilog8530 registers.  The delays are to make this
+ * driver work on the IP22 which needs a settling delay after each chip
+ * register access, other machines handle this in hardware via auxiliary
+ * flip-flops which implement the settle time we do in software.
+ *
+ * The port lock must be held and local IRQs must be disabled
+ * when {read,write}_zsreg is invoked.
+ */
+static unsigned char read_zsreg(struct zilog_channel *channel,
+                               unsigned char reg)
+{
+       unsigned char retval;
+
+       writeb(reg, &channel->control);
+       ZSDELAY();
+       retval = readb(&channel->control);
+       ZSDELAY();
+
+       return retval;
+}
+
+static void write_zsreg(struct zilog_channel *channel,
+                       unsigned char reg, unsigned char value)
+{
+       writeb(reg, &channel->control);
+       ZSDELAY();
+       writeb(value, &channel->control);
+       ZSDELAY();
+}
+
+static void ip22zilog_clear_fifo(struct zilog_channel *channel)
+{
+       int i;
+
+       for (i = 0; i < 32; i++) {
+               unsigned char regval;
+
+               regval = readb(&channel->control);
+               ZSDELAY();
+               if (regval & Rx_CH_AV)
+                       break;
+
+               regval = read_zsreg(channel, R1);
+               readb(&channel->data);
+               ZSDELAY();
+
+               if (regval & (PAR_ERR | Rx_OVR | CRC_ERR)) {
+                       writeb(ERR_RES, &channel->control);
+                       ZSDELAY();
+                       ZS_WSYNC(channel);
+               }
+       }
+}
+
+/* This function must only be called when the TX is not busy.  The UART
+ * port lock must be held and local interrupts disabled.
+ */
+static void __load_zsregs(struct zilog_channel *channel, unsigned char *regs)
+{
+       int i;
+
+       /* Let pending transmits finish.  */
+       for (i = 0; i < 1000; i++) {
+               unsigned char stat = read_zsreg(channel, R1);
+               if (stat & ALL_SNT)
+                       break;
+               udelay(100);
+       }
+
+       writeb(ERR_RES, &channel->control);
+       ZSDELAY();
+       ZS_WSYNC(channel);
+
+       ip22zilog_clear_fifo(channel);
+
+       /* Disable all interrupts.  */
+       write_zsreg(channel, R1,
+                   regs[R1] & ~(RxINT_MASK | TxINT_ENAB | EXT_INT_ENAB));
+
+       /* Set parity, sync config, stop bits, and clock divisor.  */
+       write_zsreg(channel, R4, regs[R4]);
+
+       /* Set misc. TX/RX control bits.  */
+       write_zsreg(channel, R10, regs[R10]);
+
+       /* Set TX/RX controls sans the enable bits.  */
+       write_zsreg(channel, R3, regs[R3] & ~RxENAB);
+       write_zsreg(channel, R5, regs[R5] & ~TxENAB);
+
+       /* Synchronous mode config.  */
+       write_zsreg(channel, R6, regs[R6]);
+       write_zsreg(channel, R7, regs[R7]);
+
+       /* Don't mess with the interrupt vector (R2, unused by us) and
+        * master interrupt control (R9).  We make sure this is setup
+        * properly at probe time then never touch it again.
+        */
+
+       /* Disable baud generator.  */
+       write_zsreg(channel, R14, regs[R14] & ~BRENAB);
+
+       /* Clock mode control.  */
+       write_zsreg(channel, R11, regs[R11]);
+
+       /* Lower and upper byte of baud rate generator divisor.  */
+       write_zsreg(channel, R12, regs[R12]);
+       write_zsreg(channel, R13, regs[R13]);
+
+       /* Now rewrite R14, with BRENAB (if set).  */
+       write_zsreg(channel, R14, regs[R14]);
+
+       /* External status interrupt control.  */
+       write_zsreg(channel, R15, regs[R15]);
+
+       /* Reset external status interrupts.  */
+       write_zsreg(channel, R0, RES_EXT_INT);
+       write_zsreg(channel, R0, RES_EXT_INT);
+
+       /* Rewrite R3/R5, this time without enables masked.  */
+       write_zsreg(channel, R3, regs[R3]);
+       write_zsreg(channel, R5, regs[R5]);
+
+       /* Rewrite R1, this time without IRQ enabled masked.  */
+       write_zsreg(channel, R1, regs[R1]);
+}
+
+/* Reprogram the Zilog channel HW registers with the copies found in the
+ * software state struct.  If the transmitter is busy, we defer this update
+ * until the next TX complete interrupt.  Else, we do it right now.
+ *
+ * The UART port lock must be held and local interrupts disabled.
+ */
+static void ip22zilog_maybe_update_regs(struct uart_ip22zilog_port *up,
+                                      struct zilog_channel *channel)
+{
+       if (!ZS_REGS_HELD(up)) {
+               if (ZS_TX_ACTIVE(up)) {
+                       up->flags |= IP22ZILOG_FLAG_REGS_HELD;
+               } else {
+                       __load_zsregs(channel, up->curregs);
+               }
+       }
+}
+
+#define Rx_BRK 0x0100                   /* BREAK event software flag.  */
+#define Rx_SYS 0x0200                   /* SysRq event software flag.  */
+
+static struct tty_struct *ip22zilog_receive_chars(struct uart_ip22zilog_port *up,
+                                                 struct zilog_channel *channel)
+{
+       struct tty_struct *tty;
+       unsigned char ch, flag;
+       unsigned int r1;
+
+       tty = NULL;
+       if (up->port.state != NULL &&
+           up->port.state->port.tty != NULL)
+               tty = up->port.state->port.tty;
+
+       for (;;) {
+               ch = readb(&channel->control);
+               ZSDELAY();
+               if (!(ch & Rx_CH_AV))
+                       break;
+
+               r1 = read_zsreg(channel, R1);
+               if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
+                       writeb(ERR_RES, &channel->control);
+                       ZSDELAY();
+                       ZS_WSYNC(channel);
+               }
+
+               ch = readb(&channel->data);
+               ZSDELAY();
+
+               ch &= up->parity_mask;
+
+               /* Handle the null char got when BREAK is removed.  */
+               if (!ch)
+                       r1 |= up->tty_break;
+
+               /* A real serial line, record the character and status.  */
+               flag = TTY_NORMAL;
+               up->port.icount.rx++;
+               if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | Rx_SYS | Rx_BRK)) {
+                       up->tty_break = 0;
+
+                       if (r1 & (Rx_SYS | Rx_BRK)) {
+                               up->port.icount.brk++;
+                               if (r1 & Rx_SYS)
+                                       continue;
+                               r1 &= ~(PAR_ERR | CRC_ERR);
+                       }
+                       else if (r1 & PAR_ERR)
+                               up->port.icount.parity++;
+                       else if (r1 & CRC_ERR)
+                               up->port.icount.frame++;
+                       if (r1 & Rx_OVR)
+                               up->port.icount.overrun++;
+                       r1 &= up->port.read_status_mask;
+                       if (r1 & Rx_BRK)
+                               flag = TTY_BREAK;
+                       else if (r1 & PAR_ERR)
+                               flag = TTY_PARITY;
+                       else if (r1 & CRC_ERR)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(&up->port, ch))
+                       continue;
+
+               if (tty)
+                       uart_insert_char(&up->port, r1, Rx_OVR, ch, flag);
+       }
+       return tty;
+}
+
+static void ip22zilog_status_handle(struct uart_ip22zilog_port *up,
+                                  struct zilog_channel *channel)
+{
+       unsigned char status;
+
+       status = readb(&channel->control);
+       ZSDELAY();
+
+       writeb(RES_EXT_INT, &channel->control);
+       ZSDELAY();
+       ZS_WSYNC(channel);
+
+       if (up->curregs[R15] & BRKIE) {
+               if ((status & BRK_ABRT) && !(up->prev_status & BRK_ABRT)) {
+                       if (uart_handle_break(&up->port))
+                               up->tty_break = Rx_SYS;
+                       else
+                               up->tty_break = Rx_BRK;
+               }
+       }
+
+       if (ZS_WANTS_MODEM_STATUS(up)) {
+               if (status & SYNC)
+                       up->port.icount.dsr++;
+
+               /* The Zilog just gives us an interrupt when DCD/CTS/etc. change.
+                * But it does not tell us which bit has changed, we have to keep
+                * track of this ourselves.
+                */
+               if ((status ^ up->prev_status) ^ DCD)
+                       uart_handle_dcd_change(&up->port,
+                                              (status & DCD));
+               if ((status ^ up->prev_status) ^ CTS)
+                       uart_handle_cts_change(&up->port,
+                                              (status & CTS));
+
+               wake_up_interruptible(&up->port.state->port.delta_msr_wait);
+       }
+
+       up->prev_status = status;
+}
+
+static void ip22zilog_transmit_chars(struct uart_ip22zilog_port *up,
+                                   struct zilog_channel *channel)
+{
+       struct circ_buf *xmit;
+
+       if (ZS_IS_CONS(up)) {
+               unsigned char status = readb(&channel->control);
+               ZSDELAY();
+
+               /* TX still busy?  Just wait for the next TX done interrupt.
+                *
+                * It can occur because of how we do serial console writes.  It would
+                * be nice to transmit console writes just like we normally would for
+                * a TTY line. (ie. buffered and TX interrupt driven).  That is not
+                * easy because console writes cannot sleep.  One solution might be
+                * to poll on enough port->xmit space becomming free.  -DaveM
+                */
+               if (!(status & Tx_BUF_EMP))
+                       return;
+       }
+
+       up->flags &= ~IP22ZILOG_FLAG_TX_ACTIVE;
+
+       if (ZS_REGS_HELD(up)) {
+               __load_zsregs(channel, up->curregs);
+               up->flags &= ~IP22ZILOG_FLAG_REGS_HELD;
+       }
+
+       if (ZS_TX_STOPPED(up)) {
+               up->flags &= ~IP22ZILOG_FLAG_TX_STOPPED;
+               goto ack_tx_int;
+       }
+
+       if (up->port.x_char) {
+               up->flags |= IP22ZILOG_FLAG_TX_ACTIVE;
+               writeb(up->port.x_char, &channel->data);
+               ZSDELAY();
+               ZS_WSYNC(channel);
+
+               up->port.icount.tx++;
+               up->port.x_char = 0;
+               return;
+       }
+
+       if (up->port.state == NULL)
+               goto ack_tx_int;
+       xmit = &up->port.state->xmit;
+       if (uart_circ_empty(xmit))
+               goto ack_tx_int;
+       if (uart_tx_stopped(&up->port))
+               goto ack_tx_int;
+
+       up->flags |= IP22ZILOG_FLAG_TX_ACTIVE;
+       writeb(xmit->buf[xmit->tail], &channel->data);
+       ZSDELAY();
+       ZS_WSYNC(channel);
+
+       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+       up->port.icount.tx++;
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+       return;
+
+ack_tx_int:
+       writeb(RES_Tx_P, &channel->control);
+       ZSDELAY();
+       ZS_WSYNC(channel);
+}
+
+static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id)
+{
+       struct uart_ip22zilog_port *up = dev_id;
+
+       while (up) {
+               struct zilog_channel *channel
+                       = ZILOG_CHANNEL_FROM_PORT(&up->port);
+               struct tty_struct *tty;
+               unsigned char r3;
+
+               spin_lock(&up->port.lock);
+               r3 = read_zsreg(channel, R3);
+
+               /* Channel A */
+               tty = NULL;
+               if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
+                       writeb(RES_H_IUS, &channel->control);
+                       ZSDELAY();
+                       ZS_WSYNC(channel);
+
+                       if (r3 & CHARxIP)
+                               tty = ip22zilog_receive_chars(up, channel);
+                       if (r3 & CHAEXT)
+                               ip22zilog_status_handle(up, channel);
+                       if (r3 & CHATxIP)
+                               ip22zilog_transmit_chars(up, channel);
+               }
+               spin_unlock(&up->port.lock);
+
+               if (tty)
+                       tty_flip_buffer_push(tty);
+
+               /* Channel B */
+               up = up->next;
+               channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+
+               spin_lock(&up->port.lock);
+               tty = NULL;
+               if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
+                       writeb(RES_H_IUS, &channel->control);
+                       ZSDELAY();
+                       ZS_WSYNC(channel);
+
+                       if (r3 & CHBRxIP)
+                               tty = ip22zilog_receive_chars(up, channel);
+                       if (r3 & CHBEXT)
+                               ip22zilog_status_handle(up, channel);
+                       if (r3 & CHBTxIP)
+                               ip22zilog_transmit_chars(up, channel);
+               }
+               spin_unlock(&up->port.lock);
+
+               if (tty)
+                       tty_flip_buffer_push(tty);
+
+               up = up->next;
+       }
+
+       return IRQ_HANDLED;
+}
+
+/* A convenient way to quickly get R0 status.  The caller must _not_ hold the
+ * port lock, it is acquired here.
+ */
+static __inline__ unsigned char ip22zilog_read_channel_status(struct uart_port *port)
+{
+       struct zilog_channel *channel;
+       unsigned char status;
+
+       channel = ZILOG_CHANNEL_FROM_PORT(port);
+       status = readb(&channel->control);
+       ZSDELAY();
+
+       return status;
+}
+
+/* The port lock is not held.  */
+static unsigned int ip22zilog_tx_empty(struct uart_port *port)
+{
+       unsigned long flags;
+       unsigned char status;
+       unsigned int ret;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       status = ip22zilog_read_channel_status(port);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       if (status & Tx_BUF_EMP)
+               ret = TIOCSER_TEMT;
+       else
+               ret = 0;
+
+       return ret;
+}
+
+/* The port lock is held and interrupts are disabled.  */
+static unsigned int ip22zilog_get_mctrl(struct uart_port *port)
+{
+       unsigned char status;
+       unsigned int ret;
+
+       status = ip22zilog_read_channel_status(port);
+
+       ret = 0;
+       if (status & DCD)
+               ret |= TIOCM_CAR;
+       if (status & SYNC)
+               ret |= TIOCM_DSR;
+       if (status & CTS)
+               ret |= TIOCM_CTS;
+
+       return ret;
+}
+
+/* The port lock is held and interrupts are disabled.  */
+static void ip22zilog_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
+       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
+       unsigned char set_bits, clear_bits;
+
+       set_bits = clear_bits = 0;
+
+       if (mctrl & TIOCM_RTS)
+               set_bits |= RTS;
+       else
+               clear_bits |= RTS;
+       if (mctrl & TIOCM_DTR)
+               set_bits |= DTR;
+       else
+               clear_bits |= DTR;
+
+       /* NOTE: Not subject to 'transmitter active' rule.  */
+       up->curregs[R5] |= set_bits;
+       up->curregs[R5] &= ~clear_bits;
+       write_zsreg(channel, R5, up->curregs[R5]);
+}
+
+/* The port lock is held and interrupts are disabled.  */
+static void ip22zilog_stop_tx(struct uart_port *port)
+{
+       struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
+
+       up->flags |= IP22ZILOG_FLAG_TX_STOPPED;
+}
+
+/* The port lock is held and interrupts are disabled.  */
+static void ip22zilog_start_tx(struct uart_port *port)
+{
+       struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
+       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
+       unsigned char status;
+
+       up->flags |= IP22ZILOG_FLAG_TX_ACTIVE;
+       up->flags &= ~IP22ZILOG_FLAG_TX_STOPPED;
+
+       status = readb(&channel->control);
+       ZSDELAY();
+
+       /* TX busy?  Just wait for the TX done interrupt.  */
+       if (!(status & Tx_BUF_EMP))
+               return;
+
+       /* Send the first character to jump-start the TX done
+        * IRQ sending engine.
+        */
+       if (port->x_char) {
+               writeb(port->x_char, &channel->data);
+               ZSDELAY();
+               ZS_WSYNC(channel);
+
+               port->icount.tx++;
+               port->x_char = 0;
+       } else {
+               struct circ_buf *xmit = &port->state->xmit;
+
+               writeb(xmit->buf[xmit->tail], &channel->data);
+               ZSDELAY();
+               ZS_WSYNC(channel);
+
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+
+               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+                       uart_write_wakeup(&up->port);
+       }
+}
+
+/* The port lock is held and interrupts are disabled.  */
+static void ip22zilog_stop_rx(struct uart_port *port)
+{
+       struct uart_ip22zilog_port *up = UART_ZILOG(port);
+       struct zilog_channel *channel;
+
+       if (ZS_IS_CONS(up))
+               return;
+
+       channel = ZILOG_CHANNEL_FROM_PORT(port);
+
+       /* Disable all RX interrupts.  */
+       up->curregs[R1] &= ~RxINT_MASK;
+       ip22zilog_maybe_update_regs(up, channel);
+}
+
+/* The port lock is held.  */
+static void ip22zilog_enable_ms(struct uart_port *port)
+{
+       struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
+       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
+       unsigned char new_reg;
+
+       new_reg = up->curregs[R15] | (DCDIE | SYNCIE | CTSIE);
+       if (new_reg != up->curregs[R15]) {
+               up->curregs[R15] = new_reg;
+
+               /* NOTE: Not subject to 'transmitter active' rule.  */
+               write_zsreg(channel, R15, up->curregs[R15]);
+       }
+}
+
+/* The port lock is not held.  */
+static void ip22zilog_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
+       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
+       unsigned char set_bits, clear_bits, new_reg;
+       unsigned long flags;
+
+       set_bits = clear_bits = 0;
+
+       if (break_state)
+               set_bits |= SND_BRK;
+       else
+               clear_bits |= SND_BRK;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       new_reg = (up->curregs[R5] | set_bits) & ~clear_bits;
+       if (new_reg != up->curregs[R5]) {
+               up->curregs[R5] = new_reg;
+
+               /* NOTE: Not subject to 'transmitter active' rule.  */
+               write_zsreg(channel, R5, up->curregs[R5]);
+       }
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void __ip22zilog_reset(struct uart_ip22zilog_port *up)
+{
+       struct zilog_channel *channel;
+       int i;
+
+       if (up->flags & IP22ZILOG_FLAG_RESET_DONE)
+               return;
+
+       /* Let pending transmits finish.  */
+       channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+       for (i = 0; i < 1000; i++) {
+               unsigned char stat = read_zsreg(channel, R1);
+               if (stat & ALL_SNT)
+                       break;
+               udelay(100);
+       }
+
+       if (!ZS_IS_CHANNEL_A(up)) {
+               up++;
+               channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+       }
+       write_zsreg(channel, R9, FHWRES);
+       ZSDELAY_LONG();
+       (void) read_zsreg(channel, R0);
+
+       up->flags |= IP22ZILOG_FLAG_RESET_DONE;
+       up->next->flags |= IP22ZILOG_FLAG_RESET_DONE;
+}
+
+static void __ip22zilog_startup(struct uart_ip22zilog_port *up)
+{
+       struct zilog_channel *channel;
+
+       channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+
+       __ip22zilog_reset(up);
+
+       __load_zsregs(channel, up->curregs);
+       /* set master interrupt enable */
+       write_zsreg(channel, R9, up->curregs[R9]);
+       up->prev_status = readb(&channel->control);
+
+       /* Enable receiver and transmitter.  */
+       up->curregs[R3] |= RxENAB;
+       up->curregs[R5] |= TxENAB;
+
+       up->curregs[R1] |= EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
+       ip22zilog_maybe_update_regs(up, channel);
+}
+
+static int ip22zilog_startup(struct uart_port *port)
+{
+       struct uart_ip22zilog_port *up = UART_ZILOG(port);
+       unsigned long flags;
+
+       if (ZS_IS_CONS(up))
+               return 0;
+
+       spin_lock_irqsave(&port->lock, flags);
+       __ip22zilog_startup(up);
+       spin_unlock_irqrestore(&port->lock, flags);
+       return 0;
+}
+
+/*
+ * The test for ZS_IS_CONS is explained by the following e-mail:
+ *****
+ * From: Russell King <rmk@arm.linux.org.uk>
+ * Date: Sun, 8 Dec 2002 10:18:38 +0000
+ *
+ * On Sun, Dec 08, 2002 at 02:43:36AM -0500, Pete Zaitcev wrote:
+ * > I boot my 2.5 boxes using "console=ttyS0,9600" argument,
+ * > and I noticed that something is not right with reference
+ * > counting in this case. It seems that when the console
+ * > is open by kernel initially, this is not accounted
+ * > as an open, and uart_startup is not called.
+ *
+ * That is correct.  We are unable to call uart_startup when the serial
+ * console is initialised because it may need to allocate memory (as
+ * request_irq does) and the memory allocators may not have been
+ * initialised.
+ *
+ * 1. initialise the port into a state where it can send characters in the
+ *    console write method.
+ *
+ * 2. don't do the actual hardware shutdown in your shutdown() method (but
+ *    do the normal software shutdown - ie, free irqs etc)
+ *****
+ */
+static void ip22zilog_shutdown(struct uart_port *port)
+{
+       struct uart_ip22zilog_port *up = UART_ZILOG(port);
+       struct zilog_channel *channel;
+       unsigned long flags;
+
+       if (ZS_IS_CONS(up))
+               return;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       channel = ZILOG_CHANNEL_FROM_PORT(port);
+
+       /* Disable receiver and transmitter.  */
+       up->curregs[R3] &= ~RxENAB;
+       up->curregs[R5] &= ~TxENAB;
+
+       /* Disable all interrupts and BRK assertion.  */
+       up->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
+       up->curregs[R5] &= ~SND_BRK;
+       ip22zilog_maybe_update_regs(up, channel);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* Shared by TTY driver and serial console setup.  The port lock is held
+ * and local interrupts are disabled.
+ */
+static void
+ip22zilog_convert_to_zs(struct uart_ip22zilog_port *up, unsigned int cflag,
+                      unsigned int iflag, int brg)
+{
+
+       up->curregs[R10] = NRZ;
+       up->curregs[R11] = TCBR | RCBR;
+
+       /* Program BAUD and clock source. */
+       up->curregs[R4] &= ~XCLK_MASK;
+       up->curregs[R4] |= X16CLK;
+       up->curregs[R12] = brg & 0xff;
+       up->curregs[R13] = (brg >> 8) & 0xff;
+       up->curregs[R14] = BRENAB;
+
+       /* Character size, stop bits, and parity. */
+       up->curregs[3] &= ~RxN_MASK;
+       up->curregs[5] &= ~TxN_MASK;
+       switch (cflag & CSIZE) {
+       case CS5:
+               up->curregs[3] |= Rx5;
+               up->curregs[5] |= Tx5;
+               up->parity_mask = 0x1f;
+               break;
+       case CS6:
+               up->curregs[3] |= Rx6;
+               up->curregs[5] |= Tx6;
+               up->parity_mask = 0x3f;
+               break;
+       case CS7:
+               up->curregs[3] |= Rx7;
+               up->curregs[5] |= Tx7;
+               up->parity_mask = 0x7f;
+               break;
+       case CS8:
+       default:
+               up->curregs[3] |= Rx8;
+               up->curregs[5] |= Tx8;
+               up->parity_mask = 0xff;
+               break;
+       };
+       up->curregs[4] &= ~0x0c;
+       if (cflag & CSTOPB)
+               up->curregs[4] |= SB2;
+       else
+               up->curregs[4] |= SB1;
+       if (cflag & PARENB)
+               up->curregs[4] |= PAR_ENAB;
+       else
+               up->curregs[4] &= ~PAR_ENAB;
+       if (!(cflag & PARODD))
+               up->curregs[4] |= PAR_EVEN;
+       else
+               up->curregs[4] &= ~PAR_EVEN;
+
+       up->port.read_status_mask = Rx_OVR;
+       if (iflag & INPCK)
+               up->port.read_status_mask |= CRC_ERR | PAR_ERR;
+       if (iflag & (BRKINT | PARMRK))
+               up->port.read_status_mask |= BRK_ABRT;
+
+       up->port.ignore_status_mask = 0;
+       if (iflag & IGNPAR)
+               up->port.ignore_status_mask |= CRC_ERR | PAR_ERR;
+       if (iflag & IGNBRK) {
+               up->port.ignore_status_mask |= BRK_ABRT;
+               if (iflag & IGNPAR)
+                       up->port.ignore_status_mask |= Rx_OVR;
+       }
+
+       if ((cflag & CREAD) == 0)
+               up->port.ignore_status_mask = 0xff;
+}
+
+/* The port lock is not held.  */
+static void
+ip22zilog_set_termios(struct uart_port *port, struct ktermios *termios,
+                     struct ktermios *old)
+{
+       struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
+       unsigned long flags;
+       int baud, brg;
+
+       baud = uart_get_baud_rate(port, termios, old, 1200, 76800);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
+
+       ip22zilog_convert_to_zs(up, termios->c_cflag, termios->c_iflag, brg);
+
+       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
+               up->flags |= IP22ZILOG_FLAG_MODEM_STATUS;
+       else
+               up->flags &= ~IP22ZILOG_FLAG_MODEM_STATUS;
+
+       ip22zilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port));
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static const char *ip22zilog_type(struct uart_port *port)
+{
+       return "IP22-Zilog";
+}
+
+/* We do not request/release mappings of the registers here, this
+ * happens at early serial probe time.
+ */
+static void ip22zilog_release_port(struct uart_port *port)
+{
+}
+
+static int ip22zilog_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+/* These do not need to do anything interesting either.  */
+static void ip22zilog_config_port(struct uart_port *port, int flags)
+{
+}
+
+/* We do not support letting the user mess with the divisor, IRQ, etc. */
+static int ip22zilog_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       return -EINVAL;
+}
+
+static struct uart_ops ip22zilog_pops = {
+       .tx_empty       =       ip22zilog_tx_empty,
+       .set_mctrl      =       ip22zilog_set_mctrl,
+       .get_mctrl      =       ip22zilog_get_mctrl,
+       .stop_tx        =       ip22zilog_stop_tx,
+       .start_tx       =       ip22zilog_start_tx,
+       .stop_rx        =       ip22zilog_stop_rx,
+       .enable_ms      =       ip22zilog_enable_ms,
+       .break_ctl      =       ip22zilog_break_ctl,
+       .startup        =       ip22zilog_startup,
+       .shutdown       =       ip22zilog_shutdown,
+       .set_termios    =       ip22zilog_set_termios,
+       .type           =       ip22zilog_type,
+       .release_port   =       ip22zilog_release_port,
+       .request_port   =       ip22zilog_request_port,
+       .config_port    =       ip22zilog_config_port,
+       .verify_port    =       ip22zilog_verify_port,
+};
+
+static struct uart_ip22zilog_port *ip22zilog_port_table;
+static struct zilog_layout **ip22zilog_chip_regs;
+
+static struct uart_ip22zilog_port *ip22zilog_irq_chain;
+static int zilog_irq = -1;
+
+static void * __init alloc_one_table(unsigned long size)
+{
+       return kzalloc(size, GFP_KERNEL);
+}
+
+static void __init ip22zilog_alloc_tables(void)
+{
+       ip22zilog_port_table = (struct uart_ip22zilog_port *)
+               alloc_one_table(NUM_CHANNELS * sizeof(struct uart_ip22zilog_port));
+       ip22zilog_chip_regs = (struct zilog_layout **)
+               alloc_one_table(NUM_IP22ZILOG * sizeof(struct zilog_layout *));
+
+       if (ip22zilog_port_table == NULL || ip22zilog_chip_regs == NULL) {
+               panic("IP22-Zilog: Cannot allocate IP22-Zilog tables.");
+       }
+}
+
+/* Get the address of the registers for IP22-Zilog instance CHIP.  */
+static struct zilog_layout * __init get_zs(int chip)
+{
+       unsigned long base;
+
+       if (chip < 0 || chip >= NUM_IP22ZILOG) {
+               panic("IP22-Zilog: Illegal chip number %d in get_zs.", chip);
+       }
+
+       /* Not probe-able, hard code it. */
+       base = (unsigned long) &sgioc->uart;
+
+       zilog_irq = SGI_SERIAL_IRQ;
+       request_mem_region(base, 8, "IP22-Zilog");
+
+       return (struct zilog_layout *) base;
+}
+
+#define ZS_PUT_CHAR_MAX_DELAY  2000    /* 10 ms */
+
+#ifdef CONFIG_SERIAL_IP22_ZILOG_CONSOLE
+static void ip22zilog_put_char(struct uart_port *port, int ch)
+{
+       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
+       int loops = ZS_PUT_CHAR_MAX_DELAY;
+
+       /* This is a timed polling loop so do not switch the explicit
+        * udelay with ZSDELAY as that is a NOP on some platforms.  -DaveM
+        */
+       do {
+               unsigned char val = readb(&channel->control);
+               if (val & Tx_BUF_EMP) {
+                       ZSDELAY();
+                       break;
+               }
+               udelay(5);
+       } while (--loops);
+
+       writeb(ch, &channel->data);
+       ZSDELAY();
+       ZS_WSYNC(channel);
+}
+
+static void
+ip22zilog_console_write(struct console *con, const char *s, unsigned int count)
+{
+       struct uart_ip22zilog_port *up = &ip22zilog_port_table[con->index];
+       unsigned long flags;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       uart_console_write(&up->port, s, count, ip22zilog_put_char);
+       udelay(2);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static int __init ip22zilog_console_setup(struct console *con, char *options)
+{
+       struct uart_ip22zilog_port *up = &ip22zilog_port_table[con->index];
+       unsigned long flags;
+       int baud = 9600, bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       up->flags |= IP22ZILOG_FLAG_IS_CONS;
+
+       printk(KERN_INFO "Console: ttyS%d (IP22-Zilog)\n", con->index);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       up->curregs[R15] |= BRKIE;
+
+       __ip22zilog_startup(up);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       return uart_set_options(&up->port, con, baud, parity, bits, flow);
+}
+
+static struct uart_driver ip22zilog_reg;
+
+static struct console ip22zilog_console = {
+       .name   =       "ttyS",
+       .write  =       ip22zilog_console_write,
+       .device =       uart_console_device,
+       .setup  =       ip22zilog_console_setup,
+       .flags  =       CON_PRINTBUFFER,
+       .index  =       -1,
+       .data   =       &ip22zilog_reg,
+};
+#endif /* CONFIG_SERIAL_IP22_ZILOG_CONSOLE */
+
+static struct uart_driver ip22zilog_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "serial",
+       .dev_name       = "ttyS",
+       .major          = TTY_MAJOR,
+       .minor          = 64,
+       .nr             = NUM_CHANNELS,
+#ifdef CONFIG_SERIAL_IP22_ZILOG_CONSOLE
+       .cons           = &ip22zilog_console,
+#endif
+};
+
+static void __init ip22zilog_prepare(void)
+{
+       struct uart_ip22zilog_port *up;
+       struct zilog_layout *rp;
+       int channel, chip;
+
+       /*
+        * Temporary fix.
+        */
+       for (channel = 0; channel < NUM_CHANNELS; channel++)
+               spin_lock_init(&ip22zilog_port_table[channel].port.lock);
+
+       ip22zilog_irq_chain = &ip22zilog_port_table[NUM_CHANNELS - 1];
+        up = &ip22zilog_port_table[0];
+       for (channel = NUM_CHANNELS - 1 ; channel > 0; channel--)
+               up[channel].next = &up[channel - 1];
+       up[channel].next = NULL;
+
+       for (chip = 0; chip < NUM_IP22ZILOG; chip++) {
+               if (!ip22zilog_chip_regs[chip]) {
+                       ip22zilog_chip_regs[chip] = rp = get_zs(chip);
+
+                       up[(chip * 2) + 0].port.membase = (char *) &rp->channelB;
+                       up[(chip * 2) + 1].port.membase = (char *) &rp->channelA;
+
+                       /* In theory mapbase is the physical address ...  */
+                       up[(chip * 2) + 0].port.mapbase =
+                               (unsigned long) ioremap((unsigned long) &rp->channelB, 8);
+                       up[(chip * 2) + 1].port.mapbase =
+                               (unsigned long) ioremap((unsigned long) &rp->channelA, 8);
+               }
+
+               /* Channel A */
+               up[(chip * 2) + 0].port.iotype = UPIO_MEM;
+               up[(chip * 2) + 0].port.irq = zilog_irq;
+               up[(chip * 2) + 0].port.uartclk = ZS_CLOCK;
+               up[(chip * 2) + 0].port.fifosize = 1;
+               up[(chip * 2) + 0].port.ops = &ip22zilog_pops;
+               up[(chip * 2) + 0].port.type = PORT_IP22ZILOG;
+               up[(chip * 2) + 0].port.flags = 0;
+               up[(chip * 2) + 0].port.line = (chip * 2) + 0;
+               up[(chip * 2) + 0].flags = 0;
+
+               /* Channel B */
+               up[(chip * 2) + 1].port.iotype = UPIO_MEM;
+               up[(chip * 2) + 1].port.irq = zilog_irq;
+               up[(chip * 2) + 1].port.uartclk = ZS_CLOCK;
+               up[(chip * 2) + 1].port.fifosize = 1;
+               up[(chip * 2) + 1].port.ops = &ip22zilog_pops;
+               up[(chip * 2) + 1].port.type = PORT_IP22ZILOG;
+               up[(chip * 2) + 1].port.line = (chip * 2) + 1;
+               up[(chip * 2) + 1].flags |= IP22ZILOG_FLAG_IS_CHANNEL_A;
+       }
+
+       for (channel = 0; channel < NUM_CHANNELS; channel++) {
+               struct uart_ip22zilog_port *up = &ip22zilog_port_table[channel];
+               int brg;
+
+               /* Normal serial TTY. */
+               up->parity_mask = 0xff;
+               up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
+               up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
+               up->curregs[R3] = RxENAB | Rx8;
+               up->curregs[R5] = TxENAB | Tx8;
+               up->curregs[R9] = NV | MIE;
+               up->curregs[R10] = NRZ;
+               up->curregs[R11] = TCBR | RCBR;
+               brg = BPS_TO_BRG(9600, ZS_CLOCK / ZS_CLOCK_DIVISOR);
+               up->curregs[R12] = (brg & 0xff);
+               up->curregs[R13] = (brg >> 8) & 0xff;
+               up->curregs[R14] = BRENAB;
+       }
+}
+
+static int __init ip22zilog_ports_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "Serial: IP22 Zilog driver (%d chips).\n", NUM_IP22ZILOG);
+
+       ip22zilog_prepare();
+
+       if (request_irq(zilog_irq, ip22zilog_interrupt, 0,
+                       "IP22-Zilog", ip22zilog_irq_chain)) {
+               panic("IP22-Zilog: Unable to register zs interrupt handler.\n");
+       }
+
+       ret = uart_register_driver(&ip22zilog_reg);
+       if (ret == 0) {
+               int i;
+
+               for (i = 0; i < NUM_CHANNELS; i++) {
+                       struct uart_ip22zilog_port *up = &ip22zilog_port_table[i];
+
+                       uart_add_one_port(&ip22zilog_reg, &up->port);
+               }
+       }
+
+       return ret;
+}
+
+static int __init ip22zilog_init(void)
+{
+       /* IP22 Zilog setup is hard coded, no probing to do.  */
+       ip22zilog_alloc_tables();
+       ip22zilog_ports_init();
+
+       return 0;
+}
+
+static void __exit ip22zilog_exit(void)
+{
+       int i;
+       struct uart_ip22zilog_port *up;
+
+       for (i = 0; i < NUM_CHANNELS; i++) {
+               up = &ip22zilog_port_table[i];
+
+               uart_remove_one_port(&ip22zilog_reg, &up->port);
+       }
+
+       /* Free IO mem */
+       up = &ip22zilog_port_table[0];
+       for (i = 0; i < NUM_IP22ZILOG; i++) {
+               if (up[(i * 2) + 0].port.mapbase) {
+                  iounmap((void*)up[(i * 2) + 0].port.mapbase);
+                  up[(i * 2) + 0].port.mapbase = 0;
+               }
+               if (up[(i * 2) + 1].port.mapbase) {
+                       iounmap((void*)up[(i * 2) + 1].port.mapbase);
+                       up[(i * 2) + 1].port.mapbase = 0;
+               }
+       }
+
+       uart_unregister_driver(&ip22zilog_reg);
+}
+
+module_init(ip22zilog_init);
+module_exit(ip22zilog_exit);
+
+/* David wrote it but I'm to blame for the bugs ...  */
+MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
+MODULE_DESCRIPTION("SGI Zilog serial port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/ip22zilog.h b/drivers/tty/serial/ip22zilog.h
new file mode 100644 (file)
index 0000000..a59a9a8
--- /dev/null
@@ -0,0 +1,281 @@
+#ifndef _IP22_ZILOG_H
+#define _IP22_ZILOG_H
+
+#include <asm/byteorder.h>
+
+struct zilog_channel {
+#ifdef __BIG_ENDIAN
+       volatile unsigned char unused0[3];
+       volatile unsigned char control;
+       volatile unsigned char unused1[3];
+       volatile unsigned char data;
+#else /* __LITTLE_ENDIAN */
+       volatile unsigned char control;
+       volatile unsigned char unused0[3];
+       volatile unsigned char data;
+       volatile unsigned char unused1[3];
+#endif
+};
+
+struct zilog_layout {
+       struct zilog_channel channelB;
+       struct zilog_channel channelA;
+};
+
+#define NUM_ZSREGS    16
+
+/* Conversion routines to/from brg time constants from/to bits
+ * per second.
+ */
+#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+/* The Zilog register set */
+
+#define        FLAG    0x7e
+
+/* Write Register 0 */
+#define        R0      0               /* Register selects */
+#define        R1      1
+#define        R2      2
+#define        R3      3
+#define        R4      4
+#define        R5      5
+#define        R6      6
+#define        R7      7
+#define        R8      8
+#define        R9      9
+#define        R10     10
+#define        R11     11
+#define        R12     12
+#define        R13     13
+#define        R14     14
+#define        R15     15
+
+#define        NULLCODE        0       /* Null Code */
+#define        POINT_HIGH      0x8     /* Select upper half of registers */
+#define        RES_EXT_INT     0x10    /* Reset Ext. Status Interrupts */
+#define        SEND_ABORT      0x18    /* HDLC Abort */
+#define        RES_RxINT_FC    0x20    /* Reset RxINT on First Character */
+#define        RES_Tx_P        0x28    /* Reset TxINT Pending */
+#define        ERR_RES         0x30    /* Error Reset */
+#define        RES_H_IUS       0x38    /* Reset highest IUS */
+
+#define        RES_Rx_CRC      0x40    /* Reset Rx CRC Checker */
+#define        RES_Tx_CRC      0x80    /* Reset Tx CRC Checker */
+#define        RES_EOM_L       0xC0    /* Reset EOM latch */
+
+/* Write Register 1 */
+
+#define        EXT_INT_ENAB    0x1     /* Ext Int Enable */
+#define        TxINT_ENAB      0x2     /* Tx Int Enable */
+#define        PAR_SPEC        0x4     /* Parity is special condition */
+
+#define        RxINT_DISAB     0       /* Rx Int Disable */
+#define        RxINT_FCERR     0x8     /* Rx Int on First Character Only or Error */
+#define        INT_ALL_Rx      0x10    /* Int on all Rx Characters or error */
+#define        INT_ERR_Rx      0x18    /* Int on error only */
+#define RxINT_MASK     0x18
+
+#define        WT_RDY_RT       0x20    /* Wait/Ready on R/T */
+#define        WT_FN_RDYFN     0x40    /* Wait/FN/Ready FN */
+#define        WT_RDY_ENAB     0x80    /* Wait/Ready Enable */
+
+/* Write Register #2 (Interrupt Vector) */
+
+/* Write Register 3 */
+
+#define        RxENAB          0x1     /* Rx Enable */
+#define        SYNC_L_INH      0x2     /* Sync Character Load Inhibit */
+#define        ADD_SM          0x4     /* Address Search Mode (SDLC) */
+#define        RxCRC_ENAB      0x8     /* Rx CRC Enable */
+#define        ENT_HM          0x10    /* Enter Hunt Mode */
+#define        AUTO_ENAB       0x20    /* Auto Enables */
+#define        Rx5             0x0     /* Rx 5 Bits/Character */
+#define        Rx7             0x40    /* Rx 7 Bits/Character */
+#define        Rx6             0x80    /* Rx 6 Bits/Character */
+#define        Rx8             0xc0    /* Rx 8 Bits/Character */
+#define RxN_MASK       0xc0
+
+/* Write Register 4 */
+
+#define        PAR_ENAB        0x1     /* Parity Enable */
+#define        PAR_EVEN        0x2     /* Parity Even/Odd* */
+
+#define        SYNC_ENAB       0       /* Sync Modes Enable */
+#define        SB1             0x4     /* 1 stop bit/char */
+#define        SB15            0x8     /* 1.5 stop bits/char */
+#define        SB2             0xc     /* 2 stop bits/char */
+
+#define        MONSYNC         0       /* 8 Bit Sync character */
+#define        BISYNC          0x10    /* 16 bit sync character */
+#define        SDLC            0x20    /* SDLC Mode (01111110 Sync Flag) */
+#define        EXTSYNC         0x30    /* External Sync Mode */
+
+#define        X1CLK           0x0     /* x1 clock mode */
+#define        X16CLK          0x40    /* x16 clock mode */
+#define        X32CLK          0x80    /* x32 clock mode */
+#define        X64CLK          0xC0    /* x64 clock mode */
+#define XCLK_MASK      0xC0
+
+/* Write Register 5 */
+
+#define        TxCRC_ENAB      0x1     /* Tx CRC Enable */
+#define        RTS             0x2     /* RTS */
+#define        SDLC_CRC        0x4     /* SDLC/CRC-16 */
+#define        TxENAB          0x8     /* Tx Enable */
+#define        SND_BRK         0x10    /* Send Break */
+#define        Tx5             0x0     /* Tx 5 bits (or less)/character */
+#define        Tx7             0x20    /* Tx 7 bits/character */
+#define        Tx6             0x40    /* Tx 6 bits/character */
+#define        Tx8             0x60    /* Tx 8 bits/character */
+#define TxN_MASK       0x60
+#define        DTR             0x80    /* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 8 (transmit buffer) */
+
+/* Write Register 9 (Master interrupt control) */
+#define        VIS     1       /* Vector Includes Status */
+#define        NV      2       /* No Vector */
+#define        DLC     4       /* Disable Lower Chain */
+#define        MIE     8       /* Master Interrupt Enable */
+#define        STATHI  0x10    /* Status high */
+#define        NORESET 0       /* No reset on write to R9 */
+#define        CHRB    0x40    /* Reset channel B */
+#define        CHRA    0x80    /* Reset channel A */
+#define        FHWRES  0xc0    /* Force hardware reset */
+
+/* Write Register 10 (misc control bits) */
+#define        BIT6    1       /* 6 bit/8bit sync */
+#define        LOOPMODE 2      /* SDLC Loop mode */
+#define        ABUNDER 4       /* Abort/flag on SDLC xmit underrun */
+#define        MARKIDLE 8      /* Mark/flag on idle */
+#define        GAOP    0x10    /* Go active on poll */
+#define        NRZ     0       /* NRZ mode */
+#define        NRZI    0x20    /* NRZI mode */
+#define        FM1     0x40    /* FM1 (transition = 1) */
+#define        FM0     0x60    /* FM0 (transition = 0) */
+#define        CRCPS   0x80    /* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode control) */
+#define        TRxCXT  0       /* TRxC = Xtal output */
+#define        TRxCTC  1       /* TRxC = Transmit clock */
+#define        TRxCBR  2       /* TRxC = BR Generator Output */
+#define        TRxCDP  3       /* TRxC = DPLL output */
+#define        TRxCOI  4       /* TRxC O/I */
+#define        TCRTxCP 0       /* Transmit clock = RTxC pin */
+#define        TCTRxCP 8       /* Transmit clock = TRxC pin */
+#define        TCBR    0x10    /* Transmit clock = BR Generator output */
+#define        TCDPLL  0x18    /* Transmit clock = DPLL output */
+#define        RCRTxCP 0       /* Receive clock = RTxC pin */
+#define        RCTRxCP 0x20    /* Receive clock = TRxC pin */
+#define        RCBR    0x40    /* Receive clock = BR Generator output */
+#define        RCDPLL  0x60    /* Receive clock = DPLL output */
+#define        RTxCX   0x80    /* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (lower byte of baud rate generator time constant) */
+
+/* Write Register 13 (upper byte of baud rate generator time constant) */
+
+/* Write Register 14 (Misc control bits) */
+#define        BRENAB  1       /* Baud rate generator enable */
+#define        BRSRC   2       /* Baud rate generator source */
+#define        DTRREQ  4       /* DTR/Request function */
+#define        AUTOECHO 8      /* Auto Echo */
+#define        LOOPBAK 0x10    /* Local loopback */
+#define        SEARCH  0x20    /* Enter search mode */
+#define        RMC     0x40    /* Reset missing clock */
+#define        DISDPLL 0x60    /* Disable DPLL */
+#define        SSBR    0x80    /* Set DPLL source = BR generator */
+#define        SSRTxC  0xa0    /* Set DPLL source = RTxC */
+#define        SFMM    0xc0    /* Set FM mode */
+#define        SNRZI   0xe0    /* Set NRZI mode */
+
+/* Write Register 15 (external/status interrupt control) */
+#define        ZCIE    2       /* Zero count IE */
+#define        DCDIE   8       /* DCD IE */
+#define        SYNCIE  0x10    /* Sync/hunt IE */
+#define        CTSIE   0x20    /* CTS IE */
+#define        TxUIE   0x40    /* Tx Underrun/EOM IE */
+#define        BRKIE   0x80    /* Break/Abort IE */
+
+
+/* Read Register 0 */
+#define        Rx_CH_AV        0x1     /* Rx Character Available */
+#define        ZCOUNT          0x2     /* Zero count */
+#define        Tx_BUF_EMP      0x4     /* Tx Buffer empty */
+#define        DCD             0x8     /* DCD */
+#define        SYNC            0x10    /* Sync/hunt */
+#define        CTS             0x20    /* CTS */
+#define        TxEOM           0x40    /* Tx underrun */
+#define        BRK_ABRT        0x80    /* Break/Abort */
+
+/* Read Register 1 */
+#define        ALL_SNT         0x1     /* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define        RES3            0x8     /* 0/3 */
+#define        RES4            0x4     /* 0/4 */
+#define        RES5            0xc     /* 0/5 */
+#define        RES6            0x2     /* 0/6 */
+#define        RES7            0xa     /* 0/7 */
+#define        RES8            0x6     /* 0/8 */
+#define        RES18           0xe     /* 1/8 */
+#define        RES28           0x0     /* 2/8 */
+/* Special Rx Condition Interrupts */
+#define        PAR_ERR         0x10    /* Parity error */
+#define        Rx_OVR          0x20    /* Rx Overrun Error */
+#define        CRC_ERR         0x40    /* CRC/Framing Error */
+#define        END_FR          0x80    /* End of Frame (SDLC) */
+
+/* Read Register 2 (channel b only) - Interrupt vector */
+#define CHB_Tx_EMPTY   0x00
+#define CHB_EXT_STAT   0x02
+#define CHB_Rx_AVAIL   0x04
+#define CHB_SPECIAL    0x06
+#define CHA_Tx_EMPTY   0x08
+#define CHA_EXT_STAT   0x0a
+#define CHA_Rx_AVAIL   0x0c
+#define CHA_SPECIAL    0x0e
+#define STATUS_MASK    0x0e
+
+/* Read Register 3 (interrupt pending register) ch a only */
+#define        CHBEXT  0x1             /* Channel B Ext/Stat IP */
+#define        CHBTxIP 0x2             /* Channel B Tx IP */
+#define        CHBRxIP 0x4             /* Channel B Rx IP */
+#define        CHAEXT  0x8             /* Channel A Ext/Stat IP */
+#define        CHATxIP 0x10            /* Channel A Tx IP */
+#define        CHARxIP 0x20            /* Channel A Rx IP */
+
+/* Read Register 8 (receive data register) */
+
+/* Read Register 10  (misc status bits) */
+#define        ONLOOP  2               /* On loop */
+#define        LOOPSEND 0x10           /* Loop sending */
+#define        CLK2MIS 0x40            /* Two clocks missing */
+#define        CLK1MIS 0x80            /* One clock missing */
+
+/* Read Register 12 (lower byte of baud rate generator constant) */
+
+/* Read Register 13 (upper byte of baud rate generator constant) */
+
+/* Read Register 15 (value of WR 15) */
+
+/* Misc macros */
+#define ZS_CLEARERR(channel)    do { writeb(ERR_RES, &channel->control); \
+                                    udelay(5); } while(0)
+
+#define ZS_CLEARSTAT(channel)   do { writeb(RES_EXT_INT, &channel->control); \
+                                    udelay(5); } while(0)
+
+#define ZS_CLEARFIFO(channel)   do { readb(&channel->data); \
+                                    udelay(2); \
+                                    readb(&channel->data); \
+                                    udelay(2); \
+                                    readb(&channel->data); \
+                                    udelay(2); } while(0)
+
+#endif /* _IP22_ZILOG_H */
diff --git a/drivers/tty/serial/jsm/Makefile b/drivers/tty/serial/jsm/Makefile
new file mode 100644 (file)
index 0000000..e46b6e0
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Makefile for Jasmine adapter
+#
+
+obj-$(CONFIG_SERIAL_JSM) += jsm.o
+
+jsm-objs :=    jsm_driver.o jsm_neo.o jsm_tty.o
+
diff --git a/drivers/tty/serial/jsm/jsm.h b/drivers/tty/serial/jsm/jsm.h
new file mode 100644 (file)
index 0000000..38a509c
--- /dev/null
@@ -0,0 +1,388 @@
+/************************************************************************
+ * Copyright 2003 Digi International (www.digi.com)
+ *
+ * Copyright (C) 2004 IBM Corporation. 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ * Contact Information:
+ * Scott H Kilau <Scott_Kilau@digi.com>
+ * Wendy Xiong   <wendyx@us.ibm.com>
+ *
+ ***********************************************************************/
+
+#ifndef __JSM_DRIVER_H
+#define __JSM_DRIVER_H
+
+#include <linux/kernel.h>
+#include <linux/types.h>       /* To pick up the varions Linux types */
+#include <linux/tty.h>
+#include <linux/serial_core.h>
+#include <linux/device.h>
+
+/*
+ * Debugging levels can be set using debug insmod variable
+ * They can also be compiled out completely.
+ */
+enum {
+       DBG_INIT        = 0x01,
+       DBG_BASIC       = 0x02,
+       DBG_CORE        = 0x04,
+       DBG_OPEN        = 0x08,
+       DBG_CLOSE       = 0x10,
+       DBG_READ        = 0x20,
+       DBG_WRITE       = 0x40,
+       DBG_IOCTL       = 0x80,
+       DBG_PROC        = 0x100,
+       DBG_PARAM       = 0x200,
+       DBG_PSCAN       = 0x400,
+       DBG_EVENT       = 0x800,
+       DBG_DRAIN       = 0x1000,
+       DBG_MSIGS       = 0x2000,
+       DBG_MGMT        = 0x4000,
+       DBG_INTR        = 0x8000,
+       DBG_CARR        = 0x10000,
+};
+
+#define jsm_printk(nlevel, klevel, pdev, fmt, args...) \
+       if ((DBG_##nlevel & jsm_debug))                 \
+       dev_printk(KERN_##klevel, pdev->dev, fmt, ## args)
+
+#define        MAXLINES        256
+#define MAXPORTS       8
+#define MAX_STOPS_SENT 5
+
+/* Board type definitions */
+
+#define T_NEO          0000
+#define T_CLASSIC      0001
+#define T_PCIBUS       0400
+
+/* Board State Definitions */
+
+#define BD_RUNNING     0x0
+#define BD_REASON      0x7f
+#define BD_NOTFOUND    0x1
+#define BD_NOIOPORT    0x2
+#define BD_NOMEM       0x3
+#define BD_NOBIOS      0x4
+#define BD_NOFEP       0x5
+#define BD_FAILED      0x6
+#define BD_ALLOCATED   0x7
+#define BD_TRIBOOT     0x8
+#define BD_BADKME      0x80
+
+
+/* 4 extra for alignment play space */
+#define WRITEBUFLEN    ((4096) + 4)
+#define MYFLIPLEN      N_TTY_BUF_SIZE
+
+#define JSM_VERSION    "jsm: 1.2-1-INKERNEL"
+#define JSM_PARTNUM    "40002438_A-INKERNEL"
+
+struct jsm_board;
+struct jsm_channel;
+
+/************************************************************************
+ * Per board operations structure                                      *
+ ************************************************************************/
+struct board_ops {
+       irq_handler_t intr;
+       void (*uart_init) (struct jsm_channel *ch);
+       void (*uart_off) (struct jsm_channel *ch);
+       void (*param) (struct jsm_channel *ch);
+       void (*assert_modem_signals) (struct jsm_channel *ch);
+       void (*flush_uart_write) (struct jsm_channel *ch);
+       void (*flush_uart_read) (struct jsm_channel *ch);
+       void (*disable_receiver) (struct jsm_channel *ch);
+       void (*enable_receiver) (struct jsm_channel *ch);
+       void (*send_break) (struct jsm_channel *ch);
+       void (*clear_break) (struct jsm_channel *ch, int);
+       void (*send_start_character) (struct jsm_channel *ch);
+       void (*send_stop_character) (struct jsm_channel *ch);
+       void (*copy_data_from_queue_to_uart) (struct jsm_channel *ch);
+       u32 (*get_uart_bytes_left) (struct jsm_channel *ch);
+       void (*send_immediate_char) (struct jsm_channel *ch, unsigned char);
+};
+
+
+/*
+ *     Per-board information
+ */
+struct jsm_board
+{
+       int             boardnum;       /* Board number: 0-32 */
+
+       int             type;           /* Type of board */
+       u8              rev;            /* PCI revision ID */
+       struct pci_dev  *pci_dev;
+       u32             maxports;       /* MAX ports this board can handle */
+
+       spinlock_t      bd_intr_lock;   /* Used to protect the poller tasklet and
+                                        * the interrupt routine from each other.
+                                        */
+
+       u32             nasync;         /* Number of ports on card */
+
+       u32             irq;            /* Interrupt request number */
+
+       u64             membase;        /* Start of base memory of the card */
+       u64             membase_end;    /* End of base memory of the card */
+
+       u8      __iomem *re_map_membase;/* Remapped memory of the card */
+
+       u64             iobase;         /* Start of io base of the card */
+       u64             iobase_end;     /* End of io base of the card */
+
+       u32             bd_uart_offset; /* Space between each UART */
+
+       struct jsm_channel *channels[MAXPORTS]; /* array of pointers to our channels. */
+       char            *flipbuf;       /* Our flip buffer, alloced if board is found */
+
+       u32             bd_dividend;    /* Board/UARTs specific dividend */
+
+       struct board_ops *bd_ops;
+
+       struct list_head jsm_board_entry;
+};
+
+/************************************************************************
+ * Device flag definitions for ch_flags.
+ ************************************************************************/
+#define CH_PRON                0x0001          /* Printer on string            */
+#define CH_STOP                0x0002          /* Output is stopped            */
+#define CH_STOPI       0x0004          /* Input is stopped             */
+#define CH_CD          0x0008          /* Carrier is present           */
+#define CH_FCAR                0x0010          /* Carrier forced on            */
+#define CH_HANGUP      0x0020          /* Hangup received              */
+
+#define CH_RECEIVER_OFF        0x0040          /* Receiver is off              */
+#define CH_OPENING     0x0080          /* Port in fragile open state   */
+#define CH_CLOSING     0x0100          /* Port in fragile close state  */
+#define CH_FIFO_ENABLED 0x0200         /* Port has FIFOs enabled       */
+#define CH_TX_FIFO_EMPTY 0x0400                /* TX Fifo is completely empty  */
+#define CH_TX_FIFO_LWM 0x0800          /* TX Fifo is below Low Water   */
+#define CH_BREAK_SENDING 0x1000                /* Break is being sent          */
+#define CH_LOOPBACK 0x2000             /* Channel is in lookback mode  */
+#define CH_FLIPBUF_IN_USE 0x4000       /* Channel's flipbuf is in use  */
+#define CH_BAUD0       0x08000         /* Used for checking B0 transitions */
+
+/* Our Read/Error/Write queue sizes */
+#define RQUEUEMASK     0x1FFF          /* 8 K - 1 */
+#define EQUEUEMASK     0x1FFF          /* 8 K - 1 */
+#define WQUEUEMASK     0x0FFF          /* 4 K - 1 */
+#define RQUEUESIZE     (RQUEUEMASK + 1)
+#define EQUEUESIZE     RQUEUESIZE
+#define WQUEUESIZE     (WQUEUEMASK + 1)
+
+
+/************************************************************************
+ * Channel information structure.
+ ************************************************************************/
+struct jsm_channel {
+       struct uart_port uart_port;
+       struct jsm_board        *ch_bd;         /* Board structure pointer      */
+
+       spinlock_t      ch_lock;        /* provide for serialization */
+       wait_queue_head_t ch_flags_wait;
+
+       u32             ch_portnum;     /* Port number, 0 offset.       */
+       u32             ch_open_count;  /* open count                   */
+       u32             ch_flags;       /* Channel flags                */
+
+       u64             ch_close_delay; /* How long we should drop RTS/DTR for */
+
+       tcflag_t        ch_c_iflag;     /* channel iflags               */
+       tcflag_t        ch_c_cflag;     /* channel cflags               */
+       tcflag_t        ch_c_oflag;     /* channel oflags               */
+       tcflag_t        ch_c_lflag;     /* channel lflags               */
+       u8              ch_stopc;       /* Stop character               */
+       u8              ch_startc;      /* Start character              */
+
+       u8              ch_mostat;      /* FEP output modem status      */
+       u8              ch_mistat;      /* FEP input modem status       */
+
+       struct neo_uart_struct __iomem *ch_neo_uart;    /* Pointer to the "mapped" UART struct */
+       u8              ch_cached_lsr;  /* Cached value of the LSR register */
+
+       u8              *ch_rqueue;     /* Our read queue buffer - malloc'ed */
+       u16             ch_r_head;      /* Head location of the read queue */
+       u16             ch_r_tail;      /* Tail location of the read queue */
+
+       u8              *ch_equeue;     /* Our error queue buffer - malloc'ed */
+       u16             ch_e_head;      /* Head location of the error queue */
+       u16             ch_e_tail;      /* Tail location of the error queue */
+
+       u8              *ch_wqueue;     /* Our write queue buffer - malloc'ed */
+       u16             ch_w_head;      /* Head location of the write queue */
+       u16             ch_w_tail;      /* Tail location of the write queue */
+
+       u64             ch_rxcount;     /* total of data received so far */
+       u64             ch_txcount;     /* total of data transmitted so far */
+
+       u8              ch_r_tlevel;    /* Receive Trigger level */
+       u8              ch_t_tlevel;    /* Transmit Trigger level */
+
+       u8              ch_r_watermark; /* Receive Watermark */
+
+
+       u32             ch_stops_sent;  /* How many times I have sent a stop character
+                                        * to try to stop the other guy sending.
+                                        */
+       u64             ch_err_parity;  /* Count of parity errors on channel */
+       u64             ch_err_frame;   /* Count of framing errors on channel */
+       u64             ch_err_break;   /* Count of breaks on channel */
+       u64             ch_err_overrun; /* Count of overruns on channel */
+
+       u64             ch_xon_sends;   /* Count of xons transmitted */
+       u64             ch_xoff_sends;  /* Count of xoffs transmitted */
+};
+
+
+/************************************************************************
+ * Per channel/port NEO UART structure                                 *
+ ************************************************************************
+ *             Base Structure Entries Usage Meanings to Host           *
+ *                                                                     *
+ *     W = read write          R = read only                           *
+ *                     U = Unused.                                     *
+ ************************************************************************/
+
+struct neo_uart_struct {
+        u8 txrx;               /* WR   RHR/THR - Holding Reg */
+        u8 ier;                /* WR   IER - Interrupt Enable Reg */
+        u8 isr_fcr;            /* WR   ISR/FCR - Interrupt Status Reg/Fifo Control Reg */
+        u8 lcr;                /* WR   LCR - Line Control Reg */
+        u8 mcr;                /* WR   MCR - Modem Control Reg */
+        u8 lsr;                /* WR   LSR - Line Status Reg */
+        u8 msr;                /* WR   MSR - Modem Status Reg */
+        u8 spr;                /* WR   SPR - Scratch Pad Reg */
+        u8 fctr;               /* WR   FCTR - Feature Control Reg */
+        u8 efr;                /* WR   EFR - Enhanced Function Reg */
+        u8 tfifo;              /* WR   TXCNT/TXTRG - Transmit FIFO Reg */
+        u8 rfifo;              /* WR   RXCNT/RXTRG - Recieve FIFO Reg */
+        u8 xoffchar1;  /* WR   XOFF 1 - XOff Character 1 Reg */
+        u8 xoffchar2;  /* WR   XOFF 2 - XOff Character 2 Reg */
+        u8 xonchar1;   /* WR   XON 1 - Xon Character 1 Reg */
+        u8 xonchar2;   /* WR   XON 2 - XOn Character 2 Reg */
+
+        u8 reserved1[0x2ff - 0x200]; /* U      Reserved by Exar */
+        u8 txrxburst[64];      /* RW   64 bytes of RX/TX FIFO Data */
+        u8 reserved2[0x37f - 0x340]; /* U      Reserved by Exar */
+        u8 rxburst_with_errors[64];    /* R    64 bytes of RX FIFO Data + LSR */
+};
+
+/* Where to read the extended interrupt register (32bits instead of 8bits) */
+#define        UART_17158_POLL_ADDR_OFFSET     0x80
+
+/*
+ * These are the redefinitions for the FCTR on the XR17C158, since
+ * Exar made them different than their earlier design. (XR16C854)
+ */
+
+/* These are only applicable when table D is selected */
+#define UART_17158_FCTR_RTS_NODELAY    0x00
+#define UART_17158_FCTR_RTS_4DELAY     0x01
+#define UART_17158_FCTR_RTS_6DELAY     0x02
+#define UART_17158_FCTR_RTS_8DELAY     0x03
+#define UART_17158_FCTR_RTS_12DELAY    0x12
+#define UART_17158_FCTR_RTS_16DELAY    0x05
+#define UART_17158_FCTR_RTS_20DELAY    0x13
+#define UART_17158_FCTR_RTS_24DELAY    0x06
+#define UART_17158_FCTR_RTS_28DELAY    0x14
+#define UART_17158_FCTR_RTS_32DELAY    0x07
+#define UART_17158_FCTR_RTS_36DELAY    0x16
+#define UART_17158_FCTR_RTS_40DELAY    0x08
+#define UART_17158_FCTR_RTS_44DELAY    0x09
+#define UART_17158_FCTR_RTS_48DELAY    0x10
+#define UART_17158_FCTR_RTS_52DELAY    0x11
+
+#define UART_17158_FCTR_RTS_IRDA       0x10
+#define UART_17158_FCTR_RS485          0x20
+#define UART_17158_FCTR_TRGA           0x00
+#define UART_17158_FCTR_TRGB           0x40
+#define UART_17158_FCTR_TRGC           0x80
+#define UART_17158_FCTR_TRGD           0xC0
+
+/* 17158 trigger table selects.. */
+#define UART_17158_FCTR_BIT6           0x40
+#define UART_17158_FCTR_BIT7           0x80
+
+/* 17158 TX/RX memmapped buffer offsets */
+#define UART_17158_RX_FIFOSIZE         64
+#define UART_17158_TX_FIFOSIZE         64
+
+/* 17158 Extended IIR's */
+#define UART_17158_IIR_RDI_TIMEOUT     0x0C    /* Receiver data TIMEOUT */
+#define UART_17158_IIR_XONXOFF         0x10    /* Received an XON/XOFF char */
+#define UART_17158_IIR_HWFLOW_STATE_CHANGE 0x20        /* CTS/DSR or RTS/DTR state change */
+#define UART_17158_IIR_FIFO_ENABLED    0xC0    /* 16550 FIFOs are Enabled */
+
+/*
+ * These are the extended interrupts that get sent
+ * back to us from the UART's 32bit interrupt register
+ */
+#define UART_17158_RX_LINE_STATUS      0x1     /* RX Ready */
+#define UART_17158_RXRDY_TIMEOUT       0x2     /* RX Ready Timeout */
+#define UART_17158_TXRDY               0x3     /* TX Ready */
+#define UART_17158_MSR                 0x4     /* Modem State Change */
+#define UART_17158_TX_AND_FIFO_CLR     0x40    /* Transmitter Holding Reg Empty */
+#define UART_17158_RX_FIFO_DATA_ERROR  0x80    /* UART detected an RX FIFO Data error */
+
+/*
+ * These are the EXTENDED definitions for the 17C158's Interrupt
+ * Enable Register.
+ */
+#define UART_17158_EFR_ECB     0x10    /* Enhanced control bit */
+#define UART_17158_EFR_IXON    0x2     /* Receiver compares Xon1/Xoff1 */
+#define UART_17158_EFR_IXOFF   0x8     /* Transmit Xon1/Xoff1 */
+#define UART_17158_EFR_RTSDTR  0x40    /* Auto RTS/DTR Flow Control Enable */
+#define UART_17158_EFR_CTSDSR  0x80    /* Auto CTS/DSR Flow COntrol Enable */
+
+#define UART_17158_XOFF_DETECT 0x1     /* Indicates whether chip saw an incoming XOFF char */
+#define UART_17158_XON_DETECT  0x2     /* Indicates whether chip saw an incoming XON char */
+
+#define UART_17158_IER_RSVD1   0x10    /* Reserved by Exar */
+#define UART_17158_IER_XOFF    0x20    /* Xoff Interrupt Enable */
+#define UART_17158_IER_RTSDTR  0x40    /* Output Interrupt Enable */
+#define UART_17158_IER_CTSDSR  0x80    /* Input Interrupt Enable */
+
+#define PCI_DEVICE_NEO_2DB9_PCI_NAME           "Neo 2 - DB9 Universal PCI"
+#define PCI_DEVICE_NEO_2DB9PRI_PCI_NAME                "Neo 2 - DB9 Universal PCI - Powered Ring Indicator"
+#define PCI_DEVICE_NEO_2RJ45_PCI_NAME          "Neo 2 - RJ45 Universal PCI"
+#define PCI_DEVICE_NEO_2RJ45PRI_PCI_NAME       "Neo 2 - RJ45 Universal PCI - Powered Ring Indicator"
+#define PCIE_DEVICE_NEO_IBM_PCI_NAME           "Neo 4 - PCI Express - IBM"
+
+/*
+ * Our Global Variables.
+ */
+extern struct  uart_driver jsm_uart_driver;
+extern struct  board_ops jsm_neo_ops;
+extern int     jsm_debug;
+
+/*************************************************************************
+ *
+ * Prototypes for non-static functions used in more than one module
+ *
+ *************************************************************************/
+int jsm_tty_write(struct uart_port *port);
+int jsm_tty_init(struct jsm_board *);
+int jsm_uart_port_init(struct jsm_board *);
+int jsm_remove_uart_port(struct jsm_board *);
+void jsm_input(struct jsm_channel *ch);
+void jsm_check_queue_flow_control(struct jsm_channel *ch);
+
+#endif
diff --git a/drivers/tty/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c
new file mode 100644 (file)
index 0000000..18f5484
--- /dev/null
@@ -0,0 +1,297 @@
+/************************************************************************
+ * Copyright 2003 Digi International (www.digi.com)
+ *
+ * Copyright (C) 2004 IBM Corporation. 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ * Contact Information:
+ * Scott H Kilau <Scott_Kilau@digi.com>
+ * Wendy Xiong   <wendyx@us.ibm.com>
+ *
+ *
+ ***********************************************************************/
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include "jsm.h"
+
+MODULE_AUTHOR("Digi International, http://www.digi.com");
+MODULE_DESCRIPTION("Driver for the Digi International "
+                  "Neo PCI based product line");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("jsm");
+
+#define JSM_DRIVER_NAME "jsm"
+#define NR_PORTS       32
+#define JSM_MINOR_START        0
+
+struct uart_driver jsm_uart_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = JSM_DRIVER_NAME,
+       .dev_name       = "ttyn",
+       .major          = 0,
+       .minor          = JSM_MINOR_START,
+       .nr             = NR_PORTS,
+};
+
+static pci_ers_result_t jsm_io_error_detected(struct pci_dev *pdev,
+                                       pci_channel_state_t state);
+static pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev);
+static void jsm_io_resume(struct pci_dev *pdev);
+
+static struct pci_error_handlers jsm_err_handler = {
+       .error_detected = jsm_io_error_detected,
+       .slot_reset = jsm_io_slot_reset,
+       .resume = jsm_io_resume,
+};
+
+int jsm_debug;
+module_param(jsm_debug, int, 0);
+MODULE_PARM_DESC(jsm_debug, "Driver debugging level");
+
+static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       int rc = 0;
+       struct jsm_board *brd;
+       static int adapter_count = 0;
+
+       rc = pci_enable_device(pdev);
+       if (rc) {
+               dev_err(&pdev->dev, "Device enable FAILED\n");
+               goto out;
+       }
+
+       rc = pci_request_regions(pdev, "jsm");
+       if (rc) {
+               dev_err(&pdev->dev, "pci_request_region FAILED\n");
+               goto out_disable_device;
+       }
+
+       brd = kzalloc(sizeof(struct jsm_board), GFP_KERNEL);
+       if (!brd) {
+               dev_err(&pdev->dev,
+                       "memory allocation for board structure failed\n");
+               rc = -ENOMEM;
+               goto out_release_regions;
+       }
+
+       /* store the info for the board we've found */
+       brd->boardnum = adapter_count++;
+       brd->pci_dev = pdev;
+       if (pdev->device == PCIE_DEVICE_ID_NEO_4_IBM)
+               brd->maxports = 4;
+       else if (pdev->device == PCI_DEVICE_ID_DIGI_NEO_8)
+               brd->maxports = 8;
+       else
+               brd->maxports = 2;
+
+       spin_lock_init(&brd->bd_intr_lock);
+
+       /* store which revision we have */
+       brd->rev = pdev->revision;
+
+       brd->irq = pdev->irq;
+
+       jsm_printk(INIT, INFO, &brd->pci_dev,
+               "jsm_found_board - NEO adapter\n");
+
+       /* get the PCI Base Address Registers */
+       brd->membase    = pci_resource_start(pdev, 0);
+       brd->membase_end = pci_resource_end(pdev, 0);
+
+       if (brd->membase & 1)
+               brd->membase &= ~3;
+       else
+               brd->membase &= ~15;
+
+       /* Assign the board_ops struct */
+       brd->bd_ops = &jsm_neo_ops;
+
+       brd->bd_uart_offset = 0x200;
+       brd->bd_dividend = 921600;
+
+       brd->re_map_membase = ioremap(brd->membase, 0x1000);
+       if (!brd->re_map_membase) {
+               dev_err(&pdev->dev,
+                       "card has no PCI Memory resources, "
+                       "failing board.\n");
+               rc = -ENOMEM;
+               goto out_kfree_brd;
+       }
+
+       rc = request_irq(brd->irq, brd->bd_ops->intr,
+                       IRQF_SHARED, "JSM", brd);
+       if (rc) {
+               printk(KERN_WARNING "Failed to hook IRQ %d\n",brd->irq);
+               goto out_iounmap;
+       }
+
+       rc = jsm_tty_init(brd);
+       if (rc < 0) {
+               dev_err(&pdev->dev, "Can't init tty devices (%d)\n", rc);
+               rc = -ENXIO;
+               goto out_free_irq;
+       }
+
+       rc = jsm_uart_port_init(brd);
+       if (rc < 0) {
+               /* XXX: leaking all resources from jsm_tty_init here! */
+               dev_err(&pdev->dev, "Can't init uart port (%d)\n", rc);
+               rc = -ENXIO;
+               goto out_free_irq;
+       }
+
+       /* Log the information about the board */
+       dev_info(&pdev->dev, "board %d: Digi Neo (rev %d), irq %d\n",
+                       adapter_count, brd->rev, brd->irq);
+
+       /*
+        * allocate flip buffer for board.
+        *
+        * Okay to malloc with GFP_KERNEL, we are not at interrupt
+        * context, and there are no locks held.
+        */
+       brd->flipbuf = kzalloc(MYFLIPLEN, GFP_KERNEL);
+       if (!brd->flipbuf) {
+               /* XXX: leaking all resources from jsm_tty_init and
+                       jsm_uart_port_init here! */
+               dev_err(&pdev->dev, "memory allocation for flipbuf failed\n");
+               rc = -ENOMEM;
+               goto out_free_uart;
+       }
+
+       pci_set_drvdata(pdev, brd);
+       pci_save_state(pdev);
+
+       return 0;
+ out_free_uart:
+       jsm_remove_uart_port(brd);
+ out_free_irq:
+       jsm_remove_uart_port(brd);
+       free_irq(brd->irq, brd);
+ out_iounmap:
+       iounmap(brd->re_map_membase);
+ out_kfree_brd:
+       kfree(brd);
+ out_release_regions:
+       pci_release_regions(pdev);
+ out_disable_device:
+       pci_disable_device(pdev);
+ out:
+       return rc;
+}
+
+static void __devexit jsm_remove_one(struct pci_dev *pdev)
+{
+       struct jsm_board *brd = pci_get_drvdata(pdev);
+       int i = 0;
+
+       jsm_remove_uart_port(brd);
+
+       free_irq(brd->irq, brd);
+       iounmap(brd->re_map_membase);
+
+       /* Free all allocated channels structs */
+       for (i = 0; i < brd->maxports; i++) {
+               if (brd->channels[i]) {
+                       kfree(brd->channels[i]->ch_rqueue);
+                       kfree(brd->channels[i]->ch_equeue);
+                       kfree(brd->channels[i]->ch_wqueue);
+                       kfree(brd->channels[i]);
+               }
+       }
+
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       kfree(brd->flipbuf);
+       kfree(brd);
+}
+
+static struct pci_device_id jsm_pci_tbl[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9), 0, 0, 0 },
+       { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9PRI), 0, 0, 1 },
+       { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45), 0, 0, 2 },
+       { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45PRI), 0, 0, 3 },
+       { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4_IBM), 0, 0, 4 },
+       { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_NEO_8), 0, 0, 5 },
+       { 0, }
+};
+MODULE_DEVICE_TABLE(pci, jsm_pci_tbl);
+
+static struct pci_driver jsm_driver = {
+       .name           = "jsm",
+       .id_table       = jsm_pci_tbl,
+       .probe          = jsm_probe_one,
+       .remove         = __devexit_p(jsm_remove_one),
+       .err_handler    = &jsm_err_handler,
+};
+
+static pci_ers_result_t jsm_io_error_detected(struct pci_dev *pdev,
+                                       pci_channel_state_t state)
+{
+       struct jsm_board *brd = pci_get_drvdata(pdev);
+
+       jsm_remove_uart_port(brd);
+
+       return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev)
+{
+       int rc;
+
+       rc = pci_enable_device(pdev);
+
+       if (rc)
+               return PCI_ERS_RESULT_DISCONNECT;
+
+       pci_set_master(pdev);
+
+       return PCI_ERS_RESULT_RECOVERED;
+}
+
+static void jsm_io_resume(struct pci_dev *pdev)
+{
+       struct jsm_board *brd = pci_get_drvdata(pdev);
+
+       pci_restore_state(pdev);
+
+       jsm_uart_port_init(brd);
+}
+
+static int __init jsm_init_module(void)
+{
+       int rc;
+
+       rc = uart_register_driver(&jsm_uart_driver);
+       if (!rc) {
+               rc = pci_register_driver(&jsm_driver);
+               if (rc)
+                       uart_unregister_driver(&jsm_uart_driver);
+       }
+       return rc;
+}
+
+static void __exit jsm_exit_module(void)
+{
+       pci_unregister_driver(&jsm_driver);
+       uart_unregister_driver(&jsm_uart_driver);
+}
+
+module_init(jsm_init_module);
+module_exit(jsm_exit_module);
diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c
new file mode 100644 (file)
index 0000000..7960d96
--- /dev/null
@@ -0,0 +1,1412 @@
+/************************************************************************
+ * Copyright 2003 Digi International (www.digi.com)
+ *
+ * Copyright (C) 2004 IBM Corporation. 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ * Contact Information:
+ * Scott H Kilau <Scott_Kilau@digi.com>
+ * Wendy Xiong   <wendyx@us.ibm.com>
+ *
+ ***********************************************************************/
+#include <linux/delay.h>       /* For udelay */
+#include <linux/serial_reg.h>  /* For the various UART offsets */
+#include <linux/tty.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#include "jsm.h"               /* Driver main header file */
+
+static u32 jsm_offset_table[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
+
+/*
+ * This function allows calls to ensure that all outstanding
+ * PCI writes have been completed, by doing a PCI read against
+ * a non-destructive, read-only location on the Neo card.
+ *
+ * In this case, we are reading the DVID (Read-only Device Identification)
+ * value of the Neo card.
+ */
+static inline void neo_pci_posting_flush(struct jsm_board *bd)
+{
+      readb(bd->re_map_membase + 0x8D);
+}
+
+static void neo_set_cts_flow_control(struct jsm_channel *ch)
+{
+       u8 ier, efr;
+       ier = readb(&ch->ch_neo_uart->ier);
+       efr = readb(&ch->ch_neo_uart->efr);
+
+       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting CTSFLOW\n");
+
+       /* Turn on auto CTS flow control */
+       ier |= (UART_17158_IER_CTSDSR);
+       efr |= (UART_17158_EFR_ECB | UART_17158_EFR_CTSDSR);
+
+       /* Turn off auto Xon flow control */
+       efr &= ~(UART_17158_EFR_IXON);
+
+       /* Why? Becuz Exar's spec says we have to zero it out before setting it */
+       writeb(0, &ch->ch_neo_uart->efr);
+
+       /* Turn on UART enhanced bits */
+       writeb(efr, &ch->ch_neo_uart->efr);
+
+       /* Turn on table D, with 8 char hi/low watermarks */
+       writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_4DELAY), &ch->ch_neo_uart->fctr);
+
+       /* Feed the UART our trigger levels */
+       writeb(8, &ch->ch_neo_uart->tfifo);
+       ch->ch_t_tlevel = 8;
+
+       writeb(ier, &ch->ch_neo_uart->ier);
+}
+
+static void neo_set_rts_flow_control(struct jsm_channel *ch)
+{
+       u8 ier, efr;
+       ier = readb(&ch->ch_neo_uart->ier);
+       efr = readb(&ch->ch_neo_uart->efr);
+
+       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting RTSFLOW\n");
+
+       /* Turn on auto RTS flow control */
+       ier |= (UART_17158_IER_RTSDTR);
+       efr |= (UART_17158_EFR_ECB | UART_17158_EFR_RTSDTR);
+
+       /* Turn off auto Xoff flow control */
+       ier &= ~(UART_17158_IER_XOFF);
+       efr &= ~(UART_17158_EFR_IXOFF);
+
+       /* Why? Becuz Exar's spec says we have to zero it out before setting it */
+       writeb(0, &ch->ch_neo_uart->efr);
+
+       /* Turn on UART enhanced bits */
+       writeb(efr, &ch->ch_neo_uart->efr);
+
+       writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_4DELAY), &ch->ch_neo_uart->fctr);
+       ch->ch_r_watermark = 4;
+
+       writeb(56, &ch->ch_neo_uart->rfifo);
+       ch->ch_r_tlevel = 56;
+
+       writeb(ier, &ch->ch_neo_uart->ier);
+
+       /*
+        * From the Neo UART spec sheet:
+        * The auto RTS/DTR function must be started by asserting
+        * RTS/DTR# output pin (MCR bit-0 or 1 to logic 1 after
+        * it is enabled.
+        */
+       ch->ch_mostat |= (UART_MCR_RTS);
+}
+
+
+static void neo_set_ixon_flow_control(struct jsm_channel *ch)
+{
+       u8 ier, efr;
+       ier = readb(&ch->ch_neo_uart->ier);
+       efr = readb(&ch->ch_neo_uart->efr);
+
+       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting IXON FLOW\n");
+
+       /* Turn off auto CTS flow control */
+       ier &= ~(UART_17158_IER_CTSDSR);
+       efr &= ~(UART_17158_EFR_CTSDSR);
+
+       /* Turn on auto Xon flow control */
+       efr |= (UART_17158_EFR_ECB | UART_17158_EFR_IXON);
+
+       /* Why? Becuz Exar's spec says we have to zero it out before setting it */
+       writeb(0, &ch->ch_neo_uart->efr);
+
+       /* Turn on UART enhanced bits */
+       writeb(efr, &ch->ch_neo_uart->efr);
+
+       writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
+       ch->ch_r_watermark = 4;
+
+       writeb(32, &ch->ch_neo_uart->rfifo);
+       ch->ch_r_tlevel = 32;
+
+       /* Tell UART what start/stop chars it should be looking for */
+       writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1);
+       writeb(0, &ch->ch_neo_uart->xonchar2);
+
+       writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1);
+       writeb(0, &ch->ch_neo_uart->xoffchar2);
+
+       writeb(ier, &ch->ch_neo_uart->ier);
+}
+
+static void neo_set_ixoff_flow_control(struct jsm_channel *ch)
+{
+       u8 ier, efr;
+       ier = readb(&ch->ch_neo_uart->ier);
+       efr = readb(&ch->ch_neo_uart->efr);
+
+       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting IXOFF FLOW\n");
+
+       /* Turn off auto RTS flow control */
+       ier &= ~(UART_17158_IER_RTSDTR);
+       efr &= ~(UART_17158_EFR_RTSDTR);
+
+       /* Turn on auto Xoff flow control */
+       ier |= (UART_17158_IER_XOFF);
+       efr |= (UART_17158_EFR_ECB | UART_17158_EFR_IXOFF);
+
+       /* Why? Becuz Exar's spec says we have to zero it out before setting it */
+       writeb(0, &ch->ch_neo_uart->efr);
+
+       /* Turn on UART enhanced bits */
+       writeb(efr, &ch->ch_neo_uart->efr);
+
+       /* Turn on table D, with 8 char hi/low watermarks */
+       writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
+
+       writeb(8, &ch->ch_neo_uart->tfifo);
+       ch->ch_t_tlevel = 8;
+
+       /* Tell UART what start/stop chars it should be looking for */
+       writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1);
+       writeb(0, &ch->ch_neo_uart->xonchar2);
+
+       writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1);
+       writeb(0, &ch->ch_neo_uart->xoffchar2);
+
+       writeb(ier, &ch->ch_neo_uart->ier);
+}
+
+static void neo_set_no_input_flow_control(struct jsm_channel *ch)
+{
+       u8 ier, efr;
+       ier = readb(&ch->ch_neo_uart->ier);
+       efr = readb(&ch->ch_neo_uart->efr);
+
+       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Unsetting Input FLOW\n");
+
+       /* Turn off auto RTS flow control */
+       ier &= ~(UART_17158_IER_RTSDTR);
+       efr &= ~(UART_17158_EFR_RTSDTR);
+
+       /* Turn off auto Xoff flow control */
+       ier &= ~(UART_17158_IER_XOFF);
+       if (ch->ch_c_iflag & IXON)
+               efr &= ~(UART_17158_EFR_IXOFF);
+       else
+               efr &= ~(UART_17158_EFR_ECB | UART_17158_EFR_IXOFF);
+
+       /* Why? Becuz Exar's spec says we have to zero it out before setting it */
+       writeb(0, &ch->ch_neo_uart->efr);
+
+       /* Turn on UART enhanced bits */
+       writeb(efr, &ch->ch_neo_uart->efr);
+
+       /* Turn on table D, with 8 char hi/low watermarks */
+       writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
+
+       ch->ch_r_watermark = 0;
+
+       writeb(16, &ch->ch_neo_uart->tfifo);
+       ch->ch_t_tlevel = 16;
+
+       writeb(16, &ch->ch_neo_uart->rfifo);
+       ch->ch_r_tlevel = 16;
+
+       writeb(ier, &ch->ch_neo_uart->ier);
+}
+
+static void neo_set_no_output_flow_control(struct jsm_channel *ch)
+{
+       u8 ier, efr;
+       ier = readb(&ch->ch_neo_uart->ier);
+       efr = readb(&ch->ch_neo_uart->efr);
+
+       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Unsetting Output FLOW\n");
+
+       /* Turn off auto CTS flow control */
+       ier &= ~(UART_17158_IER_CTSDSR);
+       efr &= ~(UART_17158_EFR_CTSDSR);
+
+       /* Turn off auto Xon flow control */
+       if (ch->ch_c_iflag & IXOFF)
+               efr &= ~(UART_17158_EFR_IXON);
+       else
+               efr &= ~(UART_17158_EFR_ECB | UART_17158_EFR_IXON);
+
+       /* Why? Becuz Exar's spec says we have to zero it out before setting it */
+       writeb(0, &ch->ch_neo_uart->efr);
+
+       /* Turn on UART enhanced bits */
+       writeb(efr, &ch->ch_neo_uart->efr);
+
+       /* Turn on table D, with 8 char hi/low watermarks */
+       writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
+
+       ch->ch_r_watermark = 0;
+
+       writeb(16, &ch->ch_neo_uart->tfifo);
+       ch->ch_t_tlevel = 16;
+
+       writeb(16, &ch->ch_neo_uart->rfifo);
+       ch->ch_r_tlevel = 16;
+
+       writeb(ier, &ch->ch_neo_uart->ier);
+}
+
+static inline void neo_set_new_start_stop_chars(struct jsm_channel *ch)
+{
+
+       /* if hardware flow control is set, then skip this whole thing */
+       if (ch->ch_c_cflag & CRTSCTS)
+               return;
+
+       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "start\n");
+
+       /* Tell UART what start/stop chars it should be looking for */
+       writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1);
+       writeb(0, &ch->ch_neo_uart->xonchar2);
+
+       writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1);
+       writeb(0, &ch->ch_neo_uart->xoffchar2);
+}
+
+static void neo_copy_data_from_uart_to_queue(struct jsm_channel *ch)
+{
+       int qleft = 0;
+       u8 linestatus = 0;
+       u8 error_mask = 0;
+       int n = 0;
+       int total = 0;
+       u16 head;
+       u16 tail;
+
+       if (!ch)
+               return;
+
+       /* cache head and tail of queue */
+       head = ch->ch_r_head & RQUEUEMASK;
+       tail = ch->ch_r_tail & RQUEUEMASK;
+
+       /* Get our cached LSR */
+       linestatus = ch->ch_cached_lsr;
+       ch->ch_cached_lsr = 0;
+
+       /* Store how much space we have left in the queue */
+       if ((qleft = tail - head - 1) < 0)
+               qleft += RQUEUEMASK + 1;
+
+       /*
+        * If the UART is not in FIFO mode, force the FIFO copy to
+        * NOT be run, by setting total to 0.
+        *
+        * On the other hand, if the UART IS in FIFO mode, then ask
+        * the UART to give us an approximation of data it has RX'ed.
+        */
+       if (!(ch->ch_flags & CH_FIFO_ENABLED))
+               total = 0;
+       else {
+               total = readb(&ch->ch_neo_uart->rfifo);
+
+               /*
+                * EXAR chip bug - RX FIFO COUNT - Fudge factor.
+                *
+                * This resolves a problem/bug with the Exar chip that sometimes
+                * returns a bogus value in the rfifo register.
+                * The count can be any where from 0-3 bytes "off".
+                * Bizarre, but true.
+                */
+               total -= 3;
+       }
+
+       /*
+        * Finally, bound the copy to make sure we don't overflow
+        * our own queue...
+        * The byte by byte copy loop below this loop this will
+        * deal with the queue overflow possibility.
+        */
+       total = min(total, qleft);
+
+       while (total > 0) {
+               /*
+                * Grab the linestatus register, we need to check
+                * to see if there are any errors in the FIFO.
+                */
+               linestatus = readb(&ch->ch_neo_uart->lsr);
+
+               /*
+                * Break out if there is a FIFO error somewhere.
+                * This will allow us to go byte by byte down below,
+                * finding the exact location of the error.
+                */
+               if (linestatus & UART_17158_RX_FIFO_DATA_ERROR)
+                       break;
+
+               /* Make sure we don't go over the end of our queue */
+               n = min(((u32) total), (RQUEUESIZE - (u32) head));
+
+               /*
+                * Cut down n even further if needed, this is to fix
+                * a problem with memcpy_fromio() with the Neo on the
+                * IBM pSeries platform.
+                * 15 bytes max appears to be the magic number.
+                */
+               n = min((u32) n, (u32) 12);
+
+               /*
+                * Since we are grabbing the linestatus register, which
+                * will reset some bits after our read, we need to ensure
+                * we don't miss our TX FIFO emptys.
+                */
+               if (linestatus & (UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR))
+                       ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+
+               linestatus = 0;
+
+               /* Copy data from uart to the queue */
+               memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, n);
+               /*
+                * Since RX_FIFO_DATA_ERROR was 0, we are guarenteed
+                * that all the data currently in the FIFO is free of
+                * breaks and parity/frame/orun errors.
+                */
+               memset(ch->ch_equeue + head, 0, n);
+
+               /* Add to and flip head if needed */
+               head = (head + n) & RQUEUEMASK;
+               total -= n;
+               qleft -= n;
+               ch->ch_rxcount += n;
+       }
+
+       /*
+        * Create a mask to determine whether we should
+        * insert the character (if any) into our queue.
+        */
+       if (ch->ch_c_iflag & IGNBRK)
+               error_mask |= UART_LSR_BI;
+
+       /*
+        * Now cleanup any leftover bytes still in the UART.
+        * Also deal with any possible queue overflow here as well.
+        */
+       while (1) {
+
+               /*
+                * Its possible we have a linestatus from the loop above
+                * this, so we "OR" on any extra bits.
+                */
+               linestatus |= readb(&ch->ch_neo_uart->lsr);
+
+               /*
+                * If the chip tells us there is no more data pending to
+                * be read, we can then leave.
+                * But before we do, cache the linestatus, just in case.
+                */
+               if (!(linestatus & UART_LSR_DR)) {
+                       ch->ch_cached_lsr = linestatus;
+                       break;
+               }
+
+               /* No need to store this bit */
+               linestatus &= ~UART_LSR_DR;
+
+               /*
+                * Since we are grabbing the linestatus register, which
+                * will reset some bits after our read, we need to ensure
+                * we don't miss our TX FIFO emptys.
+                */
+               if (linestatus & (UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR)) {
+                       linestatus &= ~(UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR);
+                       ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+               }
+
+               /*
+                * Discard character if we are ignoring the error mask.
+                */
+               if (linestatus & error_mask) {
+                       u8 discard;
+                       linestatus = 0;
+                       memcpy_fromio(&discard, &ch->ch_neo_uart->txrxburst, 1);
+                       continue;
+               }
+
+               /*
+                * If our queue is full, we have no choice but to drop some data.
+                * The assumption is that HWFLOW or SWFLOW should have stopped
+                * things way way before we got to this point.
+                *
+                * I decided that I wanted to ditch the oldest data first,
+                * I hope thats okay with everyone? Yes? Good.
+                */
+               while (qleft < 1) {
+                       jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+                               "Queue full, dropping DATA:%x LSR:%x\n",
+                               ch->ch_rqueue[tail], ch->ch_equeue[tail]);
+
+                       ch->ch_r_tail = tail = (tail + 1) & RQUEUEMASK;
+                       ch->ch_err_overrun++;
+                       qleft++;
+               }
+
+               memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, 1);
+               ch->ch_equeue[head] = (u8) linestatus;
+
+               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+                               "DATA/LSR pair: %x %x\n", ch->ch_rqueue[head], ch->ch_equeue[head]);
+
+               /* Ditch any remaining linestatus value. */
+               linestatus = 0;
+
+               /* Add to and flip head if needed */
+               head = (head + 1) & RQUEUEMASK;
+
+               qleft--;
+               ch->ch_rxcount++;
+       }
+
+       /*
+        * Write new final heads to channel structure.
+        */
+       ch->ch_r_head = head & RQUEUEMASK;
+       ch->ch_e_head = head & EQUEUEMASK;
+       jsm_input(ch);
+}
+
+static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch)
+{
+       u16 head;
+       u16 tail;
+       int n;
+       int s;
+       int qlen;
+       u32 len_written = 0;
+
+       if (!ch)
+               return;
+
+       /* No data to write to the UART */
+       if (ch->ch_w_tail == ch->ch_w_head)
+               return;
+
+       /* If port is "stopped", don't send any data to the UART */
+       if ((ch->ch_flags & CH_STOP) || (ch->ch_flags & CH_BREAK_SENDING))
+               return;
+       /*
+        * If FIFOs are disabled. Send data directly to txrx register
+        */
+       if (!(ch->ch_flags & CH_FIFO_ENABLED)) {
+               u8 lsrbits = readb(&ch->ch_neo_uart->lsr);
+
+               ch->ch_cached_lsr |= lsrbits;
+               if (ch->ch_cached_lsr & UART_LSR_THRE) {
+                       ch->ch_cached_lsr &= ~(UART_LSR_THRE);
+
+                       writeb(ch->ch_wqueue[ch->ch_w_tail], &ch->ch_neo_uart->txrx);
+                       jsm_printk(WRITE, INFO, &ch->ch_bd->pci_dev,
+                                       "Tx data: %x\n", ch->ch_wqueue[ch->ch_w_head]);
+                       ch->ch_w_tail++;
+                       ch->ch_w_tail &= WQUEUEMASK;
+                       ch->ch_txcount++;
+               }
+               return;
+       }
+
+       /*
+        * We have to do it this way, because of the EXAR TXFIFO count bug.
+        */
+       if (!(ch->ch_flags & (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM)))
+               return;
+
+       n = UART_17158_TX_FIFOSIZE - ch->ch_t_tlevel;
+
+       /* cache head and tail of queue */
+       head = ch->ch_w_head & WQUEUEMASK;
+       tail = ch->ch_w_tail & WQUEUEMASK;
+       qlen = (head - tail) & WQUEUEMASK;
+
+       /* Find minimum of the FIFO space, versus queue length */
+       n = min(n, qlen);
+
+       while (n > 0) {
+
+               s = ((head >= tail) ? head : WQUEUESIZE) - tail;
+               s = min(s, n);
+
+               if (s <= 0)
+                       break;
+
+               memcpy_toio(&ch->ch_neo_uart->txrxburst, ch->ch_wqueue + tail, s);
+               /* Add and flip queue if needed */
+               tail = (tail + s) & WQUEUEMASK;
+               n -= s;
+               ch->ch_txcount += s;
+               len_written += s;
+       }
+
+       /* Update the final tail */
+       ch->ch_w_tail = tail & WQUEUEMASK;
+
+       if (len_written >= ch->ch_t_tlevel)
+               ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+
+       if (!jsm_tty_write(&ch->uart_port))
+               uart_write_wakeup(&ch->uart_port);
+}
+
+static void neo_parse_modem(struct jsm_channel *ch, u8 signals)
+{
+       u8 msignals = signals;
+
+       jsm_printk(MSIGS, INFO, &ch->ch_bd->pci_dev,
+                       "neo_parse_modem: port: %d msignals: %x\n", ch->ch_portnum, msignals);
+
+       /* Scrub off lower bits. They signify delta's, which I don't care about */
+       /* Keep DDCD and DDSR though */
+       msignals &= 0xf8;
+
+       if (msignals & UART_MSR_DDCD)
+               uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_DCD);
+       if (msignals & UART_MSR_DDSR)
+               uart_handle_cts_change(&ch->uart_port, msignals & UART_MSR_CTS);
+       if (msignals & UART_MSR_DCD)
+               ch->ch_mistat |= UART_MSR_DCD;
+       else
+               ch->ch_mistat &= ~UART_MSR_DCD;
+
+       if (msignals & UART_MSR_DSR)
+               ch->ch_mistat |= UART_MSR_DSR;
+       else
+               ch->ch_mistat &= ~UART_MSR_DSR;
+
+       if (msignals & UART_MSR_RI)
+               ch->ch_mistat |= UART_MSR_RI;
+       else
+               ch->ch_mistat &= ~UART_MSR_RI;
+
+       if (msignals & UART_MSR_CTS)
+               ch->ch_mistat |= UART_MSR_CTS;
+       else
+               ch->ch_mistat &= ~UART_MSR_CTS;
+
+       jsm_printk(MSIGS, INFO, &ch->ch_bd->pci_dev,
+                       "Port: %d DTR: %d RTS: %d CTS: %d DSR: %d " "RI: %d CD: %d\n",
+               ch->ch_portnum,
+               !!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_DTR),
+               !!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_RTS),
+               !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_CTS),
+               !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DSR),
+               !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_RI),
+               !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DCD));
+}
+
+/* Make the UART raise any of the output signals we want up */
+static void neo_assert_modem_signals(struct jsm_channel *ch)
+{
+       if (!ch)
+               return;
+
+       writeb(ch->ch_mostat, &ch->ch_neo_uart->mcr);
+
+       /* flush write operation */
+       neo_pci_posting_flush(ch->ch_bd);
+}
+
+/*
+ * Flush the WRITE FIFO on the Neo.
+ *
+ * NOTE: Channel lock MUST be held before calling this function!
+ */
+static void neo_flush_uart_write(struct jsm_channel *ch)
+{
+       u8 tmp = 0;
+       int i = 0;
+
+       if (!ch)
+               return;
+
+       writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_XMIT), &ch->ch_neo_uart->isr_fcr);
+
+       for (i = 0; i < 10; i++) {
+
+               /* Check to see if the UART feels it completely flushed the FIFO. */
+               tmp = readb(&ch->ch_neo_uart->isr_fcr);
+               if (tmp & 4) {
+                       jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev,
+                                       "Still flushing TX UART... i: %d\n", i);
+                       udelay(10);
+               }
+               else
+                       break;
+       }
+
+       ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+}
+
+
+/*
+ * Flush the READ FIFO on the Neo.
+ *
+ * NOTE: Channel lock MUST be held before calling this function!
+ */
+static void neo_flush_uart_read(struct jsm_channel *ch)
+{
+       u8 tmp = 0;
+       int i = 0;
+
+       if (!ch)
+               return;
+
+       writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR), &ch->ch_neo_uart->isr_fcr);
+
+       for (i = 0; i < 10; i++) {
+
+               /* Check to see if the UART feels it completely flushed the FIFO. */
+               tmp = readb(&ch->ch_neo_uart->isr_fcr);
+               if (tmp & 2) {
+                       jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev,
+                                       "Still flushing RX UART... i: %d\n", i);
+                       udelay(10);
+               }
+               else
+                       break;
+       }
+}
+
+/*
+ * No locks are assumed to be held when calling this function.
+ */
+static void neo_clear_break(struct jsm_channel *ch, int force)
+{
+       unsigned long lock_flags;
+
+       spin_lock_irqsave(&ch->ch_lock, lock_flags);
+
+       /* Turn break off, and unset some variables */
+       if (ch->ch_flags & CH_BREAK_SENDING) {
+               u8 temp = readb(&ch->ch_neo_uart->lcr);
+               writeb((temp & ~UART_LCR_SBC), &ch->ch_neo_uart->lcr);
+
+               ch->ch_flags &= ~(CH_BREAK_SENDING);
+               jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev,
+                               "clear break Finishing UART_LCR_SBC! finished: %lx\n", jiffies);
+
+               /* flush write operation */
+               neo_pci_posting_flush(ch->ch_bd);
+       }
+       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+}
+
+/*
+ * Parse the ISR register.
+ */
+static inline void neo_parse_isr(struct jsm_board *brd, u32 port)
+{
+       struct jsm_channel *ch;
+       u8 isr;
+       u8 cause;
+       unsigned long lock_flags;
+
+       if (!brd)
+               return;
+
+       if (port > brd->maxports)
+               return;
+
+       ch = brd->channels[port];
+       if (!ch)
+               return;
+
+       /* Here we try to figure out what caused the interrupt to happen */
+       while (1) {
+
+               isr = readb(&ch->ch_neo_uart->isr_fcr);
+
+               /* Bail if no pending interrupt */
+               if (isr & UART_IIR_NO_INT)
+                       break;
+
+               /*
+                * Yank off the upper 2 bits, which just show that the FIFO's are enabled.
+                */
+               isr &= ~(UART_17158_IIR_FIFO_ENABLED);
+
+               jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
+                               "%s:%d isr: %x\n", __FILE__, __LINE__, isr);
+
+               if (isr & (UART_17158_IIR_RDI_TIMEOUT | UART_IIR_RDI)) {
+                       /* Read data from uart -> queue */
+                       neo_copy_data_from_uart_to_queue(ch);
+
+                       /* Call our tty layer to enforce queue flow control if needed. */
+                       spin_lock_irqsave(&ch->ch_lock, lock_flags);
+                       jsm_check_queue_flow_control(ch);
+                       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+               }
+
+               if (isr & UART_IIR_THRI) {
+                       /* Transfer data (if any) from Write Queue -> UART. */
+                       spin_lock_irqsave(&ch->ch_lock, lock_flags);
+                       ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+                       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+                       neo_copy_data_from_queue_to_uart(ch);
+               }
+
+               if (isr & UART_17158_IIR_XONXOFF) {
+                       cause = readb(&ch->ch_neo_uart->xoffchar1);
+
+                       jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
+                                       "Port %d. Got ISR_XONXOFF: cause:%x\n", port, cause);
+
+                       /*
+                        * Since the UART detected either an XON or
+                        * XOFF match, we need to figure out which
+                        * one it was, so we can suspend or resume data flow.
+                        */
+                       spin_lock_irqsave(&ch->ch_lock, lock_flags);
+                       if (cause == UART_17158_XON_DETECT) {
+                               /* Is output stopped right now, if so, resume it */
+                               if (brd->channels[port]->ch_flags & CH_STOP) {
+                                       ch->ch_flags &= ~(CH_STOP);
+                               }
+                               jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
+                                               "Port %d. XON detected in incoming data\n", port);
+                       }
+                       else if (cause == UART_17158_XOFF_DETECT) {
+                               if (!(brd->channels[port]->ch_flags & CH_STOP)) {
+                                       ch->ch_flags |= CH_STOP;
+                                       jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
+                                                       "Setting CH_STOP\n");
+                               }
+                               jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
+                                               "Port: %d. XOFF detected in incoming data\n", port);
+                       }
+                       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+               }
+
+               if (isr & UART_17158_IIR_HWFLOW_STATE_CHANGE) {
+                       /*
+                        * If we get here, this means the hardware is doing auto flow control.
+                        * Check to see whether RTS/DTR or CTS/DSR caused this interrupt.
+                        */
+                       cause = readb(&ch->ch_neo_uart->mcr);
+
+                       /* Which pin is doing auto flow? RTS or DTR? */
+                       spin_lock_irqsave(&ch->ch_lock, lock_flags);
+                       if ((cause & 0x4) == 0) {
+                               if (cause & UART_MCR_RTS)
+                                       ch->ch_mostat |= UART_MCR_RTS;
+                               else
+                                       ch->ch_mostat &= ~(UART_MCR_RTS);
+                       } else {
+                               if (cause & UART_MCR_DTR)
+                                       ch->ch_mostat |= UART_MCR_DTR;
+                               else
+                                       ch->ch_mostat &= ~(UART_MCR_DTR);
+                       }
+                       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+               }
+
+               /* Parse any modem signal changes */
+               jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
+                               "MOD_STAT: sending to parse_modem_sigs\n");
+               neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr));
+       }
+}
+
+static inline void neo_parse_lsr(struct jsm_board *brd, u32 port)
+{
+       struct jsm_channel *ch;
+       int linestatus;
+       unsigned long lock_flags;
+
+       if (!brd)
+               return;
+
+       if (port > brd->maxports)
+               return;
+
+       ch = brd->channels[port];
+       if (!ch)
+               return;
+
+       linestatus = readb(&ch->ch_neo_uart->lsr);
+
+       jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
+                       "%s:%d port: %d linestatus: %x\n", __FILE__, __LINE__, port, linestatus);
+
+       ch->ch_cached_lsr |= linestatus;
+
+       if (ch->ch_cached_lsr & UART_LSR_DR) {
+               /* Read data from uart -> queue */
+               neo_copy_data_from_uart_to_queue(ch);
+               spin_lock_irqsave(&ch->ch_lock, lock_flags);
+               jsm_check_queue_flow_control(ch);
+               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+       }
+
+       /*
+        * This is a special flag. It indicates that at least 1
+        * RX error (parity, framing, or break) has happened.
+        * Mark this in our struct, which will tell me that I have
+        *to do the special RX+LSR read for this FIFO load.
+        */
+       if (linestatus & UART_17158_RX_FIFO_DATA_ERROR)
+               jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
+                       "%s:%d Port: %d Got an RX error, need to parse LSR\n",
+                       __FILE__, __LINE__, port);
+
+       /*
+        * The next 3 tests should *NOT* happen, as the above test
+        * should encapsulate all 3... At least, thats what Exar says.
+        */
+
+       if (linestatus & UART_LSR_PE) {
+               ch->ch_err_parity++;
+               jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
+                       "%s:%d Port: %d. PAR ERR!\n", __FILE__, __LINE__, port);
+       }
+
+       if (linestatus & UART_LSR_FE) {
+               ch->ch_err_frame++;
+               jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
+                       "%s:%d Port: %d. FRM ERR!\n", __FILE__, __LINE__, port);
+       }
+
+       if (linestatus & UART_LSR_BI) {
+               ch->ch_err_break++;
+               jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
+                       "%s:%d Port: %d. BRK INTR!\n", __FILE__, __LINE__, port);
+       }
+
+       if (linestatus & UART_LSR_OE) {
+               /*
+                * Rx Oruns. Exar says that an orun will NOT corrupt
+                * the FIFO. It will just replace the holding register
+                * with this new data byte. So basically just ignore this.
+                * Probably we should eventually have an orun stat in our driver...
+                */
+               ch->ch_err_overrun++;
+               jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
+                       "%s:%d Port: %d. Rx Overrun!\n", __FILE__, __LINE__, port);
+       }
+
+       if (linestatus & UART_LSR_THRE) {
+               spin_lock_irqsave(&ch->ch_lock, lock_flags);
+               ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+               /* Transfer data (if any) from Write Queue -> UART. */
+               neo_copy_data_from_queue_to_uart(ch);
+       }
+       else if (linestatus & UART_17158_TX_AND_FIFO_CLR) {
+               spin_lock_irqsave(&ch->ch_lock, lock_flags);
+               ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+               /* Transfer data (if any) from Write Queue -> UART. */
+               neo_copy_data_from_queue_to_uart(ch);
+       }
+}
+
+/*
+ * neo_param()
+ * Send any/all changes to the line to the UART.
+ */
+static void neo_param(struct jsm_channel *ch)
+{
+       u8 lcr = 0;
+       u8 uart_lcr, ier;
+       u32 baud;
+       int quot;
+       struct jsm_board *bd;
+
+       bd = ch->ch_bd;
+       if (!bd)
+               return;
+
+       /*
+        * If baud rate is zero, flush queues, and set mval to drop DTR.
+        */
+       if ((ch->ch_c_cflag & (CBAUD)) == 0) {
+               ch->ch_r_head = ch->ch_r_tail = 0;
+               ch->ch_e_head = ch->ch_e_tail = 0;
+               ch->ch_w_head = ch->ch_w_tail = 0;
+
+               neo_flush_uart_write(ch);
+               neo_flush_uart_read(ch);
+
+               ch->ch_flags |= (CH_BAUD0);
+               ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR);
+               neo_assert_modem_signals(ch);
+               return;
+
+       } else {
+               int i;
+               unsigned int cflag;
+               static struct {
+                       unsigned int rate;
+                       unsigned int cflag;
+               } baud_rates[] = {
+                       { 921600, B921600 },
+                       { 460800, B460800 },
+                       { 230400, B230400 },
+                       { 115200, B115200 },
+                       {  57600, B57600  },
+                       {  38400, B38400  },
+                       {  19200, B19200  },
+                       {   9600, B9600   },
+                       {   4800, B4800   },
+                       {   2400, B2400   },
+                       {   1200, B1200   },
+                       {    600, B600    },
+                       {    300, B300    },
+                       {    200, B200    },
+                       {    150, B150    },
+                       {    134, B134    },
+                       {    110, B110    },
+                       {     75, B75     },
+                       {     50, B50     },
+               };
+
+               cflag = C_BAUD(ch->uart_port.state->port.tty);
+               baud = 9600;
+               for (i = 0; i < ARRAY_SIZE(baud_rates); i++) {
+                       if (baud_rates[i].cflag == cflag) {
+                               baud = baud_rates[i].rate;
+                               break;
+                       }
+               }
+
+               if (ch->ch_flags & CH_BAUD0)
+                       ch->ch_flags &= ~(CH_BAUD0);
+       }
+
+       if (ch->ch_c_cflag & PARENB)
+               lcr |= UART_LCR_PARITY;
+
+       if (!(ch->ch_c_cflag & PARODD))
+               lcr |= UART_LCR_EPAR;
+
+       /*
+        * Not all platforms support mark/space parity,
+        * so this will hide behind an ifdef.
+        */
+#ifdef CMSPAR
+       if (ch->ch_c_cflag & CMSPAR)
+               lcr |= UART_LCR_SPAR;
+#endif
+
+       if (ch->ch_c_cflag & CSTOPB)
+               lcr |= UART_LCR_STOP;
+
+       switch (ch->ch_c_cflag & CSIZE) {
+               case CS5:
+                       lcr |= UART_LCR_WLEN5;
+                       break;
+               case CS6:
+                       lcr |= UART_LCR_WLEN6;
+                       break;
+               case CS7:
+                       lcr |= UART_LCR_WLEN7;
+                       break;
+               case CS8:
+               default:
+                       lcr |= UART_LCR_WLEN8;
+               break;
+       }
+
+       ier = readb(&ch->ch_neo_uart->ier);
+       uart_lcr = readb(&ch->ch_neo_uart->lcr);
+
+       if (baud == 0)
+               baud = 9600;
+
+       quot = ch->ch_bd->bd_dividend / baud;
+
+       if (quot != 0) {
+               writeb(UART_LCR_DLAB, &ch->ch_neo_uart->lcr);
+               writeb((quot & 0xff), &ch->ch_neo_uart->txrx);
+               writeb((quot >> 8), &ch->ch_neo_uart->ier);
+               writeb(lcr, &ch->ch_neo_uart->lcr);
+       }
+
+       if (uart_lcr != lcr)
+               writeb(lcr, &ch->ch_neo_uart->lcr);
+
+       if (ch->ch_c_cflag & CREAD)
+               ier |= (UART_IER_RDI | UART_IER_RLSI);
+
+       ier |= (UART_IER_THRI | UART_IER_MSI);
+
+       writeb(ier, &ch->ch_neo_uart->ier);
+
+       /* Set new start/stop chars */
+       neo_set_new_start_stop_chars(ch);
+
+       if (ch->ch_c_cflag & CRTSCTS)
+               neo_set_cts_flow_control(ch);
+       else if (ch->ch_c_iflag & IXON) {
+               /* If start/stop is set to disable, then we should disable flow control */
+               if ((ch->ch_startc == __DISABLED_CHAR) || (ch->ch_stopc == __DISABLED_CHAR))
+                       neo_set_no_output_flow_control(ch);
+               else
+                       neo_set_ixon_flow_control(ch);
+       }
+       else
+               neo_set_no_output_flow_control(ch);
+
+       if (ch->ch_c_cflag & CRTSCTS)
+               neo_set_rts_flow_control(ch);
+       else if (ch->ch_c_iflag & IXOFF) {
+               /* If start/stop is set to disable, then we should disable flow control */
+               if ((ch->ch_startc == __DISABLED_CHAR) || (ch->ch_stopc == __DISABLED_CHAR))
+                       neo_set_no_input_flow_control(ch);
+               else
+                       neo_set_ixoff_flow_control(ch);
+       }
+       else
+               neo_set_no_input_flow_control(ch);
+       /*
+        * Adjust the RX FIFO Trigger level if baud is less than 9600.
+        * Not exactly elegant, but this is needed because of the Exar chip's
+        * delay on firing off the RX FIFO interrupt on slower baud rates.
+        */
+       if (baud < 9600) {
+               writeb(1, &ch->ch_neo_uart->rfifo);
+               ch->ch_r_tlevel = 1;
+       }
+
+       neo_assert_modem_signals(ch);
+
+       /* Get current status of the modem signals now */
+       neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr));
+       return;
+}
+
+/*
+ * jsm_neo_intr()
+ *
+ * Neo specific interrupt handler.
+ */
+static irqreturn_t neo_intr(int irq, void *voidbrd)
+{
+       struct jsm_board *brd = voidbrd;
+       struct jsm_channel *ch;
+       int port = 0;
+       int type = 0;
+       int current_port;
+       u32 tmp;
+       u32 uart_poll;
+       unsigned long lock_flags;
+       unsigned long lock_flags2;
+       int outofloop_count = 0;
+
+       /* Lock out the slow poller from running on this board. */
+       spin_lock_irqsave(&brd->bd_intr_lock, lock_flags);
+
+       /*
+        * Read in "extended" IRQ information from the 32bit Neo register.
+        * Bits 0-7: What port triggered the interrupt.
+        * Bits 8-31: Each 3bits indicate what type of interrupt occurred.
+        */
+       uart_poll = readl(brd->re_map_membase + UART_17158_POLL_ADDR_OFFSET);
+
+       jsm_printk(INTR, INFO, &brd->pci_dev,
+               "%s:%d uart_poll: %x\n", __FILE__, __LINE__, uart_poll);
+
+       if (!uart_poll) {
+               jsm_printk(INTR, INFO, &brd->pci_dev,
+                       "Kernel interrupted to me, but no pending interrupts...\n");
+               spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags);
+               return IRQ_NONE;
+       }
+
+       /* At this point, we have at least SOMETHING to service, dig further... */
+
+       current_port = 0;
+
+       /* Loop on each port */
+       while (((uart_poll & 0xff) != 0) && (outofloop_count < 0xff)){
+
+               tmp = uart_poll;
+               outofloop_count++;
+
+               /* Check current port to see if it has interrupt pending */
+               if ((tmp & jsm_offset_table[current_port]) != 0) {
+                       port = current_port;
+                       type = tmp >> (8 + (port * 3));
+                       type &= 0x7;
+               } else {
+                       current_port++;
+                       continue;
+               }
+
+               jsm_printk(INTR, INFO, &brd->pci_dev,
+               "%s:%d port: %x type: %x\n", __FILE__, __LINE__, port, type);
+
+               /* Remove this port + type from uart_poll */
+               uart_poll &= ~(jsm_offset_table[port]);
+
+               if (!type) {
+                       /* If no type, just ignore it, and move onto next port */
+                       jsm_printk(INTR, ERR, &brd->pci_dev,
+                               "Interrupt with no type! port: %d\n", port);
+                       continue;
+               }
+
+               /* Switch on type of interrupt we have */
+               switch (type) {
+
+               case UART_17158_RXRDY_TIMEOUT:
+                       /*
+                        * RXRDY Time-out is cleared by reading data in the
+                       * RX FIFO until it falls below the trigger level.
+                        */
+
+                       /* Verify the port is in range. */
+                       if (port > brd->nasync)
+                               continue;
+
+                       ch = brd->channels[port];
+                       neo_copy_data_from_uart_to_queue(ch);
+
+                       /* Call our tty layer to enforce queue flow control if needed. */
+                       spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+                       jsm_check_queue_flow_control(ch);
+                       spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+
+                       continue;
+
+               case UART_17158_RX_LINE_STATUS:
+                       /*
+                        * RXRDY and RX LINE Status (logic OR of LSR[4:1])
+                        */
+                       neo_parse_lsr(brd, port);
+                       continue;
+
+               case UART_17158_TXRDY:
+                       /*
+                        * TXRDY interrupt clears after reading ISR register for the UART channel.
+                        */
+
+                       /*
+                        * Yes, this is odd...
+                        * Why would I check EVERY possibility of type of
+                        * interrupt, when we know its TXRDY???
+                        * Becuz for some reason, even tho we got triggered for TXRDY,
+                        * it seems to be occassionally wrong. Instead of TX, which
+                        * it should be, I was getting things like RXDY too. Weird.
+                        */
+                       neo_parse_isr(brd, port);
+                       continue;
+
+               case UART_17158_MSR:
+                       /*
+                        * MSR or flow control was seen.
+                        */
+                       neo_parse_isr(brd, port);
+                       continue;
+
+               default:
+                       /*
+                        * The UART triggered us with a bogus interrupt type.
+                        * It appears the Exar chip, when REALLY bogged down, will throw
+                        * these once and awhile.
+                        * Its harmless, just ignore it and move on.
+                        */
+                       jsm_printk(INTR, ERR, &brd->pci_dev,
+                               "%s:%d Unknown Interrupt type: %x\n", __FILE__, __LINE__, type);
+                       continue;
+               }
+       }
+
+       spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags);
+
+       jsm_printk(INTR, INFO, &brd->pci_dev, "finish.\n");
+       return IRQ_HANDLED;
+}
+
+/*
+ * Neo specific way of turning off the receiver.
+ * Used as a way to enforce queue flow control when in
+ * hardware flow control mode.
+ */
+static void neo_disable_receiver(struct jsm_channel *ch)
+{
+       u8 tmp = readb(&ch->ch_neo_uart->ier);
+       tmp &= ~(UART_IER_RDI);
+       writeb(tmp, &ch->ch_neo_uart->ier);
+
+       /* flush write operation */
+       neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+/*
+ * Neo specific way of turning on the receiver.
+ * Used as a way to un-enforce queue flow control when in
+ * hardware flow control mode.
+ */
+static void neo_enable_receiver(struct jsm_channel *ch)
+{
+       u8 tmp = readb(&ch->ch_neo_uart->ier);
+       tmp |= (UART_IER_RDI);
+       writeb(tmp, &ch->ch_neo_uart->ier);
+
+       /* flush write operation */
+       neo_pci_posting_flush(ch->ch_bd);
+}
+
+static void neo_send_start_character(struct jsm_channel *ch)
+{
+       if (!ch)
+               return;
+
+       if (ch->ch_startc != __DISABLED_CHAR) {
+               ch->ch_xon_sends++;
+               writeb(ch->ch_startc, &ch->ch_neo_uart->txrx);
+
+               /* flush write operation */
+               neo_pci_posting_flush(ch->ch_bd);
+       }
+}
+
+static void neo_send_stop_character(struct jsm_channel *ch)
+{
+       if (!ch)
+               return;
+
+       if (ch->ch_stopc != __DISABLED_CHAR) {
+               ch->ch_xoff_sends++;
+               writeb(ch->ch_stopc, &ch->ch_neo_uart->txrx);
+
+               /* flush write operation */
+               neo_pci_posting_flush(ch->ch_bd);
+       }
+}
+
+/*
+ * neo_uart_init
+ */
+static void neo_uart_init(struct jsm_channel *ch)
+{
+       writeb(0, &ch->ch_neo_uart->ier);
+       writeb(0, &ch->ch_neo_uart->efr);
+       writeb(UART_EFR_ECB, &ch->ch_neo_uart->efr);
+
+       /* Clear out UART and FIFO */
+       readb(&ch->ch_neo_uart->txrx);
+       writeb((UART_FCR_ENABLE_FIFO|UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT), &ch->ch_neo_uart->isr_fcr);
+       readb(&ch->ch_neo_uart->lsr);
+       readb(&ch->ch_neo_uart->msr);
+
+       ch->ch_flags |= CH_FIFO_ENABLED;
+
+       /* Assert any signals we want up */
+       writeb(ch->ch_mostat, &ch->ch_neo_uart->mcr);
+}
+
+/*
+ * Make the UART completely turn off.
+ */
+static void neo_uart_off(struct jsm_channel *ch)
+{
+       /* Turn off UART enhanced bits */
+       writeb(0, &ch->ch_neo_uart->efr);
+
+       /* Stop all interrupts from occurring. */
+       writeb(0, &ch->ch_neo_uart->ier);
+}
+
+static u32 neo_get_uart_bytes_left(struct jsm_channel *ch)
+{
+       u8 left = 0;
+       u8 lsr = readb(&ch->ch_neo_uart->lsr);
+
+       /* We must cache the LSR as some of the bits get reset once read... */
+       ch->ch_cached_lsr |= lsr;
+
+       /* Determine whether the Transmitter is empty or not */
+       if (!(lsr & UART_LSR_TEMT))
+               left = 1;
+       else {
+               ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+               left = 0;
+       }
+
+       return left;
+}
+
+/* Channel lock MUST be held by the calling function! */
+static void neo_send_break(struct jsm_channel *ch)
+{
+       /*
+        * Set the time we should stop sending the break.
+        * If we are already sending a break, toss away the existing
+        * time to stop, and use this new value instead.
+        */
+
+       /* Tell the UART to start sending the break */
+       if (!(ch->ch_flags & CH_BREAK_SENDING)) {
+               u8 temp = readb(&ch->ch_neo_uart->lcr);
+               writeb((temp | UART_LCR_SBC), &ch->ch_neo_uart->lcr);
+               ch->ch_flags |= (CH_BREAK_SENDING);
+
+               /* flush write operation */
+               neo_pci_posting_flush(ch->ch_bd);
+       }
+}
+
+/*
+ * neo_send_immediate_char.
+ *
+ * Sends a specific character as soon as possible to the UART,
+ * jumping over any bytes that might be in the write queue.
+ *
+ * The channel lock MUST be held by the calling function.
+ */
+static void neo_send_immediate_char(struct jsm_channel *ch, unsigned char c)
+{
+       if (!ch)
+               return;
+
+       writeb(c, &ch->ch_neo_uart->txrx);
+
+       /* flush write operation */
+       neo_pci_posting_flush(ch->ch_bd);
+}
+
+struct board_ops jsm_neo_ops = {
+       .intr                           = neo_intr,
+       .uart_init                      = neo_uart_init,
+       .uart_off                       = neo_uart_off,
+       .param                          = neo_param,
+       .assert_modem_signals           = neo_assert_modem_signals,
+       .flush_uart_write               = neo_flush_uart_write,
+       .flush_uart_read                = neo_flush_uart_read,
+       .disable_receiver               = neo_disable_receiver,
+       .enable_receiver                = neo_enable_receiver,
+       .send_break                     = neo_send_break,
+       .clear_break                    = neo_clear_break,
+       .send_start_character           = neo_send_start_character,
+       .send_stop_character            = neo_send_stop_character,
+       .copy_data_from_queue_to_uart   = neo_copy_data_from_queue_to_uart,
+       .get_uart_bytes_left            = neo_get_uart_bytes_left,
+       .send_immediate_char            = neo_send_immediate_char
+};
diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c
new file mode 100644 (file)
index 0000000..7a4a914
--- /dev/null
@@ -0,0 +1,910 @@
+/************************************************************************
+ * Copyright 2003 Digi International (www.digi.com)
+ *
+ * Copyright (C) 2004 IBM Corporation. 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ * Contact Information:
+ * Scott H Kilau <Scott_Kilau@digi.com>
+ * Ananda Venkatarman <mansarov@us.ibm.com>
+ * Modifications:
+ * 01/19/06:   changed jsm_input routine to use the dynamically allocated
+ *             tty_buffer changes. Contributors: Scott Kilau and Ananda V.
+ ***********************************************************************/
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_reg.h>
+#include <linux/delay.h>       /* For udelay */
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include "jsm.h"
+
+static DECLARE_BITMAP(linemap, MAXLINES);
+
+static void jsm_carrier(struct jsm_channel *ch);
+
+static inline int jsm_get_mstat(struct jsm_channel *ch)
+{
+       unsigned char mstat;
+       unsigned result;
+
+       jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "start\n");
+
+       mstat = (ch->ch_mostat | ch->ch_mistat);
+
+       result = 0;
+
+       if (mstat & UART_MCR_DTR)
+               result |= TIOCM_DTR;
+       if (mstat & UART_MCR_RTS)
+               result |= TIOCM_RTS;
+       if (mstat & UART_MSR_CTS)
+               result |= TIOCM_CTS;
+       if (mstat & UART_MSR_DSR)
+               result |= TIOCM_DSR;
+       if (mstat & UART_MSR_RI)
+               result |= TIOCM_RI;
+       if (mstat & UART_MSR_DCD)
+               result |= TIOCM_CD;
+
+       jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n");
+       return result;
+}
+
+static unsigned int jsm_tty_tx_empty(struct uart_port *port)
+{
+       return TIOCSER_TEMT;
+}
+
+/*
+ * Return modem signals to ld.
+ */
+static unsigned int jsm_tty_get_mctrl(struct uart_port *port)
+{
+       int result;
+       struct jsm_channel *channel = (struct jsm_channel *)port;
+
+       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
+
+       result = jsm_get_mstat(channel);
+
+       if (result < 0)
+               return -ENXIO;
+
+       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
+
+       return result;
+}
+
+/*
+ * jsm_set_modem_info()
+ *
+ * Set modem signals, called by ld.
+ */
+static void jsm_tty_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct jsm_channel *channel = (struct jsm_channel *)port;
+
+       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
+
+       if (mctrl & TIOCM_RTS)
+               channel->ch_mostat |= UART_MCR_RTS;
+       else
+               channel->ch_mostat &= ~UART_MCR_RTS;
+
+       if (mctrl & TIOCM_DTR)
+               channel->ch_mostat |= UART_MCR_DTR;
+       else
+               channel->ch_mostat &= ~UART_MCR_DTR;
+
+       channel->ch_bd->bd_ops->assert_modem_signals(channel);
+
+       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
+       udelay(10);
+}
+
+static void jsm_tty_start_tx(struct uart_port *port)
+{
+       struct jsm_channel *channel = (struct jsm_channel *)port;
+
+       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
+
+       channel->ch_flags &= ~(CH_STOP);
+       jsm_tty_write(port);
+
+       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
+}
+
+static void jsm_tty_stop_tx(struct uart_port *port)
+{
+       struct jsm_channel *channel = (struct jsm_channel *)port;
+
+       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
+
+       channel->ch_flags |= (CH_STOP);
+
+       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
+}
+
+static void jsm_tty_send_xchar(struct uart_port *port, char ch)
+{
+       unsigned long lock_flags;
+       struct jsm_channel *channel = (struct jsm_channel *)port;
+       struct ktermios *termios;
+
+       spin_lock_irqsave(&port->lock, lock_flags);
+       termios = port->state->port.tty->termios;
+       if (ch == termios->c_cc[VSTART])
+               channel->ch_bd->bd_ops->send_start_character(channel);
+
+       if (ch == termios->c_cc[VSTOP])
+               channel->ch_bd->bd_ops->send_stop_character(channel);
+       spin_unlock_irqrestore(&port->lock, lock_flags);
+}
+
+static void jsm_tty_stop_rx(struct uart_port *port)
+{
+       struct jsm_channel *channel = (struct jsm_channel *)port;
+
+       channel->ch_bd->bd_ops->disable_receiver(channel);
+}
+
+static void jsm_tty_enable_ms(struct uart_port *port)
+{
+       /* Nothing needed */
+}
+
+static void jsm_tty_break(struct uart_port *port, int break_state)
+{
+       unsigned long lock_flags;
+       struct jsm_channel *channel = (struct jsm_channel *)port;
+
+       spin_lock_irqsave(&port->lock, lock_flags);
+       if (break_state == -1)
+               channel->ch_bd->bd_ops->send_break(channel);
+       else
+               channel->ch_bd->bd_ops->clear_break(channel, 0);
+
+       spin_unlock_irqrestore(&port->lock, lock_flags);
+}
+
+static int jsm_tty_open(struct uart_port *port)
+{
+       struct jsm_board *brd;
+       struct jsm_channel *channel = (struct jsm_channel *)port;
+       struct ktermios *termios;
+
+       /* Get board pointer from our array of majors we have allocated */
+       brd = channel->ch_bd;
+
+       /*
+        * Allocate channel buffers for read/write/error.
+        * Set flag, so we don't get trounced on.
+        */
+       channel->ch_flags |= (CH_OPENING);
+
+       /* Drop locks, as malloc with GFP_KERNEL can sleep */
+
+       if (!channel->ch_rqueue) {
+               channel->ch_rqueue = kzalloc(RQUEUESIZE, GFP_KERNEL);
+               if (!channel->ch_rqueue) {
+                       jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
+                               "unable to allocate read queue buf");
+                       return -ENOMEM;
+               }
+       }
+       if (!channel->ch_equeue) {
+               channel->ch_equeue = kzalloc(EQUEUESIZE, GFP_KERNEL);
+               if (!channel->ch_equeue) {
+                       jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
+                               "unable to allocate error queue buf");
+                       return -ENOMEM;
+               }
+       }
+       if (!channel->ch_wqueue) {
+               channel->ch_wqueue = kzalloc(WQUEUESIZE, GFP_KERNEL);
+               if (!channel->ch_wqueue) {
+                       jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
+                               "unable to allocate write queue buf");
+                       return -ENOMEM;
+               }
+       }
+
+       channel->ch_flags &= ~(CH_OPENING);
+       /*
+        * Initialize if neither terminal is open.
+        */
+       jsm_printk(OPEN, INFO, &channel->ch_bd->pci_dev,
+               "jsm_open: initializing channel in open...\n");
+
+       /*
+        * Flush input queues.
+        */
+       channel->ch_r_head = channel->ch_r_tail = 0;
+       channel->ch_e_head = channel->ch_e_tail = 0;
+       channel->ch_w_head = channel->ch_w_tail = 0;
+
+       brd->bd_ops->flush_uart_write(channel);
+       brd->bd_ops->flush_uart_read(channel);
+
+       channel->ch_flags = 0;
+       channel->ch_cached_lsr = 0;
+       channel->ch_stops_sent = 0;
+
+       termios = port->state->port.tty->termios;
+       channel->ch_c_cflag     = termios->c_cflag;
+       channel->ch_c_iflag     = termios->c_iflag;
+       channel->ch_c_oflag     = termios->c_oflag;
+       channel->ch_c_lflag     = termios->c_lflag;
+       channel->ch_startc      = termios->c_cc[VSTART];
+       channel->ch_stopc       = termios->c_cc[VSTOP];
+
+       /* Tell UART to init itself */
+       brd->bd_ops->uart_init(channel);
+
+       /*
+        * Run param in case we changed anything
+        */
+       brd->bd_ops->param(channel);
+
+       jsm_carrier(channel);
+
+       channel->ch_open_count++;
+
+       jsm_printk(OPEN, INFO, &channel->ch_bd->pci_dev, "finish\n");
+       return 0;
+}
+
+static void jsm_tty_close(struct uart_port *port)
+{
+       struct jsm_board *bd;
+       struct ktermios *ts;
+       struct jsm_channel *channel = (struct jsm_channel *)port;
+
+       jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n");
+
+       bd = channel->ch_bd;
+       ts = port->state->port.tty->termios;
+
+       channel->ch_flags &= ~(CH_STOPI);
+
+       channel->ch_open_count--;
+
+       /*
+        * If we have HUPCL set, lower DTR and RTS
+        */
+       if (channel->ch_c_cflag & HUPCL) {
+               jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev,
+                       "Close. HUPCL set, dropping DTR/RTS\n");
+
+               /* Drop RTS/DTR */
+               channel->ch_mostat &= ~(UART_MCR_DTR | UART_MCR_RTS);
+               bd->bd_ops->assert_modem_signals(channel);
+       }
+
+       /* Turn off UART interrupts for this port */
+       channel->ch_bd->bd_ops->uart_off(channel);
+
+       jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "finish\n");
+}
+
+static void jsm_tty_set_termios(struct uart_port *port,
+                                struct ktermios *termios,
+                                struct ktermios *old_termios)
+{
+       unsigned long lock_flags;
+       struct jsm_channel *channel = (struct jsm_channel *)port;
+
+       spin_lock_irqsave(&port->lock, lock_flags);
+       channel->ch_c_cflag     = termios->c_cflag;
+       channel->ch_c_iflag     = termios->c_iflag;
+       channel->ch_c_oflag     = termios->c_oflag;
+       channel->ch_c_lflag     = termios->c_lflag;
+       channel->ch_startc      = termios->c_cc[VSTART];
+       channel->ch_stopc       = termios->c_cc[VSTOP];
+
+       channel->ch_bd->bd_ops->param(channel);
+       jsm_carrier(channel);
+       spin_unlock_irqrestore(&port->lock, lock_flags);
+}
+
+static const char *jsm_tty_type(struct uart_port *port)
+{
+       return "jsm";
+}
+
+static void jsm_tty_release_port(struct uart_port *port)
+{
+}
+
+static int jsm_tty_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static void jsm_config_port(struct uart_port *port, int flags)
+{
+       port->type = PORT_JSM;
+}
+
+static struct uart_ops jsm_ops = {
+       .tx_empty       = jsm_tty_tx_empty,
+       .set_mctrl      = jsm_tty_set_mctrl,
+       .get_mctrl      = jsm_tty_get_mctrl,
+       .stop_tx        = jsm_tty_stop_tx,
+       .start_tx       = jsm_tty_start_tx,
+       .send_xchar     = jsm_tty_send_xchar,
+       .stop_rx        = jsm_tty_stop_rx,
+       .enable_ms      = jsm_tty_enable_ms,
+       .break_ctl      = jsm_tty_break,
+       .startup        = jsm_tty_open,
+       .shutdown       = jsm_tty_close,
+       .set_termios    = jsm_tty_set_termios,
+       .type           = jsm_tty_type,
+       .release_port   = jsm_tty_release_port,
+       .request_port   = jsm_tty_request_port,
+       .config_port    = jsm_config_port,
+};
+
+/*
+ * jsm_tty_init()
+ *
+ * Init the tty subsystem.  Called once per board after board has been
+ * downloaded and init'ed.
+ */
+int __devinit jsm_tty_init(struct jsm_board *brd)
+{
+       int i;
+       void __iomem *vaddr;
+       struct jsm_channel *ch;
+
+       if (!brd)
+               return -ENXIO;
+
+       jsm_printk(INIT, INFO, &brd->pci_dev, "start\n");
+
+       /*
+        * Initialize board structure elements.
+        */
+
+       brd->nasync = brd->maxports;
+
+       /*
+        * Allocate channel memory that might not have been allocated
+        * when the driver was first loaded.
+        */
+       for (i = 0; i < brd->nasync; i++) {
+               if (!brd->channels[i]) {
+
+                       /*
+                        * Okay to malloc with GFP_KERNEL, we are not at
+                        * interrupt context, and there are no locks held.
+                        */
+                       brd->channels[i] = kzalloc(sizeof(struct jsm_channel), GFP_KERNEL);
+                       if (!brd->channels[i]) {
+                               jsm_printk(CORE, ERR, &brd->pci_dev,
+                                       "%s:%d Unable to allocate memory for channel struct\n",
+                                                        __FILE__, __LINE__);
+                       }
+               }
+       }
+
+       ch = brd->channels[0];
+       vaddr = brd->re_map_membase;
+
+       /* Set up channel variables */
+       for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) {
+
+               if (!brd->channels[i])
+                       continue;
+
+               spin_lock_init(&ch->ch_lock);
+
+               if (brd->bd_uart_offset == 0x200)
+                       ch->ch_neo_uart =  vaddr + (brd->bd_uart_offset * i);
+
+               ch->ch_bd = brd;
+               ch->ch_portnum = i;
+
+               /* .25 second delay */
+               ch->ch_close_delay = 250;
+
+               init_waitqueue_head(&ch->ch_flags_wait);
+       }
+
+       jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n");
+       return 0;
+}
+
+int jsm_uart_port_init(struct jsm_board *brd)
+{
+       int i, rc;
+       unsigned int line;
+       struct jsm_channel *ch;
+
+       if (!brd)
+               return -ENXIO;
+
+       jsm_printk(INIT, INFO, &brd->pci_dev, "start\n");
+
+       /*
+        * Initialize board structure elements.
+        */
+
+       brd->nasync = brd->maxports;
+
+       /* Set up channel variables */
+       for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) {
+
+               if (!brd->channels[i])
+                       continue;
+
+               brd->channels[i]->uart_port.irq = brd->irq;
+               brd->channels[i]->uart_port.uartclk = 14745600;
+               brd->channels[i]->uart_port.type = PORT_JSM;
+               brd->channels[i]->uart_port.iotype = UPIO_MEM;
+               brd->channels[i]->uart_port.membase = brd->re_map_membase;
+               brd->channels[i]->uart_port.fifosize = 16;
+               brd->channels[i]->uart_port.ops = &jsm_ops;
+               line = find_first_zero_bit(linemap, MAXLINES);
+               if (line >= MAXLINES) {
+                       printk(KERN_INFO "jsm: linemap is full, added device failed\n");
+                       continue;
+               } else
+                       set_bit(line, linemap);
+               brd->channels[i]->uart_port.line = line;
+               rc = uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port);
+               if (rc){
+                       printk(KERN_INFO "jsm: Port %d failed. Aborting...\n", i);
+                       return rc;
+               }
+               else
+                       printk(KERN_INFO "jsm: Port %d added\n", i);
+       }
+
+       jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n");
+       return 0;
+}
+
+int jsm_remove_uart_port(struct jsm_board *brd)
+{
+       int i;
+       struct jsm_channel *ch;
+
+       if (!brd)
+               return -ENXIO;
+
+       jsm_printk(INIT, INFO, &brd->pci_dev, "start\n");
+
+       /*
+        * Initialize board structure elements.
+        */
+
+       brd->nasync = brd->maxports;
+
+       /* Set up channel variables */
+       for (i = 0; i < brd->nasync; i++) {
+
+               if (!brd->channels[i])
+                       continue;
+
+               ch = brd->channels[i];
+
+               clear_bit(ch->uart_port.line, linemap);
+               uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port);
+       }
+
+       jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n");
+       return 0;
+}
+
+void jsm_input(struct jsm_channel *ch)
+{
+       struct jsm_board *bd;
+       struct tty_struct *tp;
+       u32 rmask;
+       u16 head;
+       u16 tail;
+       int data_len;
+       unsigned long lock_flags;
+       int len = 0;
+       int n = 0;
+       int s = 0;
+       int i = 0;
+
+       jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start\n");
+
+       if (!ch)
+               return;
+
+       tp = ch->uart_port.state->port.tty;
+
+       bd = ch->ch_bd;
+       if(!bd)
+               return;
+
+       spin_lock_irqsave(&ch->ch_lock, lock_flags);
+
+       /*
+        *Figure the number of characters in the buffer.
+        *Exit immediately if none.
+        */
+
+       rmask = RQUEUEMASK;
+
+       head = ch->ch_r_head & rmask;
+       tail = ch->ch_r_tail & rmask;
+
+       data_len = (head - tail) & rmask;
+       if (data_len == 0) {
+               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+               return;
+       }
+
+       jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start\n");
+
+       /*
+        *If the device is not open, or CREAD is off, flush
+        *input data and return immediately.
+        */
+       if (!tp ||
+               !(tp->termios->c_cflag & CREAD) ) {
+
+               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+                       "input. dropping %d bytes on port %d...\n", data_len, ch->ch_portnum);
+               ch->ch_r_head = tail;
+
+               /* Force queue flow control to be released, if needed */
+               jsm_check_queue_flow_control(ch);
+
+               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+               return;
+       }
+
+       /*
+        * If we are throttled, simply don't read any data.
+        */
+       if (ch->ch_flags & CH_STOPI) {
+               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+                       "Port %d throttled, not reading any data. head: %x tail: %x\n",
+                       ch->ch_portnum, head, tail);
+               return;
+       }
+
+       jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start 2\n");
+
+       if (data_len <= 0) {
+               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "jsm_input 1\n");
+               return;
+       }
+
+       len = tty_buffer_request_room(tp, data_len);
+       n = len;
+
+       /*
+        * n now contains the most amount of data we can copy,
+        * bounded either by the flip buffer size or the amount
+        * of data the card actually has pending...
+        */
+       while (n) {
+               s = ((head >= tail) ? head : RQUEUESIZE) - tail;
+               s = min(s, n);
+
+               if (s <= 0)
+                       break;
+
+                       /*
+                        * If conditions are such that ld needs to see all
+                        * UART errors, we will have to walk each character
+                        * and error byte and send them to the buffer one at
+                        * a time.
+                        */
+
+               if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
+                       for (i = 0; i < s; i++) {
+                               /*
+                                * Give the Linux ld the flags in the
+                                * format it likes.
+                                */
+                               if (*(ch->ch_equeue +tail +i) & UART_LSR_BI)
+                                       tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i),  TTY_BREAK);
+                               else if (*(ch->ch_equeue +tail +i) & UART_LSR_PE)
+                                       tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_PARITY);
+                               else if (*(ch->ch_equeue +tail +i) & UART_LSR_FE)
+                                       tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_FRAME);
+                               else
+                                       tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_NORMAL);
+                       }
+               } else {
+                       tty_insert_flip_string(tp, ch->ch_rqueue + tail, s) ;
+               }
+               tail += s;
+               n -= s;
+               /* Flip queue if needed */
+               tail &= rmask;
+       }
+
+       ch->ch_r_tail = tail & rmask;
+       ch->ch_e_tail = tail & rmask;
+       jsm_check_queue_flow_control(ch);
+       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+       /* Tell the tty layer its okay to "eat" the data now */
+       tty_flip_buffer_push(tp);
+
+       jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n");
+}
+
+static void jsm_carrier(struct jsm_channel *ch)
+{
+       struct jsm_board *bd;
+
+       int virt_carrier = 0;
+       int phys_carrier = 0;
+
+       jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, "start\n");
+       if (!ch)
+               return;
+
+       bd = ch->ch_bd;
+
+       if (!bd)
+               return;
+
+       if (ch->ch_mistat & UART_MSR_DCD) {
+               jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev,
+                       "mistat: %x D_CD: %x\n", ch->ch_mistat, ch->ch_mistat & UART_MSR_DCD);
+               phys_carrier = 1;
+       }
+
+       if (ch->ch_c_cflag & CLOCAL)
+               virt_carrier = 1;
+
+       jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev,
+               "DCD: physical: %d virt: %d\n", phys_carrier, virt_carrier);
+
+       /*
+        * Test for a VIRTUAL carrier transition to HIGH.
+        */
+       if (((ch->ch_flags & CH_FCAR) == 0) && (virt_carrier == 1)) {
+
+               /*
+                * When carrier rises, wake any threads waiting
+                * for carrier in the open routine.
+                */
+
+               jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev,
+                       "carrier: virt DCD rose\n");
+
+               if (waitqueue_active(&(ch->ch_flags_wait)))
+                       wake_up_interruptible(&ch->ch_flags_wait);
+       }
+
+       /*
+        * Test for a PHYSICAL carrier transition to HIGH.
+        */
+       if (((ch->ch_flags & CH_CD) == 0) && (phys_carrier == 1)) {
+
+               /*
+                * When carrier rises, wake any threads waiting
+                * for carrier in the open routine.
+                */
+
+               jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev,
+                       "carrier: physical DCD rose\n");
+
+               if (waitqueue_active(&(ch->ch_flags_wait)))
+                       wake_up_interruptible(&ch->ch_flags_wait);
+       }
+
+       /*
+        *  Test for a PHYSICAL transition to low, so long as we aren't
+        *  currently ignoring physical transitions (which is what "virtual
+        *  carrier" indicates).
+        *
+        *  The transition of the virtual carrier to low really doesn't
+        *  matter... it really only means "ignore carrier state", not
+        *  "make pretend that carrier is there".
+        */
+       if ((virt_carrier == 0) && ((ch->ch_flags & CH_CD) != 0)
+                       && (phys_carrier == 0)) {
+               /*
+                *      When carrier drops:
+                *
+                *      Drop carrier on all open units.
+                *
+                *      Flush queues, waking up any task waiting in the
+                *      line discipline.
+                *
+                *      Send a hangup to the control terminal.
+                *
+                *      Enable all select calls.
+                */
+               if (waitqueue_active(&(ch->ch_flags_wait)))
+                       wake_up_interruptible(&ch->ch_flags_wait);
+       }
+
+       /*
+        *  Make sure that our cached values reflect the current reality.
+        */
+       if (virt_carrier == 1)
+               ch->ch_flags |= CH_FCAR;
+       else
+               ch->ch_flags &= ~CH_FCAR;
+
+       if (phys_carrier == 1)
+               ch->ch_flags |= CH_CD;
+       else
+               ch->ch_flags &= ~CH_CD;
+}
+
+
+void jsm_check_queue_flow_control(struct jsm_channel *ch)
+{
+       struct board_ops *bd_ops = ch->ch_bd->bd_ops;
+       int qleft;
+
+       /* Store how much space we have left in the queue */
+       if ((qleft = ch->ch_r_tail - ch->ch_r_head - 1) < 0)
+               qleft += RQUEUEMASK + 1;
+
+       /*
+        * Check to see if we should enforce flow control on our queue because
+        * the ld (or user) isn't reading data out of our queue fast enuf.
+        *
+        * NOTE: This is done based on what the current flow control of the
+        * port is set for.
+        *
+        * 1) HWFLOW (RTS) - Turn off the UART's Receive interrupt.
+        *      This will cause the UART's FIFO to back up, and force
+        *      the RTS signal to be dropped.
+        * 2) SWFLOW (IXOFF) - Keep trying to send a stop character to
+        *      the other side, in hopes it will stop sending data to us.
+        * 3) NONE - Nothing we can do.  We will simply drop any extra data
+        *      that gets sent into us when the queue fills up.
+        */
+       if (qleft < 256) {
+               /* HWFLOW */
+               if (ch->ch_c_cflag & CRTSCTS) {
+                       if(!(ch->ch_flags & CH_RECEIVER_OFF)) {
+                               bd_ops->disable_receiver(ch);
+                               ch->ch_flags |= (CH_RECEIVER_OFF);
+                               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+                                       "Internal queue hit hilevel mark (%d)! Turning off interrupts.\n",
+                                       qleft);
+                       }
+               }
+               /* SWFLOW */
+               else if (ch->ch_c_iflag & IXOFF) {
+                       if (ch->ch_stops_sent <= MAX_STOPS_SENT) {
+                               bd_ops->send_stop_character(ch);
+                               ch->ch_stops_sent++;
+                               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+                                       "Sending stop char! Times sent: %x\n", ch->ch_stops_sent);
+                       }
+               }
+       }
+
+       /*
+        * Check to see if we should unenforce flow control because
+        * ld (or user) finally read enuf data out of our queue.
+        *
+        * NOTE: This is done based on what the current flow control of the
+        * port is set for.
+        *
+        * 1) HWFLOW (RTS) - Turn back on the UART's Receive interrupt.
+        *      This will cause the UART's FIFO to raise RTS back up,
+        *      which will allow the other side to start sending data again.
+        * 2) SWFLOW (IXOFF) - Send a start character to
+        *      the other side, so it will start sending data to us again.
+        * 3) NONE - Do nothing. Since we didn't do anything to turn off the
+        *      other side, we don't need to do anything now.
+        */
+       if (qleft > (RQUEUESIZE / 2)) {
+               /* HWFLOW */
+               if (ch->ch_c_cflag & CRTSCTS) {
+                       if (ch->ch_flags & CH_RECEIVER_OFF) {
+                               bd_ops->enable_receiver(ch);
+                               ch->ch_flags &= ~(CH_RECEIVER_OFF);
+                               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+                                       "Internal queue hit lowlevel mark (%d)! Turning on interrupts.\n",
+                                       qleft);
+                       }
+               }
+               /* SWFLOW */
+               else if (ch->ch_c_iflag & IXOFF && ch->ch_stops_sent) {
+                       ch->ch_stops_sent = 0;
+                       bd_ops->send_start_character(ch);
+                       jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "Sending start char!\n");
+               }
+       }
+}
+
+/*
+ * jsm_tty_write()
+ *
+ * Take data from the user or kernel and send it out to the FEP.
+ * In here exists all the Transparent Print magic as well.
+ */
+int jsm_tty_write(struct uart_port *port)
+{
+       int bufcount;
+       int data_count = 0,data_count1 =0;
+       u16 head;
+       u16 tail;
+       u16 tmask;
+       u32 remain;
+       int temp_tail = port->state->xmit.tail;
+       struct jsm_channel *channel = (struct jsm_channel *)port;
+
+       tmask = WQUEUEMASK;
+       head = (channel->ch_w_head) & tmask;
+       tail = (channel->ch_w_tail) & tmask;
+
+       if ((bufcount = tail - head - 1) < 0)
+               bufcount += WQUEUESIZE;
+
+       bufcount = min(bufcount, 56);
+       remain = WQUEUESIZE - head;
+
+       data_count = 0;
+       if (bufcount >= remain) {
+               bufcount -= remain;
+               while ((port->state->xmit.head != temp_tail) &&
+               (data_count < remain)) {
+                       channel->ch_wqueue[head++] =
+                       port->state->xmit.buf[temp_tail];
+
+                       temp_tail++;
+                       temp_tail &= (UART_XMIT_SIZE - 1);
+                       data_count++;
+               }
+               if (data_count == remain) head = 0;
+       }
+
+       data_count1 = 0;
+       if (bufcount > 0) {
+               remain = bufcount;
+               while ((port->state->xmit.head != temp_tail) &&
+                       (data_count1 < remain)) {
+                       channel->ch_wqueue[head++] =
+                               port->state->xmit.buf[temp_tail];
+
+                       temp_tail++;
+                       temp_tail &= (UART_XMIT_SIZE - 1);
+                       data_count1++;
+
+               }
+       }
+
+       port->state->xmit.tail = temp_tail;
+
+       data_count += data_count1;
+       if (data_count) {
+               head &= tmask;
+               channel->ch_w_head = head;
+       }
+
+       if (data_count) {
+               channel->ch_bd->bd_ops->copy_data_from_queue_to_uart(channel);
+       }
+
+       return data_count;
+}
diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c
new file mode 100644 (file)
index 0000000..25a8bc5
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * Based on the same principle as kgdboe using the NETPOLL api, this
+ * driver uses a console polling api to implement a gdb serial inteface
+ * which is multiplexed on a console port.
+ *
+ * Maintainer: Jason Wessel <jason.wessel@windriver.com>
+ *
+ * 2007-2008 (c) Jason Wessel - Wind River Systems, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/kgdb.h>
+#include <linux/kdb.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/vt_kern.h>
+#include <linux/input.h>
+
+#define MAX_CONFIG_LEN         40
+
+static struct kgdb_io          kgdboc_io_ops;
+
+/* -1 = init not run yet, 0 = unconfigured, 1 = configured. */
+static int configured          = -1;
+
+static char config[MAX_CONFIG_LEN];
+static struct kparam_string kps = {
+       .string                 = config,
+       .maxlen                 = MAX_CONFIG_LEN,
+};
+
+static int kgdboc_use_kms;  /* 1 if we use kernel mode switching */
+static struct tty_driver       *kgdb_tty_driver;
+static int                     kgdb_tty_line;
+
+#ifdef CONFIG_KDB_KEYBOARD
+static int kgdboc_reset_connect(struct input_handler *handler,
+                               struct input_dev *dev,
+                               const struct input_device_id *id)
+{
+       input_reset_device(dev);
+
+       /* Retrun an error - we do not want to bind, just to reset */
+       return -ENODEV;
+}
+
+static void kgdboc_reset_disconnect(struct input_handle *handle)
+{
+       /* We do not expect anyone to actually bind to us */
+       BUG();
+}
+
+static const struct input_device_id kgdboc_reset_ids[] = {
+       {
+               .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+               .evbit = { BIT_MASK(EV_KEY) },
+       },
+       { }
+};
+
+static struct input_handler kgdboc_reset_handler = {
+       .connect        = kgdboc_reset_connect,
+       .disconnect     = kgdboc_reset_disconnect,
+       .name           = "kgdboc_reset",
+       .id_table       = kgdboc_reset_ids,
+};
+
+static DEFINE_MUTEX(kgdboc_reset_mutex);
+
+static void kgdboc_restore_input_helper(struct work_struct *dummy)
+{
+       /*
+        * We need to take a mutex to prevent several instances of
+        * this work running on different CPUs so they don't try
+        * to register again already registered handler.
+        */
+       mutex_lock(&kgdboc_reset_mutex);
+
+       if (input_register_handler(&kgdboc_reset_handler) == 0)
+               input_unregister_handler(&kgdboc_reset_handler);
+
+       mutex_unlock(&kgdboc_reset_mutex);
+}
+
+static DECLARE_WORK(kgdboc_restore_input_work, kgdboc_restore_input_helper);
+
+static void kgdboc_restore_input(void)
+{
+       if (likely(system_state == SYSTEM_RUNNING))
+               schedule_work(&kgdboc_restore_input_work);
+}
+
+static int kgdboc_register_kbd(char **cptr)
+{
+       if (strncmp(*cptr, "kbd", 3) == 0) {
+               if (kdb_poll_idx < KDB_POLL_FUNC_MAX) {
+                       kdb_poll_funcs[kdb_poll_idx] = kdb_get_kbd_char;
+                       kdb_poll_idx++;
+                       if (cptr[0][3] == ',')
+                               *cptr += 4;
+                       else
+                               return 1;
+               }
+       }
+       return 0;
+}
+
+static void kgdboc_unregister_kbd(void)
+{
+       int i;
+
+       for (i = 0; i < kdb_poll_idx; i++) {
+               if (kdb_poll_funcs[i] == kdb_get_kbd_char) {
+                       kdb_poll_idx--;
+                       kdb_poll_funcs[i] = kdb_poll_funcs[kdb_poll_idx];
+                       kdb_poll_funcs[kdb_poll_idx] = NULL;
+                       i--;
+               }
+       }
+       flush_work_sync(&kgdboc_restore_input_work);
+}
+#else /* ! CONFIG_KDB_KEYBOARD */
+#define kgdboc_register_kbd(x) 0
+#define kgdboc_unregister_kbd()
+#define kgdboc_restore_input()
+#endif /* ! CONFIG_KDB_KEYBOARD */
+
+static int kgdboc_option_setup(char *opt)
+{
+       if (strlen(opt) > MAX_CONFIG_LEN) {
+               printk(KERN_ERR "kgdboc: config string too long\n");
+               return -ENOSPC;
+       }
+       strcpy(config, opt);
+
+       return 0;
+}
+
+__setup("kgdboc=", kgdboc_option_setup);
+
+static void cleanup_kgdboc(void)
+{
+       kgdboc_unregister_kbd();
+       if (configured == 1)
+               kgdb_unregister_io_module(&kgdboc_io_ops);
+}
+
+static int configure_kgdboc(void)
+{
+       struct tty_driver *p;
+       int tty_line = 0;
+       int err;
+       char *cptr = config;
+       struct console *cons;
+
+       err = kgdboc_option_setup(config);
+       if (err || !strlen(config) || isspace(config[0]))
+               goto noconfig;
+
+       err = -ENODEV;
+       kgdboc_io_ops.is_console = 0;
+       kgdb_tty_driver = NULL;
+
+       kgdboc_use_kms = 0;
+       if (strncmp(cptr, "kms,", 4) == 0) {
+               cptr += 4;
+               kgdboc_use_kms = 1;
+       }
+
+       if (kgdboc_register_kbd(&cptr))
+               goto do_register;
+
+       p = tty_find_polling_driver(cptr, &tty_line);
+       if (!p)
+               goto noconfig;
+
+       cons = console_drivers;
+       while (cons) {
+               int idx;
+               if (cons->device && cons->device(cons, &idx) == p &&
+                   idx == tty_line) {
+                       kgdboc_io_ops.is_console = 1;
+                       break;
+               }
+               cons = cons->next;
+       }
+
+       kgdb_tty_driver = p;
+       kgdb_tty_line = tty_line;
+
+do_register:
+       err = kgdb_register_io_module(&kgdboc_io_ops);
+       if (err)
+               goto noconfig;
+
+       configured = 1;
+
+       return 0;
+
+noconfig:
+       config[0] = 0;
+       configured = 0;
+       cleanup_kgdboc();
+
+       return err;
+}
+
+static int __init init_kgdboc(void)
+{
+       /* Already configured? */
+       if (configured == 1)
+               return 0;
+
+       return configure_kgdboc();
+}
+
+static int kgdboc_get_char(void)
+{
+       if (!kgdb_tty_driver)
+               return -1;
+       return kgdb_tty_driver->ops->poll_get_char(kgdb_tty_driver,
+                                               kgdb_tty_line);
+}
+
+static void kgdboc_put_char(u8 chr)
+{
+       if (!kgdb_tty_driver)
+               return;
+       kgdb_tty_driver->ops->poll_put_char(kgdb_tty_driver,
+                                       kgdb_tty_line, chr);
+}
+
+static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp)
+{
+       int len = strlen(kmessage);
+
+       if (len >= MAX_CONFIG_LEN) {
+               printk(KERN_ERR "kgdboc: config string too long\n");
+               return -ENOSPC;
+       }
+
+       /* Only copy in the string if the init function has not run yet */
+       if (configured < 0) {
+               strcpy(config, kmessage);
+               return 0;
+       }
+
+       if (kgdb_connected) {
+               printk(KERN_ERR
+                      "kgdboc: Cannot reconfigure while KGDB is connected.\n");
+
+               return -EBUSY;
+       }
+
+       strcpy(config, kmessage);
+       /* Chop out \n char as a result of echo */
+       if (config[len - 1] == '\n')
+               config[len - 1] = '\0';
+
+       if (configured == 1)
+               cleanup_kgdboc();
+
+       /* Go and configure with the new params. */
+       return configure_kgdboc();
+}
+
+static int dbg_restore_graphics;
+
+static void kgdboc_pre_exp_handler(void)
+{
+       if (!dbg_restore_graphics && kgdboc_use_kms) {
+               dbg_restore_graphics = 1;
+               con_debug_enter(vc_cons[fg_console].d);
+       }
+       /* Increment the module count when the debugger is active */
+       if (!kgdb_connected)
+               try_module_get(THIS_MODULE);
+}
+
+static void kgdboc_post_exp_handler(void)
+{
+       /* decrement the module count when the debugger detaches */
+       if (!kgdb_connected)
+               module_put(THIS_MODULE);
+       if (kgdboc_use_kms && dbg_restore_graphics) {
+               dbg_restore_graphics = 0;
+               con_debug_leave();
+       }
+       kgdboc_restore_input();
+}
+
+static struct kgdb_io kgdboc_io_ops = {
+       .name                   = "kgdboc",
+       .read_char              = kgdboc_get_char,
+       .write_char             = kgdboc_put_char,
+       .pre_exception          = kgdboc_pre_exp_handler,
+       .post_exception         = kgdboc_post_exp_handler,
+};
+
+#ifdef CONFIG_KGDB_SERIAL_CONSOLE
+/* This is only available if kgdboc is a built in for early debugging */
+static int __init kgdboc_early_init(char *opt)
+{
+       /* save the first character of the config string because the
+        * init routine can destroy it.
+        */
+       char save_ch;
+
+       kgdboc_option_setup(opt);
+       save_ch = config[0];
+       init_kgdboc();
+       config[0] = save_ch;
+       return 0;
+}
+
+early_param("ekgdboc", kgdboc_early_init);
+#endif /* CONFIG_KGDB_SERIAL_CONSOLE */
+
+module_init(init_kgdboc);
+module_exit(cleanup_kgdboc);
+module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644);
+MODULE_PARM_DESC(kgdboc, "<serial_device>[,baud]");
+MODULE_DESCRIPTION("KGDB Console TTY Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c
new file mode 100644 (file)
index 0000000..bea5c21
--- /dev/null
@@ -0,0 +1,1192 @@
+/*
+ *  m32r_sio.c
+ *
+ *  Driver for M32R serial ports
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *  Based on drivers/serial/8250.c.
+ *
+ *  Copyright (C) 2001  Russell King.
+ *  Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
+ *
+ * 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.
+ */
+
+/*
+ * A note about mapbase / membase
+ *
+ *  mapbase is the physical address of the IO port.  Currently, we don't
+ *  support this very well, and it may well be dropped from this driver
+ *  in future.  As such, mapbase should be NULL.
+ *
+ *  membase is an 'ioremapped' cookie.  This is compatible with the old
+ *  serial.c driver, and is currently the preferred form.
+ */
+
+#if defined(CONFIG_SERIAL_M32R_SIO_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/delay.h>
+
+#include <asm/m32r.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#define PORT_M32R_BASE PORT_M32R_SIO
+#define PORT_INDEX(x)  (x - PORT_M32R_BASE + 1)
+#define BAUD_RATE      115200
+
+#include <linux/serial_core.h>
+#include "m32r_sio.h"
+#include "m32r_sio_reg.h"
+
+/*
+ * Debugging.
+ */
+#if 0
+#define DEBUG_AUTOCONF(fmt...) printk(fmt)
+#else
+#define DEBUG_AUTOCONF(fmt...) do { } while (0)
+#endif
+
+#if 0
+#define DEBUG_INTR(fmt...)     printk(fmt)
+#else
+#define DEBUG_INTR(fmt...)     do { } while (0)
+#endif
+
+#define PASS_LIMIT     256
+
+/*
+ * We default to IRQ0 for the "no irq" hack.   Some
+ * machine types want others as well - they're free
+ * to redefine this in their header file.
+ */
+#define is_real_interrupt(irq) ((irq) != 0)
+
+#define BASE_BAUD      115200
+
+/* Standard COM flags */
+#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST)
+
+/*
+ * SERIAL_PORT_DFNS tells us about built-in ports that have no
+ * standard enumeration mechanism.   Platforms that can find all
+ * serial ports via mechanisms like ACPI or PCI need not supply it.
+ */
+#if defined(CONFIG_PLAT_USRV)
+
+#define SERIAL_PORT_DFNS                                               \
+       /* UART  CLK     PORT   IRQ            FLAGS */                 \
+       { 0, BASE_BAUD, 0x3F8, PLD_IRQ_UART0, STD_COM_FLAGS }, /* ttyS0 */ \
+       { 0, BASE_BAUD, 0x2F8, PLD_IRQ_UART1, STD_COM_FLAGS }, /* ttyS1 */
+
+#else /* !CONFIG_PLAT_USRV */
+
+#if defined(CONFIG_SERIAL_M32R_PLDSIO)
+#define SERIAL_PORT_DFNS                                               \
+       { 0, BASE_BAUD, ((unsigned long)PLD_ESIO0CR), PLD_IRQ_SIO0_RCV, \
+         STD_COM_FLAGS }, /* ttyS0 */
+#else
+#define SERIAL_PORT_DFNS                                               \
+       { 0, BASE_BAUD, M32R_SIO_OFFSET, M32R_IRQ_SIO0_R,               \
+         STD_COM_FLAGS }, /* ttyS0 */
+#endif
+
+#endif /* !CONFIG_PLAT_USRV */
+
+static struct old_serial_port old_serial_port[] = {
+       SERIAL_PORT_DFNS
+};
+
+#define UART_NR        ARRAY_SIZE(old_serial_port)
+
+struct uart_sio_port {
+       struct uart_port        port;
+       struct timer_list       timer;          /* "no irq" timer */
+       struct list_head        list;           /* ports on this IRQ */
+       unsigned short          rev;
+       unsigned char           acr;
+       unsigned char           ier;
+       unsigned char           lcr;
+       unsigned char           mcr_mask;       /* mask of user bits */
+       unsigned char           mcr_force;      /* mask of forced bits */
+       unsigned char           lsr_break_flag;
+
+       /*
+        * We provide a per-port pm hook.
+        */
+       void                    (*pm)(struct uart_port *port,
+                                     unsigned int state, unsigned int old);
+};
+
+struct irq_info {
+       spinlock_t              lock;
+       struct list_head        *head;
+};
+
+static struct irq_info irq_lists[NR_IRQS];
+
+/*
+ * Here we define the default xmit fifo size used for each type of UART.
+ */
+static const struct serial_uart_config uart_config[] = {
+       [PORT_UNKNOWN] = {
+               .name                   = "unknown",
+               .dfl_xmit_fifo_size     = 1,
+               .flags                  = 0,
+       },
+       [PORT_INDEX(PORT_M32R_SIO)] = {
+               .name                   = "M32RSIO",
+               .dfl_xmit_fifo_size     = 1,
+               .flags                  = 0,
+       },
+};
+
+#ifdef CONFIG_SERIAL_M32R_PLDSIO
+
+#define __sio_in(x) inw((unsigned long)(x))
+#define __sio_out(v,x) outw((v),(unsigned long)(x))
+
+static inline void sio_set_baud_rate(unsigned long baud)
+{
+       unsigned short sbaud;
+       sbaud = (boot_cpu_data.bus_clock / (baud * 4))-1;
+       __sio_out(sbaud, PLD_ESIO0BAUR);
+}
+
+static void sio_reset(void)
+{
+       unsigned short tmp;
+
+       tmp = __sio_in(PLD_ESIO0RXB);
+       tmp = __sio_in(PLD_ESIO0RXB);
+       tmp = __sio_in(PLD_ESIO0CR);
+       sio_set_baud_rate(BAUD_RATE);
+       __sio_out(0x0300, PLD_ESIO0CR);
+       __sio_out(0x0003, PLD_ESIO0CR);
+}
+
+static void sio_init(void)
+{
+       unsigned short tmp;
+
+       tmp = __sio_in(PLD_ESIO0RXB);
+       tmp = __sio_in(PLD_ESIO0RXB);
+       tmp = __sio_in(PLD_ESIO0CR);
+       __sio_out(0x0300, PLD_ESIO0CR);
+       __sio_out(0x0003, PLD_ESIO0CR);
+}
+
+static void sio_error(int *status)
+{
+       printk("SIO0 error[%04x]\n", *status);
+       do {
+               sio_init();
+       } while ((*status = __sio_in(PLD_ESIO0CR)) != 3);
+}
+
+#else /* not CONFIG_SERIAL_M32R_PLDSIO */
+
+#define __sio_in(x) inl(x)
+#define __sio_out(v,x) outl((v),(x))
+
+static inline void sio_set_baud_rate(unsigned long baud)
+{
+       unsigned long i, j;
+
+       i = boot_cpu_data.bus_clock / (baud * 16);
+       j = (boot_cpu_data.bus_clock - (i * baud * 16)) / baud;
+       i -= 1;
+       j = (j + 1) >> 1;
+
+       __sio_out(i, M32R_SIO0_BAUR_PORTL);
+       __sio_out(j, M32R_SIO0_RBAUR_PORTL);
+}
+
+static void sio_reset(void)
+{
+       __sio_out(0x00000300, M32R_SIO0_CR_PORTL);      /* init status */
+       __sio_out(0x00000800, M32R_SIO0_MOD1_PORTL);    /* 8bit        */
+       __sio_out(0x00000080, M32R_SIO0_MOD0_PORTL);    /* 1stop non   */
+       sio_set_baud_rate(BAUD_RATE);
+       __sio_out(0x00000000, M32R_SIO0_TRCR_PORTL);
+       __sio_out(0x00000003, M32R_SIO0_CR_PORTL);      /* RXCEN */
+}
+
+static void sio_init(void)
+{
+       unsigned int tmp;
+
+       tmp = __sio_in(M32R_SIO0_RXB_PORTL);
+       tmp = __sio_in(M32R_SIO0_RXB_PORTL);
+       tmp = __sio_in(M32R_SIO0_STS_PORTL);
+       __sio_out(0x00000003, M32R_SIO0_CR_PORTL);
+}
+
+static void sio_error(int *status)
+{
+       printk("SIO0 error[%04x]\n", *status);
+       do {
+               sio_init();
+       } while ((*status = __sio_in(M32R_SIO0_CR_PORTL)) != 3);
+}
+
+#endif /* CONFIG_SERIAL_M32R_PLDSIO */
+
+static unsigned int sio_in(struct uart_sio_port *up, int offset)
+{
+       return __sio_in(up->port.iobase + offset);
+}
+
+static void sio_out(struct uart_sio_port *up, int offset, int value)
+{
+       __sio_out(value, up->port.iobase + offset);
+}
+
+static unsigned int serial_in(struct uart_sio_port *up, int offset)
+{
+       if (!offset)
+               return 0;
+
+       return __sio_in(offset);
+}
+
+static void serial_out(struct uart_sio_port *up, int offset, int value)
+{
+       if (!offset)
+               return;
+
+       __sio_out(value, offset);
+}
+
+static void m32r_sio_stop_tx(struct uart_port *port)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+
+       if (up->ier & UART_IER_THRI) {
+               up->ier &= ~UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+       }
+}
+
+static void m32r_sio_start_tx(struct uart_port *port)
+{
+#ifdef CONFIG_SERIAL_M32R_PLDSIO
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+       struct circ_buf *xmit = &up->port.state->xmit;
+
+       if (!(up->ier & UART_IER_THRI)) {
+               up->ier |= UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               up->port.icount.tx++;
+       }
+       while((serial_in(up, UART_LSR) & UART_EMPTY) != UART_EMPTY);
+#else
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+
+       if (!(up->ier & UART_IER_THRI)) {
+               up->ier |= UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+       }
+#endif
+}
+
+static void m32r_sio_stop_rx(struct uart_port *port)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+
+       up->ier &= ~UART_IER_RLSI;
+       up->port.read_status_mask &= ~UART_LSR_DR;
+       serial_out(up, UART_IER, up->ier);
+}
+
+static void m32r_sio_enable_ms(struct uart_port *port)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+
+       up->ier |= UART_IER_MSI;
+       serial_out(up, UART_IER, up->ier);
+}
+
+static void receive_chars(struct uart_sio_port *up, int *status)
+{
+       struct tty_struct *tty = up->port.state->port.tty;
+       unsigned char ch;
+       unsigned char flag;
+       int max_count = 256;
+
+       do {
+               ch = sio_in(up, SIORXB);
+               flag = TTY_NORMAL;
+               up->port.icount.rx++;
+
+               if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
+                                      UART_LSR_FE | UART_LSR_OE))) {
+                       /*
+                        * For statistics only
+                        */
+                       if (*status & UART_LSR_BI) {
+                               *status &= ~(UART_LSR_FE | UART_LSR_PE);
+                               up->port.icount.brk++;
+                               /*
+                                * We do the SysRQ and SAK checking
+                                * here because otherwise the break
+                                * may get masked by ignore_status_mask
+                                * or read_status_mask.
+                                */
+                               if (uart_handle_break(&up->port))
+                                       goto ignore_char;
+                       } else if (*status & UART_LSR_PE)
+                               up->port.icount.parity++;
+                       else if (*status & UART_LSR_FE)
+                               up->port.icount.frame++;
+                       if (*status & UART_LSR_OE)
+                               up->port.icount.overrun++;
+
+                       /*
+                        * Mask off conditions which should be ingored.
+                        */
+                       *status &= up->port.read_status_mask;
+
+                       if (up->port.line == up->port.cons->index) {
+                               /* Recover the break flag from console xmit */
+                               *status |= up->lsr_break_flag;
+                               up->lsr_break_flag = 0;
+                       }
+
+                       if (*status & UART_LSR_BI) {
+                               DEBUG_INTR("handling break....");
+                               flag = TTY_BREAK;
+                       } else if (*status & UART_LSR_PE)
+                               flag = TTY_PARITY;
+                       else if (*status & UART_LSR_FE)
+                               flag = TTY_FRAME;
+               }
+               if (uart_handle_sysrq_char(&up->port, ch))
+                       goto ignore_char;
+               if ((*status & up->port.ignore_status_mask) == 0)
+                       tty_insert_flip_char(tty, ch, flag);
+
+               if (*status & UART_LSR_OE) {
+                       /*
+                        * Overrun is special, since it's reported
+                        * immediately, and doesn't affect the current
+                        * character.
+                        */
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+               }
+       ignore_char:
+               *status = serial_in(up, UART_LSR);
+       } while ((*status & UART_LSR_DR) && (max_count-- > 0));
+       tty_flip_buffer_push(tty);
+}
+
+static void transmit_chars(struct uart_sio_port *up)
+{
+       struct circ_buf *xmit = &up->port.state->xmit;
+       int count;
+
+       if (up->port.x_char) {
+#ifndef CONFIG_SERIAL_M32R_PLDSIO      /* XXX */
+               serial_out(up, UART_TX, up->port.x_char);
+#endif
+               up->port.icount.tx++;
+               up->port.x_char = 0;
+               return;
+       }
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+               m32r_sio_stop_tx(&up->port);
+               return;
+       }
+
+       count = up->port.fifosize;
+       do {
+               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               up->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+               while (!(serial_in(up, UART_LSR) & UART_LSR_THRE));
+
+       } while (--count > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+       DEBUG_INTR("THRE...");
+
+       if (uart_circ_empty(xmit))
+               m32r_sio_stop_tx(&up->port);
+}
+
+/*
+ * This handles the interrupt from one port.
+ */
+static inline void m32r_sio_handle_port(struct uart_sio_port *up,
+       unsigned int status)
+{
+       DEBUG_INTR("status = %x...", status);
+
+       if (status & 0x04)
+               receive_chars(up, &status);
+       if (status & 0x01)
+               transmit_chars(up);
+}
+
+/*
+ * This is the serial driver's interrupt routine.
+ *
+ * Arjan thinks the old way was overly complex, so it got simplified.
+ * Alan disagrees, saying that need the complexity to handle the weird
+ * nature of ISA shared interrupts.  (This is a special exception.)
+ *
+ * In order to handle ISA shared interrupts properly, we need to check
+ * that all ports have been serviced, and therefore the ISA interrupt
+ * line has been de-asserted.
+ *
+ * This means we need to loop through all ports. checking that they
+ * don't have an interrupt pending.
+ */
+static irqreturn_t m32r_sio_interrupt(int irq, void *dev_id)
+{
+       struct irq_info *i = dev_id;
+       struct list_head *l, *end = NULL;
+       int pass_counter = 0;
+
+       DEBUG_INTR("m32r_sio_interrupt(%d)...", irq);
+
+#ifdef CONFIG_SERIAL_M32R_PLDSIO
+//     if (irq == PLD_IRQ_SIO0_SND)
+//             irq = PLD_IRQ_SIO0_RCV;
+#else
+       if (irq == M32R_IRQ_SIO0_S)
+               irq = M32R_IRQ_SIO0_R;
+#endif
+
+       spin_lock(&i->lock);
+
+       l = i->head;
+       do {
+               struct uart_sio_port *up;
+               unsigned int sts;
+
+               up = list_entry(l, struct uart_sio_port, list);
+
+               sts = sio_in(up, SIOSTS);
+               if (sts & 0x5) {
+                       spin_lock(&up->port.lock);
+                       m32r_sio_handle_port(up, sts);
+                       spin_unlock(&up->port.lock);
+
+                       end = NULL;
+               } else if (end == NULL)
+                       end = l;
+
+               l = l->next;
+
+               if (l == i->head && pass_counter++ > PASS_LIMIT) {
+                       if (sts & 0xe0)
+                               sio_error(&sts);
+                       break;
+               }
+       } while (l != end);
+
+       spin_unlock(&i->lock);
+
+       DEBUG_INTR("end.\n");
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * To support ISA shared interrupts, we need to have one interrupt
+ * handler that ensures that the IRQ line has been deasserted
+ * before returning.  Failing to do this will result in the IRQ
+ * line being stuck active, and, since ISA irqs are edge triggered,
+ * no more IRQs will be seen.
+ */
+static void serial_do_unlink(struct irq_info *i, struct uart_sio_port *up)
+{
+       spin_lock_irq(&i->lock);
+
+       if (!list_empty(i->head)) {
+               if (i->head == &up->list)
+                       i->head = i->head->next;
+               list_del(&up->list);
+       } else {
+               BUG_ON(i->head != &up->list);
+               i->head = NULL;
+       }
+
+       spin_unlock_irq(&i->lock);
+}
+
+static int serial_link_irq_chain(struct uart_sio_port *up)
+{
+       struct irq_info *i = irq_lists + up->port.irq;
+       int ret, irq_flags = 0;
+
+       spin_lock_irq(&i->lock);
+
+       if (i->head) {
+               list_add(&up->list, i->head);
+               spin_unlock_irq(&i->lock);
+
+               ret = 0;
+       } else {
+               INIT_LIST_HEAD(&up->list);
+               i->head = &up->list;
+               spin_unlock_irq(&i->lock);
+
+               ret = request_irq(up->port.irq, m32r_sio_interrupt,
+                                 irq_flags, "SIO0-RX", i);
+               ret |= request_irq(up->port.irq + 1, m32r_sio_interrupt,
+                                 irq_flags, "SIO0-TX", i);
+               if (ret < 0)
+                       serial_do_unlink(i, up);
+       }
+
+       return ret;
+}
+
+static void serial_unlink_irq_chain(struct uart_sio_port *up)
+{
+       struct irq_info *i = irq_lists + up->port.irq;
+
+       BUG_ON(i->head == NULL);
+
+       if (list_empty(i->head)) {
+               free_irq(up->port.irq, i);
+               free_irq(up->port.irq + 1, i);
+       }
+
+       serial_do_unlink(i, up);
+}
+
+/*
+ * This function is used to handle ports that do not have an interrupt.
+ */
+static void m32r_sio_timeout(unsigned long data)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)data;
+       unsigned int timeout;
+       unsigned int sts;
+
+       sts = sio_in(up, SIOSTS);
+       if (sts & 0x5) {
+               spin_lock(&up->port.lock);
+               m32r_sio_handle_port(up, sts);
+               spin_unlock(&up->port.lock);
+       }
+
+       timeout = up->port.timeout;
+       timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
+       mod_timer(&up->timer, jiffies + timeout);
+}
+
+static unsigned int m32r_sio_tx_empty(struct uart_port *port)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+       unsigned long flags;
+       unsigned int ret;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       return ret;
+}
+
+static unsigned int m32r_sio_get_mctrl(struct uart_port *port)
+{
+       return 0;
+}
+
+static void m32r_sio_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+
+}
+
+static void m32r_sio_break_ctl(struct uart_port *port, int break_state)
+{
+
+}
+
+static int m32r_sio_startup(struct uart_port *port)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+       int retval;
+
+       sio_init();
+
+       /*
+        * If the "interrupt" for this port doesn't correspond with any
+        * hardware interrupt, we use a timer-based system.  The original
+        * driver used to do this with IRQ0.
+        */
+       if (!is_real_interrupt(up->port.irq)) {
+               unsigned int timeout = up->port.timeout;
+
+               timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
+
+               up->timer.data = (unsigned long)up;
+               mod_timer(&up->timer, jiffies + timeout);
+       } else {
+               retval = serial_link_irq_chain(up);
+               if (retval)
+                       return retval;
+       }
+
+       /*
+        * Finally, enable interrupts.  Note: Modem status interrupts
+        * are set via set_termios(), which will be occurring imminently
+        * anyway, so we don't enable them here.
+        * - M32R_SIO: 0x0c
+        * - M32R_PLDSIO: 0x04
+        */
+       up->ier = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
+       sio_out(up, SIOTRCR, up->ier);
+
+       /*
+        * And clear the interrupt registers again for luck.
+        */
+       sio_reset();
+
+       return 0;
+}
+
+static void m32r_sio_shutdown(struct uart_port *port)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+
+       /*
+        * Disable interrupts from this port
+        */
+       up->ier = 0;
+       sio_out(up, SIOTRCR, 0);
+
+       /*
+        * Disable break condition and FIFOs
+        */
+
+       sio_init();
+
+       if (!is_real_interrupt(up->port.irq))
+               del_timer_sync(&up->timer);
+       else
+               serial_unlink_irq_chain(up);
+}
+
+static unsigned int m32r_sio_get_divisor(struct uart_port *port,
+       unsigned int baud)
+{
+       return uart_get_divisor(port, baud);
+}
+
+static void m32r_sio_set_termios(struct uart_port *port,
+       struct ktermios *termios, struct ktermios *old)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+       unsigned char cval = 0;
+       unsigned long flags;
+       unsigned int baud, quot;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               cval = UART_LCR_WLEN5;
+               break;
+       case CS6:
+               cval = UART_LCR_WLEN6;
+               break;
+       case CS7:
+               cval = UART_LCR_WLEN7;
+               break;
+       default:
+       case CS8:
+               cval = UART_LCR_WLEN8;
+               break;
+       }
+
+       if (termios->c_cflag & CSTOPB)
+               cval |= UART_LCR_STOP;
+       if (termios->c_cflag & PARENB)
+               cval |= UART_LCR_PARITY;
+       if (!(termios->c_cflag & PARODD))
+               cval |= UART_LCR_EPAR;
+#ifdef CMSPAR
+       if (termios->c_cflag & CMSPAR)
+               cval |= UART_LCR_SPAR;
+#endif
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+#ifdef CONFIG_SERIAL_M32R_PLDSIO
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/4);
+#else
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+#endif
+       quot = m32r_sio_get_divisor(port, baud);
+
+       /*
+        * Ok, we're now changing the port state.  Do it with
+        * interrupts disabled.
+        */
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       sio_set_baud_rate(baud);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+       if (termios->c_iflag & INPCK)
+               up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               up->port.read_status_mask |= UART_LSR_BI;
+
+       /*
+        * Characteres to ignore
+        */
+       up->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+       if (termios->c_iflag & IGNBRK) {
+               up->port.ignore_status_mask |= UART_LSR_BI;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       up->port.ignore_status_mask |= UART_LSR_OE;
+       }
+
+       /*
+        * ignore all characters if CREAD is not set
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               up->port.ignore_status_mask |= UART_LSR_DR;
+
+       /*
+        * CTS flow control flag and modem status interrupts
+        */
+       up->ier &= ~UART_IER_MSI;
+       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
+               up->ier |= UART_IER_MSI;
+
+       serial_out(up, UART_IER, up->ier);
+
+       up->lcr = cval;                                 /* Save LCR */
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static void m32r_sio_pm(struct uart_port *port, unsigned int state,
+       unsigned int oldstate)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+
+       if (up->pm)
+               up->pm(port, state, oldstate);
+}
+
+/*
+ * Resource handling.  This is complicated by the fact that resources
+ * depend on the port type.  Maybe we should be claiming the standard
+ * 8250 ports, and then trying to get other resources as necessary?
+ */
+static int
+m32r_sio_request_std_resource(struct uart_sio_port *up, struct resource **res)
+{
+       unsigned int size = 8 << up->port.regshift;
+#ifndef CONFIG_SERIAL_M32R_PLDSIO
+       unsigned long start;
+#endif
+       int ret = 0;
+
+       switch (up->port.iotype) {
+       case UPIO_MEM:
+               if (up->port.mapbase) {
+#ifdef CONFIG_SERIAL_M32R_PLDSIO
+                       *res = request_mem_region(up->port.mapbase, size, "serial");
+#else
+                       start = up->port.mapbase;
+                       *res = request_mem_region(start, size, "serial");
+#endif
+                       if (!*res)
+                               ret = -EBUSY;
+               }
+               break;
+
+       case UPIO_PORT:
+               *res = request_region(up->port.iobase, size, "serial");
+               if (!*res)
+                       ret = -EBUSY;
+               break;
+       }
+       return ret;
+}
+
+static void m32r_sio_release_port(struct uart_port *port)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+       unsigned long start, offset = 0, size = 0;
+
+       size <<= up->port.regshift;
+
+       switch (up->port.iotype) {
+       case UPIO_MEM:
+               if (up->port.mapbase) {
+                       /*
+                        * Unmap the area.
+                        */
+                       iounmap(up->port.membase);
+                       up->port.membase = NULL;
+
+                       start = up->port.mapbase;
+
+                       if (size)
+                               release_mem_region(start + offset, size);
+                       release_mem_region(start, 8 << up->port.regshift);
+               }
+               break;
+
+       case UPIO_PORT:
+               start = up->port.iobase;
+
+               if (size)
+                       release_region(start + offset, size);
+               release_region(start + offset, 8 << up->port.regshift);
+               break;
+
+       default:
+               break;
+       }
+}
+
+static int m32r_sio_request_port(struct uart_port *port)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+       struct resource *res = NULL;
+       int ret = 0;
+
+       ret = m32r_sio_request_std_resource(up, &res);
+
+       /*
+        * If we have a mapbase, then request that as well.
+        */
+       if (ret == 0 && up->port.flags & UPF_IOREMAP) {
+               int size = res->end - res->start + 1;
+
+               up->port.membase = ioremap(up->port.mapbase, size);
+               if (!up->port.membase)
+                       ret = -ENOMEM;
+       }
+
+       if (ret < 0) {
+               if (res)
+                       release_resource(res);
+       }
+
+       return ret;
+}
+
+static void m32r_sio_config_port(struct uart_port *port, int flags)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       up->port.type = (PORT_M32R_SIO - PORT_M32R_BASE + 1);
+       up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size;
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static int
+m32r_sio_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       if (ser->irq >= nr_irqs || ser->irq < 0 ||
+           ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||
+           ser->type >= ARRAY_SIZE(uart_config))
+               return -EINVAL;
+       return 0;
+}
+
+static const char *
+m32r_sio_type(struct uart_port *port)
+{
+       int type = port->type;
+
+       if (type >= ARRAY_SIZE(uart_config))
+               type = 0;
+       return uart_config[type].name;
+}
+
+static struct uart_ops m32r_sio_pops = {
+       .tx_empty       = m32r_sio_tx_empty,
+       .set_mctrl      = m32r_sio_set_mctrl,
+       .get_mctrl      = m32r_sio_get_mctrl,
+       .stop_tx        = m32r_sio_stop_tx,
+       .start_tx       = m32r_sio_start_tx,
+       .stop_rx        = m32r_sio_stop_rx,
+       .enable_ms      = m32r_sio_enable_ms,
+       .break_ctl      = m32r_sio_break_ctl,
+       .startup        = m32r_sio_startup,
+       .shutdown       = m32r_sio_shutdown,
+       .set_termios    = m32r_sio_set_termios,
+       .pm             = m32r_sio_pm,
+       .type           = m32r_sio_type,
+       .release_port   = m32r_sio_release_port,
+       .request_port   = m32r_sio_request_port,
+       .config_port    = m32r_sio_config_port,
+       .verify_port    = m32r_sio_verify_port,
+};
+
+static struct uart_sio_port m32r_sio_ports[UART_NR];
+
+static void __init m32r_sio_init_ports(void)
+{
+       struct uart_sio_port *up;
+       static int first = 1;
+       int i;
+
+       if (!first)
+               return;
+       first = 0;
+
+       for (i = 0, up = m32r_sio_ports; i < ARRAY_SIZE(old_serial_port);
+            i++, up++) {
+               up->port.iobase   = old_serial_port[i].port;
+               up->port.irq      = irq_canonicalize(old_serial_port[i].irq);
+               up->port.uartclk  = old_serial_port[i].baud_base * 16;
+               up->port.flags    = old_serial_port[i].flags;
+               up->port.membase  = old_serial_port[i].iomem_base;
+               up->port.iotype   = old_serial_port[i].io_type;
+               up->port.regshift = old_serial_port[i].iomem_reg_shift;
+               up->port.ops      = &m32r_sio_pops;
+       }
+}
+
+static void __init m32r_sio_register_ports(struct uart_driver *drv)
+{
+       int i;
+
+       m32r_sio_init_ports();
+
+       for (i = 0; i < UART_NR; i++) {
+               struct uart_sio_port *up = &m32r_sio_ports[i];
+
+               up->port.line = i;
+               up->port.ops = &m32r_sio_pops;
+               init_timer(&up->timer);
+               up->timer.function = m32r_sio_timeout;
+
+               /*
+                * ALPHA_KLUDGE_MCR needs to be killed.
+                */
+               up->mcr_mask = ~ALPHA_KLUDGE_MCR;
+               up->mcr_force = ALPHA_KLUDGE_MCR;
+
+               uart_add_one_port(drv, &up->port);
+       }
+}
+
+#ifdef CONFIG_SERIAL_M32R_SIO_CONSOLE
+
+/*
+ *     Wait for transmitter & holding register to empty
+ */
+static inline void wait_for_xmitr(struct uart_sio_port *up)
+{
+       unsigned int status, tmout = 10000;
+
+       /* Wait up to 10ms for the character(s) to be sent. */
+       do {
+               status = sio_in(up, SIOSTS);
+
+               if (--tmout == 0)
+                       break;
+               udelay(1);
+       } while ((status & UART_EMPTY) != UART_EMPTY);
+
+       /* Wait up to 1s for flow control if necessary */
+       if (up->port.flags & UPF_CONS_FLOW) {
+               tmout = 1000000;
+               while (--tmout)
+                       udelay(1);
+       }
+}
+
+static void m32r_sio_console_putchar(struct uart_port *port, int ch)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+
+       wait_for_xmitr(up);
+       sio_out(up, SIOTXB, ch);
+}
+
+/*
+ *     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.
+ */
+static void m32r_sio_console_write(struct console *co, const char *s,
+       unsigned int count)
+{
+       struct uart_sio_port *up = &m32r_sio_ports[co->index];
+       unsigned int ier;
+
+       /*
+        *      First save the UER then disable the interrupts
+        */
+       ier = sio_in(up, SIOTRCR);
+       sio_out(up, SIOTRCR, 0);
+
+       uart_console_write(&up->port, s, count, m32r_sio_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the IER
+        */
+       wait_for_xmitr(up);
+       sio_out(up, SIOTRCR, ier);
+}
+
+static int __init m32r_sio_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       int baud = 9600;
+       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.
+        */
+       if (co->index >= UART_NR)
+               co->index = 0;
+       port = &m32r_sio_ports[co->index].port;
+
+       /*
+        * Temporary fix.
+        */
+       spin_lock_init(&port->lock);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver m32r_sio_reg;
+static struct console m32r_sio_console = {
+       .name           = "ttyS",
+       .write          = m32r_sio_console_write,
+       .device         = uart_console_device,
+       .setup          = m32r_sio_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &m32r_sio_reg,
+};
+
+static int __init m32r_sio_console_init(void)
+{
+       sio_reset();
+       sio_init();
+       m32r_sio_init_ports();
+       register_console(&m32r_sio_console);
+       return 0;
+}
+console_initcall(m32r_sio_console_init);
+
+#define M32R_SIO_CONSOLE       &m32r_sio_console
+#else
+#define M32R_SIO_CONSOLE       NULL
+#endif
+
+static struct uart_driver m32r_sio_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "sio",
+       .dev_name               = "ttyS",
+       .major                  = TTY_MAJOR,
+       .minor                  = 64,
+       .nr                     = UART_NR,
+       .cons                   = M32R_SIO_CONSOLE,
+};
+
+/**
+ *     m32r_sio_suspend_port - suspend one serial port
+ *     @line: serial line number
+ *
+ *     Suspend one serial port.
+ */
+void m32r_sio_suspend_port(int line)
+{
+       uart_suspend_port(&m32r_sio_reg, &m32r_sio_ports[line].port);
+}
+
+/**
+ *     m32r_sio_resume_port - resume one serial port
+ *     @line: serial line number
+ *
+ *     Resume one serial port.
+ */
+void m32r_sio_resume_port(int line)
+{
+       uart_resume_port(&m32r_sio_reg, &m32r_sio_ports[line].port);
+}
+
+static int __init m32r_sio_init(void)
+{
+       int ret, i;
+
+       printk(KERN_INFO "Serial: M32R SIO driver\n");
+
+       for (i = 0; i < nr_irqs; i++)
+               spin_lock_init(&irq_lists[i].lock);
+
+       ret = uart_register_driver(&m32r_sio_reg);
+       if (ret >= 0)
+               m32r_sio_register_ports(&m32r_sio_reg);
+
+       return ret;
+}
+
+static void __exit m32r_sio_exit(void)
+{
+       int i;
+
+       for (i = 0; i < UART_NR; i++)
+               uart_remove_one_port(&m32r_sio_reg, &m32r_sio_ports[i].port);
+
+       uart_unregister_driver(&m32r_sio_reg);
+}
+
+module_init(m32r_sio_init);
+module_exit(m32r_sio_exit);
+
+EXPORT_SYMBOL(m32r_sio_suspend_port);
+EXPORT_SYMBOL(m32r_sio_resume_port);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic M32R SIO serial driver");
diff --git a/drivers/tty/serial/m32r_sio.h b/drivers/tty/serial/m32r_sio.h
new file mode 100644 (file)
index 0000000..e9b7e11
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ *  m32r_sio.h
+ *
+ *  Driver for M32R serial ports
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *  Based on drivers/serial/8250.h.
+ *
+ *  Copyright (C) 2001  Russell King.
+ *  Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
+ *
+ * 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.
+ */
+
+
+struct m32r_sio_probe {
+       struct module   *owner;
+       int             (*pci_init_one)(struct pci_dev *dev);
+       void            (*pci_remove_one)(struct pci_dev *dev);
+       void            (*pnp_init)(void);
+};
+
+int m32r_sio_register_probe(struct m32r_sio_probe *probe);
+void m32r_sio_unregister_probe(struct m32r_sio_probe *probe);
+void m32r_sio_get_irq_map(unsigned int *map);
+void m32r_sio_suspend_port(int line);
+void m32r_sio_resume_port(int line);
+
+struct old_serial_port {
+       unsigned int uart;
+       unsigned int baud_base;
+       unsigned int port;
+       unsigned int irq;
+       unsigned int flags;
+       unsigned char io_type;
+       unsigned char __iomem *iomem_base;
+       unsigned short iomem_reg_shift;
+};
+
+#define _INLINE_ inline
+
+#define PROBE_RSA      (1 << 0)
+#define PROBE_ANY      (~0)
+
+#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
diff --git a/drivers/tty/serial/m32r_sio_reg.h b/drivers/tty/serial/m32r_sio_reg.h
new file mode 100644 (file)
index 0000000..4671473
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * m32r_sio_reg.h
+ *
+ * Copyright (C) 1992, 1994 by Theodore Ts'o.
+ * Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
+ *
+ * Redistribution of this file is permitted under the terms of the GNU
+ * Public License (GPL)
+ *
+ * These are the UART port assignments, expressed as offsets from the base
+ * register.  These assignments should hold for any serial port based on
+ * a 8250, 16450, or 16550(A).
+ */
+
+#ifndef _M32R_SIO_REG_H
+#define _M32R_SIO_REG_H
+
+
+#ifdef CONFIG_SERIAL_M32R_PLDSIO
+
+#define SIOCR          0x000
+#define SIOMOD0                0x002
+#define SIOMOD1                0x004
+#define SIOSTS         0x006
+#define SIOTRCR                0x008
+#define SIOBAUR                0x00a
+// #define SIORBAUR    0x018
+#define SIOTXB         0x00c
+#define SIORXB         0x00e
+
+#define UART_RX                ((unsigned long) PLD_ESIO0RXB)
+                               /* In:  Receive buffer (DLAB=0) */
+#define UART_TX                ((unsigned long) PLD_ESIO0TXB)
+                               /* Out: Transmit buffer (DLAB=0) */
+#define UART_DLL       0       /* Out: Divisor Latch Low (DLAB=1) */
+#define UART_TRG       0       /* (LCR=BF) FCTR bit 7 selects Rx or Tx
+                                * In: Fifo count
+                                * Out: Fifo custom trigger levels
+                                * XR16C85x only */
+
+#define UART_DLM       0       /* Out: Divisor Latch High (DLAB=1) */
+#define UART_IER       ((unsigned long) PLD_ESIO0INTCR)
+                               /* Out: Interrupt Enable Register */
+#define UART_FCTR      0       /* (LCR=BF) Feature Control Register
+                                * XR16C85x only */
+
+#define UART_IIR       0       /* In:  Interrupt ID Register */
+#define UART_FCR       0       /* Out: FIFO Control Register */
+#define UART_EFR       0       /* I/O: Extended Features Register */
+                               /* (DLAB=1, 16C660 only) */
+
+#define UART_LCR       0       /* Out: Line Control Register */
+#define UART_MCR       0       /* Out: Modem Control Register */
+#define UART_LSR       ((unsigned long) PLD_ESIO0STS)
+                               /* In:  Line Status Register */
+#define UART_MSR       0       /* In:  Modem Status Register */
+#define UART_SCR       0       /* I/O: Scratch Register */
+#define UART_EMSR      0       /* (LCR=BF) Extended Mode Select Register
+                                * FCTR bit 6 selects SCR or EMSR
+                                * XR16c85x only */
+
+#else /* not CONFIG_SERIAL_M32R_PLDSIO */
+
+#define SIOCR          0x000
+#define SIOMOD0                0x004
+#define SIOMOD1                0x008
+#define SIOSTS         0x00c
+#define SIOTRCR                0x010
+#define SIOBAUR                0x014
+#define SIORBAUR       0x018
+#define SIOTXB         0x01c
+#define SIORXB         0x020
+
+#define UART_RX                M32R_SIO0_RXB_PORTL     /* In:  Receive buffer (DLAB=0) */
+#define UART_TX                M32R_SIO0_TXB_PORTL     /* Out: Transmit buffer (DLAB=0) */
+#define UART_DLL       0       /* Out: Divisor Latch Low (DLAB=1) */
+#define UART_TRG       0       /* (LCR=BF) FCTR bit 7 selects Rx or Tx
+                                * In: Fifo count
+                                * Out: Fifo custom trigger levels
+                                * XR16C85x only */
+
+#define UART_DLM       0       /* Out: Divisor Latch High (DLAB=1) */
+#define UART_IER       M32R_SIO0_TRCR_PORTL    /* Out: Interrupt Enable Register */
+#define UART_FCTR      0       /* (LCR=BF) Feature Control Register
+                                * XR16C85x only */
+
+#define UART_IIR       0       /* In:  Interrupt ID Register */
+#define UART_FCR       0       /* Out: FIFO Control Register */
+#define UART_EFR       0       /* I/O: Extended Features Register */
+                               /* (DLAB=1, 16C660 only) */
+
+#define UART_LCR       0       /* Out: Line Control Register */
+#define UART_MCR       0       /* Out: Modem Control Register */
+#define UART_LSR       M32R_SIO0_STS_PORTL     /* In:  Line Status Register */
+#define UART_MSR       0       /* In:  Modem Status Register */
+#define UART_SCR       0       /* I/O: Scratch Register */
+#define UART_EMSR      0       /* (LCR=BF) Extended Mode Select Register
+                                * FCTR bit 6 selects SCR or EMSR
+                                * XR16c85x only */
+
+#endif /* CONFIG_SERIAL_M32R_PLDSIO */
+
+#define UART_EMPTY     (UART_LSR_TEMT | UART_LSR_THRE)
+
+/*
+ * These are the definitions for the Line Control Register
+ *
+ * Note: if the word length is 5 bits (UART_LCR_WLEN5), then setting
+ * UART_LCR_STOP will select 1.5 stop bits, not 2 stop bits.
+ */
+#define UART_LCR_DLAB  0x80    /* Divisor latch access bit */
+#define UART_LCR_SBC   0x40    /* Set break control */
+#define UART_LCR_SPAR  0x20    /* Stick parity (?) */
+#define UART_LCR_EPAR  0x10    /* Even parity select */
+#define UART_LCR_PARITY        0x08    /* Parity Enable */
+#define UART_LCR_STOP  0x04    /* Stop bits: 0=1 stop bit, 1= 2 stop bits */
+#define UART_LCR_WLEN5  0x00   /* Wordlength: 5 bits */
+#define UART_LCR_WLEN6  0x01   /* Wordlength: 6 bits */
+#define UART_LCR_WLEN7  0x02   /* Wordlength: 7 bits */
+#define UART_LCR_WLEN8  0x03   /* Wordlength: 8 bits */
+
+/*
+ * These are the definitions for the Line Status Register
+ */
+#define UART_LSR_TEMT  0x02    /* Transmitter empty */
+#define UART_LSR_THRE  0x01    /* Transmit-hold-register empty */
+#define UART_LSR_BI    0x00    /* Break interrupt indicator */
+#define UART_LSR_FE    0x80    /* Frame error indicator */
+#define UART_LSR_PE    0x40    /* Parity error indicator */
+#define UART_LSR_OE    0x20    /* Overrun error indicator */
+#define UART_LSR_DR    0x04    /* Receiver data ready */
+
+/*
+ * These are the definitions for the Interrupt Identification Register
+ */
+#define UART_IIR_NO_INT        0x01    /* No interrupts pending */
+#define UART_IIR_ID    0x06    /* Mask for the interrupt ID */
+
+#define UART_IIR_MSI   0x00    /* Modem status interrupt */
+#define UART_IIR_THRI  0x02    /* Transmitter holding register empty */
+#define UART_IIR_RDI   0x04    /* Receiver data interrupt */
+#define UART_IIR_RLSI  0x06    /* Receiver line status interrupt */
+
+/*
+ * These are the definitions for the Interrupt Enable Register
+ */
+#define UART_IER_MSI   0x00    /* Enable Modem status interrupt */
+#define UART_IER_RLSI  0x08    /* Enable receiver line status interrupt */
+#define UART_IER_THRI  0x03    /* Enable Transmitter holding register int. */
+#define UART_IER_RDI   0x04    /* Enable receiver data interrupt */
+
+#endif /* _M32R_SIO_REG_H */
diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c
new file mode 100644 (file)
index 0000000..beb1afa
--- /dev/null
@@ -0,0 +1,926 @@
+/*
+ *
+ *  Copyright (C) 2008 Christian Pellegrin <chripell@evolware.org>
+ *
+ * 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.
+ *
+ *
+ * Notes: the MAX3100 doesn't provide an interrupt on CTS so we have
+ * to use polling for flow control. TX empty IRQ is unusable, since
+ * writing conf clears FIFO buffer and we cannot have this interrupt
+ * always asking us for attention.
+ *
+ * Example platform data:
+
+ static struct plat_max3100 max3100_plat_data = {
+ .loopback = 0,
+ .crystal = 0,
+ .poll_time = 100,
+ };
+
+ static struct spi_board_info spi_board_info[] = {
+ {
+ .modalias     = "max3100",
+ .platform_data        = &max3100_plat_data,
+ .irq          = IRQ_EINT12,
+ .max_speed_hz = 5*1000*1000,
+ .chip_select  = 0,
+ },
+ };
+
+ * The initial minor number is 209 in the low-density serial port:
+ * mknod /dev/ttyMAX0 c 204 209
+ */
+
+#define MAX3100_MAJOR 204
+#define MAX3100_MINOR 209
+/* 4 MAX3100s should be enough for everyone */
+#define MAX_MAX3100 4
+
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/spi/spi.h>
+#include <linux/freezer.h>
+
+#include <linux/serial_max3100.h>
+
+#define MAX3100_C    (1<<14)
+#define MAX3100_D    (0<<14)
+#define MAX3100_W    (1<<15)
+#define MAX3100_RX   (0<<15)
+
+#define MAX3100_WC   (MAX3100_W  | MAX3100_C)
+#define MAX3100_RC   (MAX3100_RX | MAX3100_C)
+#define MAX3100_WD   (MAX3100_W  | MAX3100_D)
+#define MAX3100_RD   (MAX3100_RX | MAX3100_D)
+#define MAX3100_CMD  (3 << 14)
+
+#define MAX3100_T    (1<<14)
+#define MAX3100_R    (1<<15)
+
+#define MAX3100_FEN  (1<<13)
+#define MAX3100_SHDN (1<<12)
+#define MAX3100_TM   (1<<11)
+#define MAX3100_RM   (1<<10)
+#define MAX3100_PM   (1<<9)
+#define MAX3100_RAM  (1<<8)
+#define MAX3100_IR   (1<<7)
+#define MAX3100_ST   (1<<6)
+#define MAX3100_PE   (1<<5)
+#define MAX3100_L    (1<<4)
+#define MAX3100_BAUD (0xf)
+
+#define MAX3100_TE   (1<<10)
+#define MAX3100_RAFE (1<<10)
+#define MAX3100_RTS  (1<<9)
+#define MAX3100_CTS  (1<<9)
+#define MAX3100_PT   (1<<8)
+#define MAX3100_DATA (0xff)
+
+#define MAX3100_RT   (MAX3100_R | MAX3100_T)
+#define MAX3100_RTC  (MAX3100_RT | MAX3100_CTS | MAX3100_RAFE)
+
+/* the following simulate a status reg for ignore_status_mask */
+#define MAX3100_STATUS_PE 1
+#define MAX3100_STATUS_FE 2
+#define MAX3100_STATUS_OE 4
+
+struct max3100_port {
+       struct uart_port port;
+       struct spi_device *spi;
+
+       int cts;                /* last CTS received for flow ctrl */
+       int tx_empty;           /* last TX empty bit */
+
+       spinlock_t conf_lock;   /* shared data */
+       int conf_commit;        /* need to make changes */
+       int conf;               /* configuration for the MAX31000
+                                * (bits 0-7, bits 8-11 are irqs) */
+       int rts_commit;         /* need to change rts */
+       int rts;                /* rts status */
+       int baud;               /* current baud rate */
+
+       int parity;             /* keeps track if we should send parity */
+#define MAX3100_PARITY_ON 1
+#define MAX3100_PARITY_ODD 2
+#define MAX3100_7BIT 4
+       int rx_enabled;         /* if we should rx chars */
+
+       int irq;                /* irq assigned to the max3100 */
+
+       int minor;              /* minor number */
+       int crystal;            /* 1 if 3.6864Mhz crystal 0 for 1.8432 */
+       int loopback;           /* 1 if we are in loopback mode */
+
+       /* for handling irqs: need workqueue since we do spi_sync */
+       struct workqueue_struct *workqueue;
+       struct work_struct work;
+       /* set to 1 to make the workhandler exit as soon as possible */
+       int  force_end_work;
+       /* need to know we are suspending to avoid deadlock on workqueue */
+       int suspending;
+
+       /* hook for suspending MAX3100 via dedicated pin */
+       void (*max3100_hw_suspend) (int suspend);
+
+       /* poll time (in ms) for ctrl lines */
+       int poll_time;
+       /* and its timer */
+       struct timer_list       timer;
+};
+
+static struct max3100_port *max3100s[MAX_MAX3100]; /* the chips */
+static DEFINE_MUTEX(max3100s_lock);               /* race on probe */
+
+static int max3100_do_parity(struct max3100_port *s, u16 c)
+{
+       int parity;
+
+       if (s->parity & MAX3100_PARITY_ODD)
+               parity = 1;
+       else
+               parity = 0;
+
+       if (s->parity & MAX3100_7BIT)
+               c &= 0x7f;
+       else
+               c &= 0xff;
+
+       parity = parity ^ (hweight8(c) & 1);
+       return parity;
+}
+
+static int max3100_check_parity(struct max3100_port *s, u16 c)
+{
+       return max3100_do_parity(s, c) == ((c >> 8) & 1);
+}
+
+static void max3100_calc_parity(struct max3100_port *s, u16 *c)
+{
+       if (s->parity & MAX3100_7BIT)
+               *c &= 0x7f;
+       else
+               *c &= 0xff;
+
+       if (s->parity & MAX3100_PARITY_ON)
+               *c |= max3100_do_parity(s, *c) << 8;
+}
+
+static void max3100_work(struct work_struct *w);
+
+static void max3100_dowork(struct max3100_port *s)
+{
+       if (!s->force_end_work && !work_pending(&s->work) &&
+           !freezing(current) && !s->suspending)
+               queue_work(s->workqueue, &s->work);
+}
+
+static void max3100_timeout(unsigned long data)
+{
+       struct max3100_port *s = (struct max3100_port *)data;
+
+       if (s->port.state) {
+               max3100_dowork(s);
+               mod_timer(&s->timer, jiffies + s->poll_time);
+       }
+}
+
+static int max3100_sr(struct max3100_port *s, u16 tx, u16 *rx)
+{
+       struct spi_message message;
+       u16 etx, erx;
+       int status;
+       struct spi_transfer tran = {
+               .tx_buf = &etx,
+               .rx_buf = &erx,
+               .len = 2,
+       };
+
+       etx = cpu_to_be16(tx);
+       spi_message_init(&message);
+       spi_message_add_tail(&tran, &message);
+       status = spi_sync(s->spi, &message);
+       if (status) {
+               dev_warn(&s->spi->dev, "error while calling spi_sync\n");
+               return -EIO;
+       }
+       *rx = be16_to_cpu(erx);
+       s->tx_empty = (*rx & MAX3100_T) > 0;
+       dev_dbg(&s->spi->dev, "%04x - %04x\n", tx, *rx);
+       return 0;
+}
+
+static int max3100_handlerx(struct max3100_port *s, u16 rx)
+{
+       unsigned int ch, flg, status = 0;
+       int ret = 0, cts;
+
+       if (rx & MAX3100_R && s->rx_enabled) {
+               dev_dbg(&s->spi->dev, "%s\n", __func__);
+               ch = rx & (s->parity & MAX3100_7BIT ? 0x7f : 0xff);
+               if (rx & MAX3100_RAFE) {
+                       s->port.icount.frame++;
+                       flg = TTY_FRAME;
+                       status |= MAX3100_STATUS_FE;
+               } else {
+                       if (s->parity & MAX3100_PARITY_ON) {
+                               if (max3100_check_parity(s, rx)) {
+                                       s->port.icount.rx++;
+                                       flg = TTY_NORMAL;
+                               } else {
+                                       s->port.icount.parity++;
+                                       flg = TTY_PARITY;
+                                       status |= MAX3100_STATUS_PE;
+                               }
+                       } else {
+                               s->port.icount.rx++;
+                               flg = TTY_NORMAL;
+                       }
+               }
+               uart_insert_char(&s->port, status, MAX3100_STATUS_OE, ch, flg);
+               ret = 1;
+       }
+
+       cts = (rx & MAX3100_CTS) > 0;
+       if (s->cts != cts) {
+               s->cts = cts;
+               uart_handle_cts_change(&s->port, cts ? TIOCM_CTS : 0);
+       }
+
+       return ret;
+}
+
+static void max3100_work(struct work_struct *w)
+{
+       struct max3100_port *s = container_of(w, struct max3100_port, work);
+       int rxchars;
+       u16 tx, rx;
+       int conf, cconf, rts, crts;
+       struct circ_buf *xmit = &s->port.state->xmit;
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       rxchars = 0;
+       do {
+               spin_lock(&s->conf_lock);
+               conf = s->conf;
+               cconf = s->conf_commit;
+               s->conf_commit = 0;
+               rts = s->rts;
+               crts = s->rts_commit;
+               s->rts_commit = 0;
+               spin_unlock(&s->conf_lock);
+               if (cconf)
+                       max3100_sr(s, MAX3100_WC | conf, &rx);
+               if (crts) {
+                       max3100_sr(s, MAX3100_WD | MAX3100_TE |
+                                  (s->rts ? MAX3100_RTS : 0), &rx);
+                       rxchars += max3100_handlerx(s, rx);
+               }
+
+               max3100_sr(s, MAX3100_RD, &rx);
+               rxchars += max3100_handlerx(s, rx);
+
+               if (rx & MAX3100_T) {
+                       tx = 0xffff;
+                       if (s->port.x_char) {
+                               tx = s->port.x_char;
+                               s->port.icount.tx++;
+                               s->port.x_char = 0;
+                       } else if (!uart_circ_empty(xmit) &&
+                                  !uart_tx_stopped(&s->port)) {
+                               tx = xmit->buf[xmit->tail];
+                               xmit->tail = (xmit->tail + 1) &
+                                       (UART_XMIT_SIZE - 1);
+                               s->port.icount.tx++;
+                       }
+                       if (tx != 0xffff) {
+                               max3100_calc_parity(s, &tx);
+                               tx |= MAX3100_WD | (s->rts ? MAX3100_RTS : 0);
+                               max3100_sr(s, tx, &rx);
+                               rxchars += max3100_handlerx(s, rx);
+                       }
+               }
+
+               if (rxchars > 16 && s->port.state->port.tty != NULL) {
+                       tty_flip_buffer_push(s->port.state->port.tty);
+                       rxchars = 0;
+               }
+               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+                       uart_write_wakeup(&s->port);
+
+       } while (!s->force_end_work &&
+                !freezing(current) &&
+                ((rx & MAX3100_R) ||
+                 (!uart_circ_empty(xmit) &&
+                  !uart_tx_stopped(&s->port))));
+
+       if (rxchars > 0 && s->port.state->port.tty != NULL)
+               tty_flip_buffer_push(s->port.state->port.tty);
+}
+
+static irqreturn_t max3100_irq(int irqno, void *dev_id)
+{
+       struct max3100_port *s = dev_id;
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       max3100_dowork(s);
+       return IRQ_HANDLED;
+}
+
+static void max3100_enable_ms(struct uart_port *port)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+
+       if (s->poll_time > 0)
+               mod_timer(&s->timer, jiffies);
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+}
+
+static void max3100_start_tx(struct uart_port *port)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       max3100_dowork(s);
+}
+
+static void max3100_stop_rx(struct uart_port *port)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       s->rx_enabled = 0;
+       spin_lock(&s->conf_lock);
+       s->conf &= ~MAX3100_RM;
+       s->conf_commit = 1;
+       spin_unlock(&s->conf_lock);
+       max3100_dowork(s);
+}
+
+static unsigned int max3100_tx_empty(struct uart_port *port)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       /* may not be truly up-to-date */
+       max3100_dowork(s);
+       return s->tx_empty;
+}
+
+static unsigned int max3100_get_mctrl(struct uart_port *port)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       /* may not be truly up-to-date */
+       max3100_dowork(s);
+       /* always assert DCD and DSR since these lines are not wired */
+       return (s->cts ? TIOCM_CTS : 0) | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void max3100_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+       int rts;
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       rts = (mctrl & TIOCM_RTS) > 0;
+
+       spin_lock(&s->conf_lock);
+       if (s->rts != rts) {
+               s->rts = rts;
+               s->rts_commit = 1;
+               max3100_dowork(s);
+       }
+       spin_unlock(&s->conf_lock);
+}
+
+static void
+max3100_set_termios(struct uart_port *port, struct ktermios *termios,
+                   struct ktermios *old)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+       int baud = 0;
+       unsigned cflag;
+       u32 param_new, param_mask, parity = 0;
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       cflag = termios->c_cflag;
+       param_new = 0;
+       param_mask = 0;
+
+       baud = tty_termios_baud_rate(termios);
+       param_new = s->conf & MAX3100_BAUD;
+       switch (baud) {
+       case 300:
+               if (s->crystal)
+                       baud = s->baud;
+               else
+                       param_new = 15;
+               break;
+       case 600:
+               param_new = 14 + s->crystal;
+               break;
+       case 1200:
+               param_new = 13 + s->crystal;
+               break;
+       case 2400:
+               param_new = 12 + s->crystal;
+               break;
+       case 4800:
+               param_new = 11 + s->crystal;
+               break;
+       case 9600:
+               param_new = 10 + s->crystal;
+               break;
+       case 19200:
+               param_new = 9 + s->crystal;
+               break;
+       case 38400:
+               param_new = 8 + s->crystal;
+               break;
+       case 57600:
+               param_new = 1 + s->crystal;
+               break;
+       case 115200:
+               param_new = 0 + s->crystal;
+               break;
+       case 230400:
+               if (s->crystal)
+                       param_new = 0;
+               else
+                       baud = s->baud;
+               break;
+       default:
+               baud = s->baud;
+       }
+       tty_termios_encode_baud_rate(termios, baud, baud);
+       s->baud = baud;
+       param_mask |= MAX3100_BAUD;
+
+       if ((cflag & CSIZE) == CS8) {
+               param_new &= ~MAX3100_L;
+               parity &= ~MAX3100_7BIT;
+       } else {
+               param_new |= MAX3100_L;
+               parity |= MAX3100_7BIT;
+               cflag = (cflag & ~CSIZE) | CS7;
+       }
+       param_mask |= MAX3100_L;
+
+       if (cflag & CSTOPB)
+               param_new |= MAX3100_ST;
+       else
+               param_new &= ~MAX3100_ST;
+       param_mask |= MAX3100_ST;
+
+       if (cflag & PARENB) {
+               param_new |= MAX3100_PE;
+               parity |= MAX3100_PARITY_ON;
+       } else {
+               param_new &= ~MAX3100_PE;
+               parity &= ~MAX3100_PARITY_ON;
+       }
+       param_mask |= MAX3100_PE;
+
+       if (cflag & PARODD)
+               parity |= MAX3100_PARITY_ODD;
+       else
+               parity &= ~MAX3100_PARITY_ODD;
+
+       /* mask termios capabilities we don't support */
+       cflag &= ~CMSPAR;
+       termios->c_cflag = cflag;
+
+       s->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               s->port.ignore_status_mask |=
+                       MAX3100_STATUS_PE | MAX3100_STATUS_FE |
+                       MAX3100_STATUS_OE;
+
+       /* we are sending char from a workqueue so enable */
+       s->port.state->port.tty->low_latency = 1;
+
+       if (s->poll_time > 0)
+               del_timer_sync(&s->timer);
+
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       spin_lock(&s->conf_lock);
+       s->conf = (s->conf & ~param_mask) | (param_new & param_mask);
+       s->conf_commit = 1;
+       s->parity = parity;
+       spin_unlock(&s->conf_lock);
+       max3100_dowork(s);
+
+       if (UART_ENABLE_MS(&s->port, termios->c_cflag))
+               max3100_enable_ms(&s->port);
+}
+
+static void max3100_shutdown(struct uart_port *port)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       if (s->suspending)
+               return;
+
+       s->force_end_work = 1;
+
+       if (s->poll_time > 0)
+               del_timer_sync(&s->timer);
+
+       if (s->workqueue) {
+               flush_workqueue(s->workqueue);
+               destroy_workqueue(s->workqueue);
+               s->workqueue = NULL;
+       }
+       if (s->irq)
+               free_irq(s->irq, s);
+
+       /* set shutdown mode to save power */
+       if (s->max3100_hw_suspend)
+               s->max3100_hw_suspend(1);
+       else  {
+               u16 tx, rx;
+
+               tx = MAX3100_WC | MAX3100_SHDN;
+               max3100_sr(s, tx, &rx);
+       }
+}
+
+static int max3100_startup(struct uart_port *port)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+       char b[12];
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       s->conf = MAX3100_RM;
+       s->baud = s->crystal ? 230400 : 115200;
+       s->rx_enabled = 1;
+
+       if (s->suspending)
+               return 0;
+
+       s->force_end_work = 0;
+       s->parity = 0;
+       s->rts = 0;
+
+       sprintf(b, "max3100-%d", s->minor);
+       s->workqueue = create_freezeable_workqueue(b);
+       if (!s->workqueue) {
+               dev_warn(&s->spi->dev, "cannot create workqueue\n");
+               return -EBUSY;
+       }
+       INIT_WORK(&s->work, max3100_work);
+
+       if (request_irq(s->irq, max3100_irq,
+                       IRQF_TRIGGER_FALLING, "max3100", s) < 0) {
+               dev_warn(&s->spi->dev, "cannot allocate irq %d\n", s->irq);
+               s->irq = 0;
+               destroy_workqueue(s->workqueue);
+               s->workqueue = NULL;
+               return -EBUSY;
+       }
+
+       if (s->loopback) {
+               u16 tx, rx;
+               tx = 0x4001;
+               max3100_sr(s, tx, &rx);
+       }
+
+       if (s->max3100_hw_suspend)
+               s->max3100_hw_suspend(0);
+       s->conf_commit = 1;
+       max3100_dowork(s);
+       /* wait for clock to settle */
+       msleep(50);
+
+       max3100_enable_ms(&s->port);
+
+       return 0;
+}
+
+static const char *max3100_type(struct uart_port *port)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       return s->port.type == PORT_MAX3100 ? "MAX3100" : NULL;
+}
+
+static void max3100_release_port(struct uart_port *port)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+}
+
+static void max3100_config_port(struct uart_port *port, int flags)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       if (flags & UART_CONFIG_TYPE)
+               s->port.type = PORT_MAX3100;
+}
+
+static int max3100_verify_port(struct uart_port *port,
+                              struct serial_struct *ser)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+       int ret = -EINVAL;
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       if (ser->type == PORT_UNKNOWN || ser->type == PORT_MAX3100)
+               ret = 0;
+       return ret;
+}
+
+static void max3100_stop_tx(struct uart_port *port)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+}
+
+static int max3100_request_port(struct uart_port *port)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+       return 0;
+}
+
+static void max3100_break_ctl(struct uart_port *port, int break_state)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+}
+
+static struct uart_ops max3100_ops = {
+       .tx_empty       = max3100_tx_empty,
+       .set_mctrl      = max3100_set_mctrl,
+       .get_mctrl      = max3100_get_mctrl,
+       .stop_tx        = max3100_stop_tx,
+       .start_tx       = max3100_start_tx,
+       .stop_rx        = max3100_stop_rx,
+       .enable_ms      = max3100_enable_ms,
+       .break_ctl      = max3100_break_ctl,
+       .startup        = max3100_startup,
+       .shutdown       = max3100_shutdown,
+       .set_termios    = max3100_set_termios,
+       .type           = max3100_type,
+       .release_port   = max3100_release_port,
+       .request_port   = max3100_request_port,
+       .config_port    = max3100_config_port,
+       .verify_port    = max3100_verify_port,
+};
+
+static struct uart_driver max3100_uart_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "ttyMAX",
+       .dev_name       = "ttyMAX",
+       .major          = MAX3100_MAJOR,
+       .minor          = MAX3100_MINOR,
+       .nr             = MAX_MAX3100,
+};
+static int uart_driver_registered;
+
+static int __devinit max3100_probe(struct spi_device *spi)
+{
+       int i, retval;
+       struct plat_max3100 *pdata;
+       u16 tx, rx;
+
+       mutex_lock(&max3100s_lock);
+
+       if (!uart_driver_registered) {
+               uart_driver_registered = 1;
+               retval = uart_register_driver(&max3100_uart_driver);
+               if (retval) {
+                       printk(KERN_ERR "Couldn't register max3100 uart driver\n");
+                       mutex_unlock(&max3100s_lock);
+                       return retval;
+               }
+       }
+
+       for (i = 0; i < MAX_MAX3100; i++)
+               if (!max3100s[i])
+                       break;
+       if (i == MAX_MAX3100) {
+               dev_warn(&spi->dev, "too many MAX3100 chips\n");
+               mutex_unlock(&max3100s_lock);
+               return -ENOMEM;
+       }
+
+       max3100s[i] = kzalloc(sizeof(struct max3100_port), GFP_KERNEL);
+       if (!max3100s[i]) {
+               dev_warn(&spi->dev,
+                        "kmalloc for max3100 structure %d failed!\n", i);
+               mutex_unlock(&max3100s_lock);
+               return -ENOMEM;
+       }
+       max3100s[i]->spi = spi;
+       max3100s[i]->irq = spi->irq;
+       spin_lock_init(&max3100s[i]->conf_lock);
+       dev_set_drvdata(&spi->dev, max3100s[i]);
+       pdata = spi->dev.platform_data;
+       max3100s[i]->crystal = pdata->crystal;
+       max3100s[i]->loopback = pdata->loopback;
+       max3100s[i]->poll_time = pdata->poll_time * HZ / 1000;
+       if (pdata->poll_time > 0 && max3100s[i]->poll_time == 0)
+               max3100s[i]->poll_time = 1;
+       max3100s[i]->max3100_hw_suspend = pdata->max3100_hw_suspend;
+       max3100s[i]->minor = i;
+       init_timer(&max3100s[i]->timer);
+       max3100s[i]->timer.function = max3100_timeout;
+       max3100s[i]->timer.data = (unsigned long) max3100s[i];
+
+       dev_dbg(&spi->dev, "%s: adding port %d\n", __func__, i);
+       max3100s[i]->port.irq = max3100s[i]->irq;
+       max3100s[i]->port.uartclk = max3100s[i]->crystal ? 3686400 : 1843200;
+       max3100s[i]->port.fifosize = 16;
+       max3100s[i]->port.ops = &max3100_ops;
+       max3100s[i]->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
+       max3100s[i]->port.line = i;
+       max3100s[i]->port.type = PORT_MAX3100;
+       max3100s[i]->port.dev = &spi->dev;
+       retval = uart_add_one_port(&max3100_uart_driver, &max3100s[i]->port);
+       if (retval < 0)
+               dev_warn(&spi->dev,
+                        "uart_add_one_port failed for line %d with error %d\n",
+                        i, retval);
+
+       /* set shutdown mode to save power. Will be woken-up on open */
+       if (max3100s[i]->max3100_hw_suspend)
+               max3100s[i]->max3100_hw_suspend(1);
+       else {
+               tx = MAX3100_WC | MAX3100_SHDN;
+               max3100_sr(max3100s[i], tx, &rx);
+       }
+       mutex_unlock(&max3100s_lock);
+       return 0;
+}
+
+static int __devexit max3100_remove(struct spi_device *spi)
+{
+       struct max3100_port *s = dev_get_drvdata(&spi->dev);
+       int i;
+
+       mutex_lock(&max3100s_lock);
+
+       /* find out the index for the chip we are removing */
+       for (i = 0; i < MAX_MAX3100; i++)
+               if (max3100s[i] == s)
+                       break;
+
+       dev_dbg(&spi->dev, "%s: removing port %d\n", __func__, i);
+       uart_remove_one_port(&max3100_uart_driver, &max3100s[i]->port);
+       kfree(max3100s[i]);
+       max3100s[i] = NULL;
+
+       /* check if this is the last chip we have */
+       for (i = 0; i < MAX_MAX3100; i++)
+               if (max3100s[i]) {
+                       mutex_unlock(&max3100s_lock);
+                       return 0;
+               }
+       pr_debug("removing max3100 driver\n");
+       uart_unregister_driver(&max3100_uart_driver);
+
+       mutex_unlock(&max3100s_lock);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int max3100_suspend(struct spi_device *spi, pm_message_t state)
+{
+       struct max3100_port *s = dev_get_drvdata(&spi->dev);
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       disable_irq(s->irq);
+
+       s->suspending = 1;
+       uart_suspend_port(&max3100_uart_driver, &s->port);
+
+       if (s->max3100_hw_suspend)
+               s->max3100_hw_suspend(1);
+       else {
+               /* no HW suspend, so do SW one */
+               u16 tx, rx;
+
+               tx = MAX3100_WC | MAX3100_SHDN;
+               max3100_sr(s, tx, &rx);
+       }
+       return 0;
+}
+
+static int max3100_resume(struct spi_device *spi)
+{
+       struct max3100_port *s = dev_get_drvdata(&spi->dev);
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       if (s->max3100_hw_suspend)
+               s->max3100_hw_suspend(0);
+       uart_resume_port(&max3100_uart_driver, &s->port);
+       s->suspending = 0;
+
+       enable_irq(s->irq);
+
+       s->conf_commit = 1;
+       if (s->workqueue)
+               max3100_dowork(s);
+
+       return 0;
+}
+
+#else
+#define max3100_suspend NULL
+#define max3100_resume  NULL
+#endif
+
+static struct spi_driver max3100_driver = {
+       .driver = {
+               .name           = "max3100",
+               .bus            = &spi_bus_type,
+               .owner          = THIS_MODULE,
+       },
+
+       .probe          = max3100_probe,
+       .remove         = __devexit_p(max3100_remove),
+       .suspend        = max3100_suspend,
+       .resume         = max3100_resume,
+};
+
+static int __init max3100_init(void)
+{
+       return spi_register_driver(&max3100_driver);
+}
+module_init(max3100_init);
+
+static void __exit max3100_exit(void)
+{
+       spi_unregister_driver(&max3100_driver);
+}
+module_exit(max3100_exit);
+
+MODULE_DESCRIPTION("MAX3100 driver");
+MODULE_AUTHOR("Christian Pellegrin <chripell@evolware.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:max3100");
diff --git a/drivers/tty/serial/max3107-aava.c b/drivers/tty/serial/max3107-aava.c
new file mode 100644 (file)
index 0000000..a1fe304
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ *  max3107.c - spi uart protocol driver for Maxim 3107
+ *  Based on max3100.c
+ *     by Christian Pellegrin <chripell@evolware.org>
+ *  and        max3110.c
+ *     by Feng Tang <feng.tang@intel.com>
+ *
+ *  Copyright (C) Aavamobile 2009
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  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/delay.h>
+#include <linux/device.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/spi/spi.h>
+#include <linux/freezer.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/sfi.h>
+#include <asm/mrst.h>
+#include "max3107.h"
+
+/* GPIO direction to input function */
+static int max3107_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+       struct max3107_port *s = container_of(chip, struct max3107_port, chip);
+       u16 buf[1];             /* Buffer for SPI transfer */
+
+       if (offset >= MAX3107_GPIO_COUNT) {
+               dev_err(&s->spi->dev, "Invalid GPIO\n");
+               return -EINVAL;
+       }
+
+       /* Read current GPIO configuration register */
+       buf[0] = MAX3107_GPIOCFG_REG;
+       /* Perform SPI transfer */
+       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
+               dev_err(&s->spi->dev, "SPI transfer GPIO read failed\n");
+               return -EIO;
+       }
+       buf[0] &= MAX3107_SPI_RX_DATA_MASK;
+
+       /* Set GPIO to input */
+       buf[0] &= ~(0x0001 << offset);
+
+       /* Write new GPIO configuration register value */
+       buf[0] |= (MAX3107_WRITE_BIT | MAX3107_GPIOCFG_REG);
+       /* Perform SPI transfer */
+       if (max3107_rw(s, (u8 *)buf, NULL, 2)) {
+               dev_err(&s->spi->dev, "SPI transfer GPIO write failed\n");
+               return -EIO;
+       }
+       return 0;
+}
+
+/* GPIO direction to output function */
+static int max3107_gpio_direction_out(struct gpio_chip *chip, unsigned offset,
+                                       int value)
+{
+       struct max3107_port *s = container_of(chip, struct max3107_port, chip);
+       u16 buf[2];     /* Buffer for SPI transfers */
+
+       if (offset >= MAX3107_GPIO_COUNT) {
+               dev_err(&s->spi->dev, "Invalid GPIO\n");
+               return -EINVAL;
+       }
+
+       /* Read current GPIO configuration and data registers */
+       buf[0] = MAX3107_GPIOCFG_REG;
+       buf[1] = MAX3107_GPIODATA_REG;
+       /* Perform SPI transfer */
+       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 4)) {
+               dev_err(&s->spi->dev, "SPI transfer gpio failed\n");
+               return -EIO;
+       }
+       buf[0] &= MAX3107_SPI_RX_DATA_MASK;
+       buf[1] &= MAX3107_SPI_RX_DATA_MASK;
+
+       /* Set GPIO to output */
+       buf[0] |= (0x0001 << offset);
+       /* Set value */
+       if (value)
+               buf[1] |= (0x0001 << offset);
+       else
+               buf[1] &= ~(0x0001 << offset);
+
+       /* Write new GPIO configuration and data register values */
+       buf[0] |= (MAX3107_WRITE_BIT | MAX3107_GPIOCFG_REG);
+       buf[1] |= (MAX3107_WRITE_BIT | MAX3107_GPIODATA_REG);
+       /* Perform SPI transfer */
+       if (max3107_rw(s, (u8 *)buf, NULL, 4)) {
+               dev_err(&s->spi->dev,
+                       "SPI transfer for GPIO conf data w failed\n");
+               return -EIO;
+       }
+       return 0;
+}
+
+/* GPIO value query function */
+static int max3107_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       struct max3107_port *s = container_of(chip, struct max3107_port, chip);
+       u16 buf[1];     /* Buffer for SPI transfer */
+
+       if (offset >= MAX3107_GPIO_COUNT) {
+               dev_err(&s->spi->dev, "Invalid GPIO\n");
+               return -EINVAL;
+       }
+
+       /* Read current GPIO data register */
+       buf[0] = MAX3107_GPIODATA_REG;
+       /* Perform SPI transfer */
+       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
+               dev_err(&s->spi->dev, "SPI transfer GPIO data r failed\n");
+               return -EIO;
+       }
+       buf[0] &= MAX3107_SPI_RX_DATA_MASK;
+
+       /* Return value */
+       return buf[0] & (0x0001 << offset);
+}
+
+/* GPIO value set function */
+static void max3107_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct max3107_port *s = container_of(chip, struct max3107_port, chip);
+       u16 buf[2];     /* Buffer for SPI transfers */
+
+       if (offset >= MAX3107_GPIO_COUNT) {
+               dev_err(&s->spi->dev, "Invalid GPIO\n");
+               return;
+       }
+
+       /* Read current GPIO configuration registers*/
+       buf[0] = MAX3107_GPIODATA_REG;
+       buf[1] = MAX3107_GPIOCFG_REG;
+       /* Perform SPI transfer */
+       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 4)) {
+               dev_err(&s->spi->dev,
+                       "SPI transfer for GPIO data and config read failed\n");
+               return;
+       }
+       buf[0] &= MAX3107_SPI_RX_DATA_MASK;
+       buf[1] &= MAX3107_SPI_RX_DATA_MASK;
+
+       if (!(buf[1] & (0x0001 << offset))) {
+               /* Configured as input, can't set value */
+               dev_warn(&s->spi->dev,
+                               "Trying to set value for input GPIO\n");
+               return;
+       }
+
+       /* Set value */
+       if (value)
+               buf[0] |= (0x0001 << offset);
+       else
+               buf[0] &= ~(0x0001 << offset);
+
+       /* Write new GPIO data register value */
+       buf[0] |= (MAX3107_WRITE_BIT | MAX3107_GPIODATA_REG);
+       /* Perform SPI transfer */
+       if (max3107_rw(s, (u8 *)buf, NULL, 2))
+               dev_err(&s->spi->dev, "SPI transfer GPIO data w failed\n");
+}
+
+/* GPIO chip data */
+static struct gpio_chip max3107_gpio_chip = {
+       .owner                  = THIS_MODULE,
+       .direction_input        = max3107_gpio_direction_in,
+       .direction_output       = max3107_gpio_direction_out,
+       .get                    = max3107_gpio_get,
+       .set                    = max3107_gpio_set,
+       .can_sleep              = 1,
+       .base                   = MAX3107_GPIO_BASE,
+       .ngpio                  = MAX3107_GPIO_COUNT,
+};
+
+/**
+ *     max3107_aava_reset      -       reset on AAVA systems
+ *     @spi: The SPI device we are probing
+ *
+ *     Reset the device ready for probing.
+ */
+
+static int max3107_aava_reset(struct spi_device *spi)
+{
+       /* Reset the chip */
+       if (gpio_request(MAX3107_RESET_GPIO, "max3107")) {
+               pr_err("Requesting RESET GPIO failed\n");
+               return -EIO;
+       }
+       if (gpio_direction_output(MAX3107_RESET_GPIO, 0)) {
+               pr_err("Setting RESET GPIO to 0 failed\n");
+               gpio_free(MAX3107_RESET_GPIO);
+               return -EIO;
+       }
+       msleep(MAX3107_RESET_DELAY);
+       if (gpio_direction_output(MAX3107_RESET_GPIO, 1)) {
+               pr_err("Setting RESET GPIO to 1 failed\n");
+               gpio_free(MAX3107_RESET_GPIO);
+               return -EIO;
+       }
+       gpio_free(MAX3107_RESET_GPIO);
+       msleep(MAX3107_WAKEUP_DELAY);
+       return 0;
+}
+
+static int max3107_aava_configure(struct max3107_port *s)
+{
+       int retval;
+
+       /* Initialize GPIO chip data */
+       s->chip = max3107_gpio_chip;
+       s->chip.label = s->spi->modalias;
+       s->chip.dev = &s->spi->dev;
+
+       /* Add GPIO chip */
+       retval = gpiochip_add(&s->chip);
+       if (retval) {
+               dev_err(&s->spi->dev, "Adding GPIO chip failed\n");
+               return retval;
+       }
+
+       /* Temporary fix for EV2 boot problems, set modem reset to 0 */
+       max3107_gpio_direction_out(&s->chip, 3, 0);
+       return 0;
+}
+
+#if 0
+/* This will get enabled once we have the board stuff merged for this
+   specific case */
+
+static const struct baud_table brg13_ext[] = {
+       { 300,    MAX3107_BRG13_B300 },
+       { 600,    MAX3107_BRG13_B600 },
+       { 1200,   MAX3107_BRG13_B1200 },
+       { 2400,   MAX3107_BRG13_B2400 },
+       { 4800,   MAX3107_BRG13_B4800 },
+       { 9600,   MAX3107_BRG13_B9600 },
+       { 19200,  MAX3107_BRG13_B19200 },
+       { 57600,  MAX3107_BRG13_B57600 },
+       { 115200, MAX3107_BRG13_B115200 },
+       { 230400, MAX3107_BRG13_B230400 },
+       { 460800, MAX3107_BRG13_B460800 },
+       { 921600, MAX3107_BRG13_B921600 },
+       { 0, 0 }
+};
+
+static void max3107_aava_init(struct max3107_port *s)
+{
+       /*override for AAVA SC specific*/
+       if (mrst_platform_id() == MRST_PLATFORM_AAVA_SC) {
+               if (get_koski_build_id() <= KOSKI_EV2)
+                       if (s->ext_clk) {
+                               s->brg_cfg = MAX3107_BRG13_B9600;
+                               s->baud_tbl = (struct baud_table *)brg13_ext;
+                       }
+       }
+}
+#endif
+
+static int __devexit max3107_aava_remove(struct spi_device *spi)
+{
+       struct max3107_port *s = dev_get_drvdata(&spi->dev);
+
+       /* Remove GPIO chip */
+       if (gpiochip_remove(&s->chip))
+               dev_warn(&spi->dev, "Removing GPIO chip failed\n");
+
+       /* Then do the default remove */
+       return max3107_remove(spi);
+}
+
+/* Platform data */
+static struct max3107_plat aava_plat_data = {
+       .loopback               = 0,
+       .ext_clk                = 1,
+/*     .init                   = max3107_aava_init, */
+       .configure              = max3107_aava_configure,
+       .hw_suspend             = max3107_hw_susp,
+       .polled_mode            = 0,
+       .poll_time              = 0,
+};
+
+
+static int __devinit max3107_probe_aava(struct spi_device *spi)
+{
+       int err = max3107_aava_reset(spi);
+       if (err < 0)
+               return err;
+       return max3107_probe(spi, &aava_plat_data);
+}
+
+/* Spi driver data */
+static struct spi_driver max3107_driver = {
+       .driver = {
+               .name           = "aava-max3107",
+               .bus            = &spi_bus_type,
+               .owner          = THIS_MODULE,
+       },
+       .probe          = max3107_probe_aava,
+       .remove         = __devexit_p(max3107_aava_remove),
+       .suspend        = max3107_suspend,
+       .resume         = max3107_resume,
+};
+
+/* Driver init function */
+static int __init max3107_init(void)
+{
+       return spi_register_driver(&max3107_driver);
+}
+
+/* Driver exit function */
+static void __exit max3107_exit(void)
+{
+       spi_unregister_driver(&max3107_driver);
+}
+
+module_init(max3107_init);
+module_exit(max3107_exit);
+
+MODULE_DESCRIPTION("MAX3107 driver");
+MODULE_AUTHOR("Aavamobile");
+MODULE_ALIAS("aava-max3107-spi");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/max3107.c b/drivers/tty/serial/max3107.c
new file mode 100644 (file)
index 0000000..910870e
--- /dev/null
@@ -0,0 +1,1213 @@
+/*
+ *  max3107.c - spi uart protocol driver for Maxim 3107
+ *  Based on max3100.c
+ *     by Christian Pellegrin <chripell@evolware.org>
+ *  and        max3110.c
+ *     by Feng Tang <feng.tang@intel.com>
+ *
+ *  Copyright (C) Aavamobile 2009
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  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/delay.h>
+#include <linux/device.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/freezer.h>
+#include "max3107.h"
+
+static const struct baud_table brg26_ext[] = {
+       { 300,    MAX3107_BRG26_B300 },
+       { 600,    MAX3107_BRG26_B600 },
+       { 1200,   MAX3107_BRG26_B1200 },
+       { 2400,   MAX3107_BRG26_B2400 },
+       { 4800,   MAX3107_BRG26_B4800 },
+       { 9600,   MAX3107_BRG26_B9600 },
+       { 19200,  MAX3107_BRG26_B19200 },
+       { 57600,  MAX3107_BRG26_B57600 },
+       { 115200, MAX3107_BRG26_B115200 },
+       { 230400, MAX3107_BRG26_B230400 },
+       { 460800, MAX3107_BRG26_B460800 },
+       { 921600, MAX3107_BRG26_B921600 },
+       { 0, 0 }
+};
+
+static const struct baud_table brg13_int[] = {
+       { 300,    MAX3107_BRG13_IB300 },
+       { 600,    MAX3107_BRG13_IB600 },
+       { 1200,   MAX3107_BRG13_IB1200 },
+       { 2400,   MAX3107_BRG13_IB2400 },
+       { 4800,   MAX3107_BRG13_IB4800 },
+       { 9600,   MAX3107_BRG13_IB9600 },
+       { 19200,  MAX3107_BRG13_IB19200 },
+       { 57600,  MAX3107_BRG13_IB57600 },
+       { 115200, MAX3107_BRG13_IB115200 },
+       { 230400, MAX3107_BRG13_IB230400 },
+       { 460800, MAX3107_BRG13_IB460800 },
+       { 921600, MAX3107_BRG13_IB921600 },
+       { 0, 0 }
+};
+
+static u32 get_new_brg(int baud, struct max3107_port *s)
+{
+       int i;
+       const struct baud_table *baud_tbl = s->baud_tbl;
+
+       for (i = 0; i < 13; i++) {
+               if (baud == baud_tbl[i].baud)
+                       return baud_tbl[i].new_brg;
+       }
+
+       return 0;
+}
+
+/* Perform SPI transfer for write/read of device register(s) */
+int max3107_rw(struct max3107_port *s, u8 *tx, u8 *rx, int len)
+{
+       struct spi_message spi_msg;
+       struct spi_transfer spi_xfer;
+
+       /* Initialize SPI ,message */
+       spi_message_init(&spi_msg);
+
+       /* Initialize SPI transfer */
+       memset(&spi_xfer, 0, sizeof spi_xfer);
+       spi_xfer.len = len;
+       spi_xfer.tx_buf = tx;
+       spi_xfer.rx_buf = rx;
+       spi_xfer.speed_hz = MAX3107_SPI_SPEED;
+
+       /* Add SPI transfer to SPI message */
+       spi_message_add_tail(&spi_xfer, &spi_msg);
+
+#ifdef DBG_TRACE_SPI_DATA
+       {
+               int i;
+               pr_info("tx len %d:\n", spi_xfer.len);
+               for (i = 0 ; i < spi_xfer.len && i < 32 ; i++)
+                       pr_info(" %x", ((u8 *)spi_xfer.tx_buf)[i]);
+               pr_info("\n");
+       }
+#endif
+
+       /* Perform synchronous SPI transfer */
+       if (spi_sync(s->spi, &spi_msg)) {
+               dev_err(&s->spi->dev, "spi_sync failure\n");
+               return -EIO;
+       }
+
+#ifdef DBG_TRACE_SPI_DATA
+       if (spi_xfer.rx_buf) {
+               int i;
+               pr_info("rx len %d:\n", spi_xfer.len);
+               for (i = 0 ; i < spi_xfer.len && i < 32 ; i++)
+                       pr_info(" %x", ((u8 *)spi_xfer.rx_buf)[i]);
+               pr_info("\n");
+       }
+#endif
+       return 0;
+}
+EXPORT_SYMBOL_GPL(max3107_rw);
+
+/* Puts received data to circular buffer */
+static void put_data_to_circ_buf(struct max3107_port *s, unsigned char *data,
+                                       int len)
+{
+       struct uart_port *port = &s->port;
+       struct tty_struct *tty;
+
+       if (!port->state)
+               return;
+
+       tty = port->state->port.tty;
+       if (!tty)
+               return;
+
+       /* Insert received data */
+       tty_insert_flip_string(tty, data, len);
+       /* Update RX counter */
+       port->icount.rx += len;
+}
+
+/* Handle data receiving */
+static void max3107_handlerx(struct max3107_port *s, u16 rxlvl)
+{
+       int i;
+       int j;
+       int len;                                /* SPI transfer buffer length */
+       u16 *buf;
+       u8 *valid_str;
+
+       if (!s->rx_enabled)
+               /* RX is disabled */
+               return;
+
+       if (rxlvl == 0) {
+               /* RX fifo is empty */
+               return;
+       } else if (rxlvl >= MAX3107_RX_FIFO_SIZE) {
+               dev_warn(&s->spi->dev, "Possible RX FIFO overrun %d\n", rxlvl);
+               /* Ensure sanity of RX level */
+               rxlvl = MAX3107_RX_FIFO_SIZE;
+       }
+       if ((s->rxbuf == 0) || (s->rxstr == 0)) {
+               dev_warn(&s->spi->dev, "Rx buffer/str isn't ready\n");
+               return;
+       }
+       buf = s->rxbuf;
+       valid_str = s->rxstr;
+       while (rxlvl) {
+               pr_debug("rxlvl %d\n", rxlvl);
+               /* Clear buffer */
+               memset(buf, 0, sizeof(u16) * (MAX3107_RX_FIFO_SIZE + 2));
+               len = 0;
+               if (s->irqen_reg & MAX3107_IRQ_RXFIFO_BIT) {
+                       /* First disable RX FIFO interrupt */
+                       pr_debug("Disabling RX INT\n");
+                       buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
+                       s->irqen_reg &= ~MAX3107_IRQ_RXFIFO_BIT;
+                       buf[0] |= s->irqen_reg;
+                       len++;
+               }
+               /* Just increase the length by amount of words in FIFO since
+                * buffer was zeroed and SPI transfer of 0x0000 means reading
+                * from RX FIFO
+                */
+               len += rxlvl;
+               /* Append RX level query */
+               buf[len] = MAX3107_RXFIFOLVL_REG;
+               len++;
+
+               /* Perform the SPI transfer */
+               if (max3107_rw(s, (u8 *)buf, (u8 *)buf, len * 2)) {
+                       dev_err(&s->spi->dev, "SPI transfer for RX h failed\n");
+                       return;
+               }
+
+               /* Skip RX FIFO interrupt disabling word if it was added */
+               j = ((len - 1) - rxlvl);
+               /* Read received words */
+               for (i = 0; i < rxlvl; i++, j++)
+                       valid_str[i] = (u8)buf[j];
+               put_data_to_circ_buf(s, valid_str, rxlvl);
+               /* Get new RX level */
+               rxlvl = (buf[len - 1] & MAX3107_SPI_RX_DATA_MASK);
+       }
+
+       if (s->rx_enabled) {
+               /* RX still enabled, re-enable RX FIFO interrupt */
+               pr_debug("Enabling RX INT\n");
+               buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
+               s->irqen_reg |= MAX3107_IRQ_RXFIFO_BIT;
+               buf[0] |= s->irqen_reg;
+               if (max3107_rw(s, (u8 *)buf, NULL, 2))
+                       dev_err(&s->spi->dev, "RX FIFO INT enabling failed\n");
+       }
+
+       /* Push the received data to receivers */
+       if (s->port.state->port.tty)
+               tty_flip_buffer_push(s->port.state->port.tty);
+}
+
+
+/* Handle data sending */
+static void max3107_handletx(struct max3107_port *s)
+{
+       struct circ_buf *xmit = &s->port.state->xmit;
+       int i;
+       unsigned long flags;
+       int len;                                /* SPI transfer buffer length */
+       u16 *buf;
+
+       if (!s->tx_fifo_empty)
+               /* Don't send more data before previous data is sent */
+               return;
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&s->port))
+               /* No data to send or TX is stopped */
+               return;
+
+       if (!s->txbuf) {
+               dev_warn(&s->spi->dev, "Txbuf isn't ready\n");
+               return;
+       }
+       buf = s->txbuf;
+       /* Get length of data pending in circular buffer */
+       len = uart_circ_chars_pending(xmit);
+       if (len) {
+               /* Limit to size of TX FIFO */
+               if (len > MAX3107_TX_FIFO_SIZE)
+                       len = MAX3107_TX_FIFO_SIZE;
+
+               pr_debug("txlen %d\n", len);
+
+               /* Update TX counter */
+               s->port.icount.tx += len;
+
+               /* TX FIFO will no longer be empty */
+               s->tx_fifo_empty = 0;
+
+               i = 0;
+               if (s->irqen_reg & MAX3107_IRQ_TXEMPTY_BIT) {
+                       /* First disable TX empty interrupt */
+                       pr_debug("Disabling TE INT\n");
+                       buf[i] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
+                       s->irqen_reg &= ~MAX3107_IRQ_TXEMPTY_BIT;
+                       buf[i] |= s->irqen_reg;
+                       i++;
+                       len++;
+               }
+               /* Add data to send */
+               spin_lock_irqsave(&s->port.lock, flags);
+               for ( ; i < len ; i++) {
+                       buf[i] = (MAX3107_WRITE_BIT | MAX3107_THR_REG);
+                       buf[i] |= ((u16)xmit->buf[xmit->tail] &
+                                               MAX3107_SPI_TX_DATA_MASK);
+                       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               }
+               spin_unlock_irqrestore(&s->port.lock, flags);
+               if (!(s->irqen_reg & MAX3107_IRQ_TXEMPTY_BIT)) {
+                       /* Enable TX empty interrupt */
+                       pr_debug("Enabling TE INT\n");
+                       buf[i] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
+                       s->irqen_reg |= MAX3107_IRQ_TXEMPTY_BIT;
+                       buf[i] |= s->irqen_reg;
+                       i++;
+                       len++;
+               }
+               if (!s->tx_enabled) {
+                       /* Enable TX */
+                       pr_debug("Enable TX\n");
+                       buf[i] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
+                       spin_lock_irqsave(&s->data_lock, flags);
+                       s->mode1_reg &= ~MAX3107_MODE1_TXDIS_BIT;
+                       buf[i] |= s->mode1_reg;
+                       spin_unlock_irqrestore(&s->data_lock, flags);
+                       s->tx_enabled = 1;
+                       i++;
+                       len++;
+               }
+
+               /* Perform the SPI transfer */
+               if (max3107_rw(s, (u8 *)buf, NULL, len*2)) {
+                       dev_err(&s->spi->dev,
+                               "SPI transfer TX handling failed\n");
+                       return;
+               }
+       }
+
+       /* Indicate wake up if circular buffer is getting low on data */
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&s->port);
+
+}
+
+/* Handle interrupts
+ * Also reads and returns current RX FIFO level
+ */
+static u16 handle_interrupt(struct max3107_port *s)
+{
+       u16 buf[4];     /* Buffer for SPI transfers */
+       u8 irq_status;
+       u16 rx_level;
+       unsigned long flags;
+
+       /* Read IRQ status register */
+       buf[0] = MAX3107_IRQSTS_REG;
+       /* Read status IRQ status register */
+       buf[1] = MAX3107_STS_IRQSTS_REG;
+       /* Read LSR IRQ status register */
+       buf[2] = MAX3107_LSR_IRQSTS_REG;
+       /* Query RX level */
+       buf[3] = MAX3107_RXFIFOLVL_REG;
+
+       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 8)) {
+               dev_err(&s->spi->dev,
+                       "SPI transfer for INTR handling failed\n");
+               return 0;
+       }
+
+       irq_status = (u8)buf[0];
+       pr_debug("IRQSTS %x\n", irq_status);
+       rx_level = (buf[3] & MAX3107_SPI_RX_DATA_MASK);
+
+       if (irq_status & MAX3107_IRQ_LSR_BIT) {
+               /* LSR interrupt */
+               if (buf[2] & MAX3107_LSR_RXTO_BIT)
+                       /* RX timeout interrupt,
+                        * handled by normal RX handling
+                        */
+                       pr_debug("RX TO INT\n");
+       }
+
+       if (irq_status & MAX3107_IRQ_TXEMPTY_BIT) {
+               /* Tx empty interrupt,
+                * disable TX and set tx_fifo_empty flag
+                */
+               pr_debug("TE INT, disabling TX\n");
+               buf[0] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
+               spin_lock_irqsave(&s->data_lock, flags);
+               s->mode1_reg |= MAX3107_MODE1_TXDIS_BIT;
+               buf[0] |= s->mode1_reg;
+               spin_unlock_irqrestore(&s->data_lock, flags);
+               if (max3107_rw(s, (u8 *)buf, NULL, 2))
+                       dev_err(&s->spi->dev, "SPI transfer TX dis failed\n");
+               s->tx_enabled = 0;
+               s->tx_fifo_empty = 1;
+       }
+
+       if (irq_status & MAX3107_IRQ_RXFIFO_BIT)
+               /* RX FIFO interrupt,
+                * handled by normal RX handling
+                */
+               pr_debug("RFIFO INT\n");
+
+       /* Return RX level */
+       return rx_level;
+}
+
+/* Trigger work thread*/
+static void max3107_dowork(struct max3107_port *s)
+{
+       if (!work_pending(&s->work) && !freezing(current) && !s->suspended)
+               queue_work(s->workqueue, &s->work);
+       else
+               dev_warn(&s->spi->dev, "interrup isn't serviced normally!\n");
+}
+
+/* Work thread */
+static void max3107_work(struct work_struct *w)
+{
+       struct max3107_port *s = container_of(w, struct max3107_port, work);
+       u16 rxlvl = 0;
+       int len;        /* SPI transfer buffer length */
+       u16 buf[5];     /* Buffer for SPI transfers */
+       unsigned long flags;
+
+       /* Start by reading current RX FIFO level */
+       buf[0] = MAX3107_RXFIFOLVL_REG;
+       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
+               dev_err(&s->spi->dev, "SPI transfer RX lev failed\n");
+               rxlvl = 0;
+       } else {
+               rxlvl = (buf[0] & MAX3107_SPI_RX_DATA_MASK);
+       }
+
+       do {
+               pr_debug("rxlvl %d\n", rxlvl);
+
+               /* Handle RX */
+               max3107_handlerx(s, rxlvl);
+               rxlvl = 0;
+
+               if (s->handle_irq) {
+                       /* Handle pending interrupts
+                        * We also get new RX FIFO level since new data may
+                        * have been received while pushing received data to
+                        * receivers
+                        */
+                       s->handle_irq = 0;
+                       rxlvl = handle_interrupt(s);
+               }
+
+               /* Handle TX */
+               max3107_handletx(s);
+
+               /* Handle configuration changes */
+               len = 0;
+               spin_lock_irqsave(&s->data_lock, flags);
+               if (s->mode1_commit) {
+                       pr_debug("mode1_commit\n");
+                       buf[len] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
+                       buf[len++] |= s->mode1_reg;
+                       s->mode1_commit = 0;
+               }
+               if (s->lcr_commit) {
+                       pr_debug("lcr_commit\n");
+                       buf[len] = (MAX3107_WRITE_BIT | MAX3107_LCR_REG);
+                       buf[len++] |= s->lcr_reg;
+                       s->lcr_commit = 0;
+               }
+               if (s->brg_commit) {
+                       pr_debug("brg_commit\n");
+                       buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVMSB_REG);
+                       buf[len++] |= ((s->brg_cfg >> 16) &
+                                               MAX3107_SPI_TX_DATA_MASK);
+                       buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVLSB_REG);
+                       buf[len++] |= ((s->brg_cfg >> 8) &
+                                               MAX3107_SPI_TX_DATA_MASK);
+                       buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGCFG_REG);
+                       buf[len++] |= ((s->brg_cfg) & 0xff);
+                       s->brg_commit = 0;
+               }
+               spin_unlock_irqrestore(&s->data_lock, flags);
+
+               if (len > 0) {
+                       if (max3107_rw(s, (u8 *)buf, NULL, len * 2))
+                               dev_err(&s->spi->dev,
+                                       "SPI transfer config failed\n");
+               }
+
+               /* Reloop if interrupt handling indicated data in RX FIFO */
+       } while (rxlvl);
+
+}
+
+/* Set sleep mode */
+static void max3107_set_sleep(struct max3107_port *s, int mode)
+{
+       u16 buf[1];     /* Buffer for SPI transfer */
+       unsigned long flags;
+       pr_debug("enter, mode %d\n", mode);
+
+       buf[0] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
+       spin_lock_irqsave(&s->data_lock, flags);
+       switch (mode) {
+       case MAX3107_DISABLE_FORCED_SLEEP:
+                       s->mode1_reg &= ~MAX3107_MODE1_FORCESLEEP_BIT;
+                       break;
+       case MAX3107_ENABLE_FORCED_SLEEP:
+                       s->mode1_reg |= MAX3107_MODE1_FORCESLEEP_BIT;
+                       break;
+       case MAX3107_DISABLE_AUTOSLEEP:
+                       s->mode1_reg &= ~MAX3107_MODE1_AUTOSLEEP_BIT;
+                       break;
+       case MAX3107_ENABLE_AUTOSLEEP:
+                       s->mode1_reg |= MAX3107_MODE1_AUTOSLEEP_BIT;
+                       break;
+       default:
+               spin_unlock_irqrestore(&s->data_lock, flags);
+               dev_warn(&s->spi->dev, "invalid sleep mode\n");
+               return;
+       }
+       buf[0] |= s->mode1_reg;
+       spin_unlock_irqrestore(&s->data_lock, flags);
+
+       if (max3107_rw(s, (u8 *)buf, NULL, 2))
+               dev_err(&s->spi->dev, "SPI transfer sleep mode failed\n");
+
+       if (mode == MAX3107_DISABLE_AUTOSLEEP ||
+                       mode == MAX3107_DISABLE_FORCED_SLEEP)
+               msleep(MAX3107_WAKEUP_DELAY);
+}
+
+/* Perform full register initialization */
+static void max3107_register_init(struct max3107_port *s)
+{
+       u16 buf[11];    /* Buffer for SPI transfers */
+
+       /* 1. Configure baud rate, 9600 as default */
+       s->baud = 9600;
+       /* the below is default*/
+       if (s->ext_clk) {
+               s->brg_cfg = MAX3107_BRG26_B9600;
+               s->baud_tbl = (struct baud_table *)brg26_ext;
+       } else {
+               s->brg_cfg = MAX3107_BRG13_IB9600;
+               s->baud_tbl = (struct baud_table *)brg13_int;
+       }
+
+       if (s->pdata->init)
+               s->pdata->init(s);
+
+       buf[0] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVMSB_REG)
+               | ((s->brg_cfg >> 16) & MAX3107_SPI_TX_DATA_MASK);
+       buf[1] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVLSB_REG)
+               | ((s->brg_cfg >> 8) & MAX3107_SPI_TX_DATA_MASK);
+       buf[2] = (MAX3107_WRITE_BIT | MAX3107_BRGCFG_REG)
+               | ((s->brg_cfg) & 0xff);
+
+       /* 2. Configure LCR register, 8N1 mode by default */
+       s->lcr_reg = MAX3107_LCR_WORD_LEN_8;
+       buf[3] = (MAX3107_WRITE_BIT | MAX3107_LCR_REG)
+               | s->lcr_reg;
+
+       /* 3. Configure MODE 1 register */
+       s->mode1_reg = 0;
+       /* Enable IRQ pin */
+       s->mode1_reg |= MAX3107_MODE1_IRQSEL_BIT;
+       /* Disable TX */
+       s->mode1_reg |= MAX3107_MODE1_TXDIS_BIT;
+       s->tx_enabled = 0;
+       /* RX is enabled */
+       s->rx_enabled = 1;
+       buf[4] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG)
+               | s->mode1_reg;
+
+       /* 4. Configure MODE 2 register */
+       buf[5] = (MAX3107_WRITE_BIT | MAX3107_MODE2_REG);
+       if (s->loopback) {
+               /* Enable loopback */
+               buf[5] |= MAX3107_MODE2_LOOPBACK_BIT;
+       }
+       /* Reset FIFOs */
+       buf[5] |= MAX3107_MODE2_FIFORST_BIT;
+       s->tx_fifo_empty = 1;
+
+       /* 5. Configure FIFO trigger level register */
+       buf[6] = (MAX3107_WRITE_BIT | MAX3107_FIFOTRIGLVL_REG);
+       /* RX FIFO trigger for 16 words, TX FIFO trigger not used */
+       buf[6] |= (MAX3107_FIFOTRIGLVL_RX(16) | MAX3107_FIFOTRIGLVL_TX(0));
+
+       /* 6. Configure flow control levels */
+       buf[7] = (MAX3107_WRITE_BIT | MAX3107_FLOWLVL_REG);
+       /* Flow control halt level 96, resume level 48 */
+       buf[7] |= (MAX3107_FLOWLVL_RES(48) | MAX3107_FLOWLVL_HALT(96));
+
+       /* 7. Configure flow control */
+       buf[8] = (MAX3107_WRITE_BIT | MAX3107_FLOWCTRL_REG);
+       /* Enable auto CTS and auto RTS flow control */
+       buf[8] |= (MAX3107_FLOWCTRL_AUTOCTS_BIT | MAX3107_FLOWCTRL_AUTORTS_BIT);
+
+       /* 8. Configure RX timeout register */
+       buf[9] = (MAX3107_WRITE_BIT | MAX3107_RXTO_REG);
+       /* Timeout after 48 character intervals */
+       buf[9] |= 0x0030;
+
+       /* 9. Configure LSR interrupt enable register */
+       buf[10] = (MAX3107_WRITE_BIT | MAX3107_LSR_IRQEN_REG);
+       /* Enable RX timeout interrupt */
+       buf[10] |= MAX3107_LSR_RXTO_BIT;
+
+       /* Perform SPI transfer */
+       if (max3107_rw(s, (u8 *)buf, NULL, 22))
+               dev_err(&s->spi->dev, "SPI transfer for init failed\n");
+
+       /* 10. Clear IRQ status register by reading it */
+       buf[0] = MAX3107_IRQSTS_REG;
+
+       /* 11. Configure interrupt enable register */
+       /* Enable LSR interrupt */
+       s->irqen_reg = MAX3107_IRQ_LSR_BIT;
+       /* Enable RX FIFO interrupt */
+       s->irqen_reg |= MAX3107_IRQ_RXFIFO_BIT;
+       buf[1] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG)
+               | s->irqen_reg;
+
+       /* 12. Clear FIFO reset that was set in step 6 */
+       buf[2] = (MAX3107_WRITE_BIT | MAX3107_MODE2_REG);
+       if (s->loopback) {
+               /* Keep loopback enabled */
+               buf[2] |= MAX3107_MODE2_LOOPBACK_BIT;
+       }
+
+       /* Perform SPI transfer */
+       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 6))
+               dev_err(&s->spi->dev, "SPI transfer for init failed\n");
+
+}
+
+/* IRQ handler */
+static irqreturn_t max3107_irq(int irqno, void *dev_id)
+{
+       struct max3107_port *s = dev_id;
+
+       if (irqno != s->spi->irq) {
+               /* Unexpected IRQ */
+               return IRQ_NONE;
+       }
+
+       /* Indicate irq */
+       s->handle_irq = 1;
+
+       /* Trigger work thread */
+       max3107_dowork(s);
+
+       return IRQ_HANDLED;
+}
+
+/* HW suspension function
+ *
+ * Currently autosleep is used to decrease current consumption, alternative
+ * approach would be to set the chip to reset mode if UART is not being
+ * used but that would mess the GPIOs
+ *
+ */
+void max3107_hw_susp(struct max3107_port *s, int suspend)
+{
+       pr_debug("enter, suspend %d\n", suspend);
+
+       if (suspend) {
+               /* Suspend requested,
+                * enable autosleep to decrease current consumption
+                */
+               s->suspended = 1;
+               max3107_set_sleep(s, MAX3107_ENABLE_AUTOSLEEP);
+       } else {
+               /* Resume requested,
+                * disable autosleep
+                */
+               s->suspended = 0;
+               max3107_set_sleep(s, MAX3107_DISABLE_AUTOSLEEP);
+       }
+}
+EXPORT_SYMBOL_GPL(max3107_hw_susp);
+
+/* Modem status IRQ enabling */
+static void max3107_enable_ms(struct uart_port *port)
+{
+       /* Modem status not supported */
+}
+
+/* Data send function */
+static void max3107_start_tx(struct uart_port *port)
+{
+       struct max3107_port *s = container_of(port, struct max3107_port, port);
+
+       /* Trigger work thread for sending data */
+       max3107_dowork(s);
+}
+
+/* Function for checking that there is no pending transfers */
+static unsigned int max3107_tx_empty(struct uart_port *port)
+{
+       struct max3107_port *s = container_of(port, struct max3107_port, port);
+
+       pr_debug("returning %d\n",
+                 (s->tx_fifo_empty && uart_circ_empty(&s->port.state->xmit)));
+       return s->tx_fifo_empty && uart_circ_empty(&s->port.state->xmit);
+}
+
+/* Function for stopping RX */
+static void max3107_stop_rx(struct uart_port *port)
+{
+       struct max3107_port *s = container_of(port, struct max3107_port, port);
+       unsigned long flags;
+
+       /* Set RX disabled in MODE 1 register */
+       spin_lock_irqsave(&s->data_lock, flags);
+       s->mode1_reg |= MAX3107_MODE1_RXDIS_BIT;
+       s->mode1_commit = 1;
+       spin_unlock_irqrestore(&s->data_lock, flags);
+       /* Set RX disabled */
+       s->rx_enabled = 0;
+       /* Trigger work thread for doing the actual configuration change */
+       max3107_dowork(s);
+}
+
+/* Function for returning control pin states */
+static unsigned int max3107_get_mctrl(struct uart_port *port)
+{
+       /* DCD and DSR are not wired and CTS/RTS is handled automatically
+        * so just indicate DSR and CAR asserted
+        */
+       return TIOCM_DSR | TIOCM_CAR;
+}
+
+/* Function for setting control pin states */
+static void max3107_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       /* DCD and DSR are not wired and CTS/RTS is hadnled automatically
+        * so do nothing
+        */
+}
+
+/* Function for configuring UART parameters */
+static void max3107_set_termios(struct uart_port *port,
+                               struct ktermios *termios,
+                               struct ktermios *old)
+{
+       struct max3107_port *s = container_of(port, struct max3107_port, port);
+       struct tty_struct *tty;
+       int baud;
+       u16 new_lcr = 0;
+       u32 new_brg = 0;
+       unsigned long flags;
+
+       if (!port->state)
+               return;
+
+       tty = port->state->port.tty;
+       if (!tty)
+               return;
+
+       /* Get new LCR register values */
+       /* Word size */
+       if ((termios->c_cflag & CSIZE) == CS7)
+               new_lcr |= MAX3107_LCR_WORD_LEN_7;
+       else
+               new_lcr |= MAX3107_LCR_WORD_LEN_8;
+
+       /* Parity */
+       if (termios->c_cflag & PARENB) {
+               new_lcr |= MAX3107_LCR_PARITY_BIT;
+               if (!(termios->c_cflag & PARODD))
+                       new_lcr |= MAX3107_LCR_EVENPARITY_BIT;
+       }
+
+       /* Stop bits */
+       if (termios->c_cflag & CSTOPB) {
+               /* 2 stop bits */
+               new_lcr |= MAX3107_LCR_STOPLEN_BIT;
+       }
+
+       /* Mask termios capabilities we don't support */
+       termios->c_cflag &= ~CMSPAR;
+
+       /* Set status ignore mask */
+       s->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               s->port.ignore_status_mask |= MAX3107_ALL_ERRORS;
+
+       /* Set low latency to immediately handle pushed data */
+       s->port.state->port.tty->low_latency = 1;
+
+       /* Get new baud rate generator configuration */
+       baud = tty_get_baud_rate(tty);
+
+       spin_lock_irqsave(&s->data_lock, flags);
+       new_brg = get_new_brg(baud, s);
+       /* if can't find the corrent config, use previous */
+       if (!new_brg) {
+               baud = s->baud;
+               new_brg = s->brg_cfg;
+       }
+       spin_unlock_irqrestore(&s->data_lock, flags);
+       tty_termios_encode_baud_rate(termios, baud, baud);
+       s->baud = baud;
+
+       /* Update timeout according to new baud rate */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       spin_lock_irqsave(&s->data_lock, flags);
+       if (s->lcr_reg != new_lcr) {
+               s->lcr_reg = new_lcr;
+               s->lcr_commit = 1;
+       }
+       if (s->brg_cfg != new_brg) {
+               s->brg_cfg = new_brg;
+               s->brg_commit = 1;
+       }
+       spin_unlock_irqrestore(&s->data_lock, flags);
+
+       /* Trigger work thread for doing the actual configuration change */
+       max3107_dowork(s);
+}
+
+/* Port shutdown function */
+static void max3107_shutdown(struct uart_port *port)
+{
+       struct max3107_port *s = container_of(port, struct max3107_port, port);
+
+       if (s->suspended && s->pdata->hw_suspend)
+               s->pdata->hw_suspend(s, 0);
+
+       /* Free the interrupt */
+       free_irq(s->spi->irq, s);
+
+       if (s->workqueue) {
+               /* Flush and destroy work queue */
+               flush_workqueue(s->workqueue);
+               destroy_workqueue(s->workqueue);
+               s->workqueue = NULL;
+       }
+
+       /* Suspend HW */
+       if (s->pdata->hw_suspend)
+               s->pdata->hw_suspend(s, 1);
+}
+
+/* Port startup function */
+static int max3107_startup(struct uart_port *port)
+{
+       struct max3107_port *s = container_of(port, struct max3107_port, port);
+
+       /* Initialize work queue */
+       s->workqueue = create_freezeable_workqueue("max3107");
+       if (!s->workqueue) {
+               dev_err(&s->spi->dev, "Workqueue creation failed\n");
+               return -EBUSY;
+       }
+       INIT_WORK(&s->work, max3107_work);
+
+       /* Setup IRQ */
+       if (request_irq(s->spi->irq, max3107_irq, IRQF_TRIGGER_FALLING,
+                       "max3107", s)) {
+               dev_err(&s->spi->dev, "IRQ reguest failed\n");
+               destroy_workqueue(s->workqueue);
+               s->workqueue = NULL;
+               return -EBUSY;
+       }
+
+       /* Resume HW */
+       if (s->pdata->hw_suspend)
+               s->pdata->hw_suspend(s, 0);
+
+       /* Init registers */
+       max3107_register_init(s);
+
+       return 0;
+}
+
+/* Port type function */
+static const char *max3107_type(struct uart_port *port)
+{
+       struct max3107_port *s = container_of(port, struct max3107_port, port);
+       return s->spi->modalias;
+}
+
+/* Port release function */
+static void max3107_release_port(struct uart_port *port)
+{
+       /* Do nothing */
+}
+
+/* Port request function */
+static int max3107_request_port(struct uart_port *port)
+{
+       /* Do nothing */
+       return 0;
+}
+
+/* Port config function */
+static void max3107_config_port(struct uart_port *port, int flags)
+{
+       struct max3107_port *s = container_of(port, struct max3107_port, port);
+       s->port.type = PORT_MAX3107;
+}
+
+/* Port verify function */
+static int max3107_verify_port(struct uart_port *port,
+                               struct serial_struct *ser)
+{
+       if (ser->type == PORT_UNKNOWN || ser->type == PORT_MAX3107)
+               return 0;
+
+       return -EINVAL;
+}
+
+/* Port stop TX function */
+static void max3107_stop_tx(struct uart_port *port)
+{
+       /* Do nothing */
+}
+
+/* Port break control function */
+static void max3107_break_ctl(struct uart_port *port, int break_state)
+{
+       /* We don't support break control, do nothing */
+}
+
+
+/* Port functions */
+static struct uart_ops max3107_ops = {
+       .tx_empty       = max3107_tx_empty,
+       .set_mctrl      = max3107_set_mctrl,
+       .get_mctrl      = max3107_get_mctrl,
+       .stop_tx        = max3107_stop_tx,
+       .start_tx       = max3107_start_tx,
+       .stop_rx        = max3107_stop_rx,
+       .enable_ms      = max3107_enable_ms,
+       .break_ctl      = max3107_break_ctl,
+       .startup        = max3107_startup,
+       .shutdown       = max3107_shutdown,
+       .set_termios    = max3107_set_termios,
+       .type           = max3107_type,
+       .release_port   = max3107_release_port,
+       .request_port   = max3107_request_port,
+       .config_port    = max3107_config_port,
+       .verify_port    = max3107_verify_port,
+};
+
+/* UART driver data */
+static struct uart_driver max3107_uart_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "ttyMAX",
+       .dev_name       = "ttyMAX",
+       .nr             = 1,
+};
+
+static int driver_registered = 0;
+
+
+
+/* 'Generic' platform data */
+static struct max3107_plat generic_plat_data = {
+       .loopback               = 0,
+       .ext_clk                = 1,
+       .hw_suspend             = max3107_hw_susp,
+       .polled_mode            = 0,
+       .poll_time              = 0,
+};
+
+
+/*******************************************************************/
+
+/**
+ *     max3107_probe           -       SPI bus probe entry point
+ *     @spi: the spi device
+ *
+ *     SPI wants us to probe this device and if appropriate claim it.
+ *     Perform any platform specific requirements and then initialise
+ *     the device.
+ */
+
+int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata)
+{
+       struct max3107_port *s;
+       u16 buf[2];     /* Buffer for SPI transfers */
+       int retval;
+
+       pr_info("enter max3107 probe\n");
+
+       /* Allocate port structure */
+       s = kzalloc(sizeof(*s), GFP_KERNEL);
+       if (!s) {
+               pr_err("Allocating port structure failed\n");
+               return -ENOMEM;
+       }
+
+       s->pdata = pdata;
+
+       /* SPI Rx buffer
+        * +2 for RX FIFO interrupt
+        * disabling and RX level query
+        */
+       s->rxbuf = kzalloc(sizeof(u16) * (MAX3107_RX_FIFO_SIZE+2), GFP_KERNEL);
+       if (!s->rxbuf) {
+               pr_err("Allocating RX buffer failed\n");
+               retval = -ENOMEM;
+               goto err_free4;
+       }
+       s->rxstr = kzalloc(sizeof(u8) * MAX3107_RX_FIFO_SIZE, GFP_KERNEL);
+       if (!s->rxstr) {
+               pr_err("Allocating RX buffer failed\n");
+               retval = -ENOMEM;
+               goto err_free3;
+       }
+       /* SPI Tx buffer
+        * SPI transfer buffer
+        * +3 for TX FIFO empty
+        * interrupt disabling and
+        * enabling and TX enabling
+        */
+       s->txbuf = kzalloc(sizeof(u16) * MAX3107_TX_FIFO_SIZE + 3, GFP_KERNEL);
+       if (!s->txbuf) {
+               pr_err("Allocating TX buffer failed\n");
+               retval = -ENOMEM;
+               goto err_free2;
+       }
+       /* Initialize shared data lock */
+       spin_lock_init(&s->data_lock);
+
+       /* SPI intializations */
+       dev_set_drvdata(&spi->dev, s);
+       spi->mode = SPI_MODE_0;
+       spi->dev.platform_data = pdata;
+       spi->bits_per_word = 16;
+       s->ext_clk = pdata->ext_clk;
+       s->loopback = pdata->loopback;
+       spi_setup(spi);
+       s->spi = spi;
+
+       /* Check REV ID to ensure we are talking to what we expect */
+       buf[0] = MAX3107_REVID_REG;
+       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
+               dev_err(&s->spi->dev, "SPI transfer for REVID read failed\n");
+               retval = -EIO;
+               goto err_free1;
+       }
+       if ((buf[0] & MAX3107_SPI_RX_DATA_MASK) != MAX3107_REVID1 &&
+               (buf[0] & MAX3107_SPI_RX_DATA_MASK) != MAX3107_REVID2) {
+               dev_err(&s->spi->dev, "REVID %x does not match\n",
+                               (buf[0] & MAX3107_SPI_RX_DATA_MASK));
+               retval = -ENODEV;
+               goto err_free1;
+       }
+
+       /* Disable all interrupts */
+       buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG | 0x0000);
+       buf[0] |= 0x0000;
+
+       /* Configure clock source */
+       buf[1] = (MAX3107_WRITE_BIT | MAX3107_CLKSRC_REG);
+       if (s->ext_clk) {
+               /* External clock */
+               buf[1] |= MAX3107_CLKSRC_EXTCLK_BIT;
+       }
+
+       /* PLL bypass ON */
+       buf[1] |= MAX3107_CLKSRC_PLLBYP_BIT;
+
+       /* Perform SPI transfer */
+       if (max3107_rw(s, (u8 *)buf, NULL, 4)) {
+               dev_err(&s->spi->dev, "SPI transfer for init failed\n");
+               retval = -EIO;
+               goto err_free1;
+       }
+
+       /* Register UART driver */
+       if (!driver_registered) {
+               retval = uart_register_driver(&max3107_uart_driver);
+               if (retval) {
+                       dev_err(&s->spi->dev, "Registering UART driver failed\n");
+                       goto err_free1;
+               }
+               driver_registered = 1;
+       }
+
+       /* Initialize UART port data */
+       s->port.fifosize = 128;
+       s->port.ops = &max3107_ops;
+       s->port.line = 0;
+       s->port.dev = &spi->dev;
+       s->port.uartclk = 9600;
+       s->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
+       s->port.irq = s->spi->irq;
+       s->port.type = PORT_MAX3107;
+
+       /* Add UART port */
+       retval = uart_add_one_port(&max3107_uart_driver, &s->port);
+       if (retval < 0) {
+               dev_err(&s->spi->dev, "Adding UART port failed\n");
+               goto err_free1;
+       }
+
+       if (pdata->configure) {
+               retval = pdata->configure(s);
+               if (retval < 0)
+                       goto err_free1;
+       }
+
+       /* Go to suspend mode */
+       if (pdata->hw_suspend)
+               pdata->hw_suspend(s, 1);
+
+       return 0;
+
+err_free1:
+       kfree(s->txbuf);
+err_free2:
+       kfree(s->rxstr);
+err_free3:
+       kfree(s->rxbuf);
+err_free4:
+       kfree(s);
+       return retval;
+}
+EXPORT_SYMBOL_GPL(max3107_probe);
+
+/* Driver remove function */
+int max3107_remove(struct spi_device *spi)
+{
+       struct max3107_port *s = dev_get_drvdata(&spi->dev);
+
+       pr_info("enter max3107 remove\n");
+
+       /* Remove port */
+       if (uart_remove_one_port(&max3107_uart_driver, &s->port))
+               dev_warn(&s->spi->dev, "Removing UART port failed\n");
+
+
+       /* Free TxRx buffer */
+       kfree(s->rxbuf);
+       kfree(s->rxstr);
+       kfree(s->txbuf);
+
+       /* Free port structure */
+       kfree(s);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(max3107_remove);
+
+/* Driver suspend function */
+int max3107_suspend(struct spi_device *spi, pm_message_t state)
+{
+#ifdef CONFIG_PM
+       struct max3107_port *s = dev_get_drvdata(&spi->dev);
+
+       pr_debug("enter suspend\n");
+
+       /* Suspend UART port */
+       uart_suspend_port(&max3107_uart_driver, &s->port);
+
+       /* Go to suspend mode */
+       if (s->pdata->hw_suspend)
+               s->pdata->hw_suspend(s, 1);
+#endif /* CONFIG_PM */
+       return 0;
+}
+EXPORT_SYMBOL_GPL(max3107_suspend);
+
+/* Driver resume function */
+int max3107_resume(struct spi_device *spi)
+{
+#ifdef CONFIG_PM
+       struct max3107_port *s = dev_get_drvdata(&spi->dev);
+
+       pr_debug("enter resume\n");
+
+       /* Resume from suspend */
+       if (s->pdata->hw_suspend)
+               s->pdata->hw_suspend(s, 0);
+
+       /* Resume UART port */
+       uart_resume_port(&max3107_uart_driver, &s->port);
+#endif /* CONFIG_PM */
+       return 0;
+}
+EXPORT_SYMBOL_GPL(max3107_resume);
+
+static int max3107_probe_generic(struct spi_device *spi)
+{
+       return max3107_probe(spi, &generic_plat_data);
+}
+
+/* Spi driver data */
+static struct spi_driver max3107_driver = {
+       .driver = {
+               .name           = "max3107",
+               .bus            = &spi_bus_type,
+               .owner          = THIS_MODULE,
+       },
+       .probe          = max3107_probe_generic,
+       .remove         = __devexit_p(max3107_remove),
+       .suspend        = max3107_suspend,
+       .resume         = max3107_resume,
+};
+
+/* Driver init function */
+static int __init max3107_init(void)
+{
+       pr_info("enter max3107 init\n");
+       return spi_register_driver(&max3107_driver);
+}
+
+/* Driver exit function */
+static void __exit max3107_exit(void)
+{
+       pr_info("enter max3107 exit\n");
+       /* Unregister UART driver */
+       if (driver_registered)
+               uart_unregister_driver(&max3107_uart_driver);
+       spi_unregister_driver(&max3107_driver);
+}
+
+module_init(max3107_init);
+module_exit(max3107_exit);
+
+MODULE_DESCRIPTION("MAX3107 driver");
+MODULE_AUTHOR("Aavamobile");
+MODULE_ALIAS("max3107-spi");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/max3107.h b/drivers/tty/serial/max3107.h
new file mode 100644 (file)
index 0000000..7ab6323
--- /dev/null
@@ -0,0 +1,441 @@
+/*
+ * max3107.h - spi uart protocol driver header for Maxim 3107
+ *
+ * Copyright (C) Aavamobile 2009
+ * Based on serial_max3100.h by Christian Pellegrin
+ *
+ * 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.
+ */
+
+#ifndef _MAX3107_H
+#define _MAX3107_H
+
+/* Serial error status definitions */
+#define MAX3107_PARITY_ERROR   1
+#define MAX3107_FRAME_ERROR    2
+#define MAX3107_OVERRUN_ERROR  4
+#define MAX3107_ALL_ERRORS     (MAX3107_PARITY_ERROR | \
+                                MAX3107_FRAME_ERROR | \
+                                MAX3107_OVERRUN_ERROR)
+
+/* GPIO definitions */
+#define MAX3107_GPIO_BASE      88
+#define MAX3107_GPIO_COUNT     4
+
+
+/* GPIO connected to chip's reset pin */
+#define MAX3107_RESET_GPIO     87
+
+
+/* Chip reset delay */
+#define MAX3107_RESET_DELAY    10
+
+/* Chip wakeup delay */
+#define MAX3107_WAKEUP_DELAY   50
+
+
+/* Sleep mode definitions */
+#define MAX3107_DISABLE_FORCED_SLEEP   0
+#define MAX3107_ENABLE_FORCED_SLEEP    1
+#define MAX3107_DISABLE_AUTOSLEEP      2
+#define MAX3107_ENABLE_AUTOSLEEP       3
+
+
+/* Definitions for register access with SPI transfers
+ *
+ * SPI transfer format:
+ *
+ * Master to slave bits xzzzzzzzyyyyyyyy
+ * Slave to master bits aaaaaaaabbbbbbbb
+ *
+ * where:
+ * x = 0 for reads, 1 for writes
+ * z = register address
+ * y = new register value if write, 0 if read
+ * a = unspecified
+ * b = register value if read, unspecified if write
+ */
+
+/* SPI speed */
+#define MAX3107_SPI_SPEED      (3125000 * 2)
+
+/* Write bit */
+#define MAX3107_WRITE_BIT      (1 << 15)
+
+/* SPI TX data mask */
+#define MAX3107_SPI_RX_DATA_MASK       (0x00ff)
+
+/* SPI RX data mask */
+#define MAX3107_SPI_TX_DATA_MASK       (0x00ff)
+
+/* Register access masks */
+#define MAX3107_RHR_REG                        (0x0000) /* RX FIFO */
+#define MAX3107_THR_REG                        (0x0000) /* TX FIFO */
+#define MAX3107_IRQEN_REG              (0x0100) /* IRQ enable */
+#define MAX3107_IRQSTS_REG             (0x0200) /* IRQ status */
+#define MAX3107_LSR_IRQEN_REG          (0x0300) /* LSR IRQ enable */
+#define MAX3107_LSR_IRQSTS_REG         (0x0400) /* LSR IRQ status */
+#define MAX3107_SPCHR_IRQEN_REG                (0x0500) /* Special char IRQ enable */
+#define MAX3107_SPCHR_IRQSTS_REG       (0x0600) /* Special char IRQ status */
+#define MAX3107_STS_IRQEN_REG          (0x0700) /* Status IRQ enable */
+#define MAX3107_STS_IRQSTS_REG         (0x0800) /* Status IRQ status */
+#define MAX3107_MODE1_REG              (0x0900) /* MODE1 */
+#define MAX3107_MODE2_REG              (0x0a00) /* MODE2 */
+#define MAX3107_LCR_REG                        (0x0b00) /* LCR */
+#define MAX3107_RXTO_REG               (0x0c00) /* RX timeout */
+#define MAX3107_HDPIXDELAY_REG         (0x0d00) /* Auto transceiver delays */
+#define MAX3107_IRDA_REG               (0x0e00) /* IRDA settings */
+#define MAX3107_FLOWLVL_REG            (0x0f00) /* Flow control levels */
+#define MAX3107_FIFOTRIGLVL_REG                (0x1000) /* FIFO IRQ trigger levels */
+#define MAX3107_TXFIFOLVL_REG          (0x1100) /* TX FIFO level */
+#define MAX3107_RXFIFOLVL_REG          (0x1200) /* RX FIFO level */
+#define MAX3107_FLOWCTRL_REG           (0x1300) /* Flow control */
+#define MAX3107_XON1_REG               (0x1400) /* XON1 character */
+#define MAX3107_XON2_REG               (0x1500) /* XON2 character */
+#define MAX3107_XOFF1_REG              (0x1600) /* XOFF1 character */
+#define MAX3107_XOFF2_REG              (0x1700) /* XOFF2 character */
+#define MAX3107_GPIOCFG_REG            (0x1800) /* GPIO config */
+#define MAX3107_GPIODATA_REG           (0x1900) /* GPIO data */
+#define MAX3107_PLLCFG_REG             (0x1a00) /* PLL config */
+#define MAX3107_BRGCFG_REG             (0x1b00) /* Baud rate generator conf */
+#define MAX3107_BRGDIVLSB_REG          (0x1c00) /* Baud rate divisor LSB */
+#define MAX3107_BRGDIVMSB_REG          (0x1d00) /* Baud rate divisor MSB */
+#define MAX3107_CLKSRC_REG             (0x1e00) /* Clock source */
+#define MAX3107_REVID_REG              (0x1f00) /* Revision identification */
+
+/* IRQ register bits */
+#define MAX3107_IRQ_LSR_BIT    (1 << 0) /* LSR interrupt */
+#define MAX3107_IRQ_SPCHR_BIT  (1 << 1) /* Special char interrupt */
+#define MAX3107_IRQ_STS_BIT    (1 << 2) /* Status interrupt */
+#define MAX3107_IRQ_RXFIFO_BIT (1 << 3) /* RX FIFO interrupt */
+#define MAX3107_IRQ_TXFIFO_BIT (1 << 4) /* TX FIFO interrupt */
+#define MAX3107_IRQ_TXEMPTY_BIT        (1 << 5) /* TX FIFO empty interrupt */
+#define MAX3107_IRQ_RXEMPTY_BIT        (1 << 6) /* RX FIFO empty interrupt */
+#define MAX3107_IRQ_CTS_BIT    (1 << 7) /* CTS interrupt */
+
+/* LSR register bits */
+#define MAX3107_LSR_RXTO_BIT   (1 << 0) /* RX timeout */
+#define MAX3107_LSR_RXOVR_BIT  (1 << 1) /* RX overrun */
+#define MAX3107_LSR_RXPAR_BIT  (1 << 2) /* RX parity error */
+#define MAX3107_LSR_FRERR_BIT  (1 << 3) /* Frame error */
+#define MAX3107_LSR_RXBRK_BIT  (1 << 4) /* RX break */
+#define MAX3107_LSR_RXNOISE_BIT        (1 << 5) /* RX noise */
+#define MAX3107_LSR_UNDEF6_BIT (1 << 6) /* Undefined/not used */
+#define MAX3107_LSR_CTS_BIT    (1 << 7) /* CTS pin state */
+
+/* Special character register bits */
+#define MAX3107_SPCHR_XON1_BIT         (1 << 0) /* XON1 character */
+#define MAX3107_SPCHR_XON2_BIT         (1 << 1) /* XON2 character */
+#define MAX3107_SPCHR_XOFF1_BIT                (1 << 2) /* XOFF1 character */
+#define MAX3107_SPCHR_XOFF2_BIT                (1 << 3) /* XOFF2 character */
+#define MAX3107_SPCHR_BREAK_BIT                (1 << 4) /* RX break */
+#define MAX3107_SPCHR_MULTIDROP_BIT    (1 << 5) /* 9-bit multidrop addr char */
+#define MAX3107_SPCHR_UNDEF6_BIT       (1 << 6) /* Undefined/not used */
+#define MAX3107_SPCHR_UNDEF7_BIT       (1 << 7) /* Undefined/not used */
+
+/* Status register bits */
+#define MAX3107_STS_GPIO0_BIT          (1 << 0) /* GPIO 0 interrupt */
+#define MAX3107_STS_GPIO1_BIT          (1 << 1) /* GPIO 1 interrupt */
+#define MAX3107_STS_GPIO2_BIT          (1 << 2) /* GPIO 2 interrupt */
+#define MAX3107_STS_GPIO3_BIT          (1 << 3) /* GPIO 3 interrupt */
+#define MAX3107_STS_UNDEF4_BIT         (1 << 4) /* Undefined/not used */
+#define MAX3107_STS_CLKREADY_BIT       (1 << 5) /* Clock ready */
+#define MAX3107_STS_SLEEP_BIT          (1 << 6) /* Sleep interrupt */
+#define MAX3107_STS_UNDEF7_BIT         (1 << 7) /* Undefined/not used */
+
+/* MODE1 register bits */
+#define MAX3107_MODE1_RXDIS_BIT                (1 << 0) /* RX disable */
+#define MAX3107_MODE1_TXDIS_BIT                (1 << 1) /* TX disable */
+#define MAX3107_MODE1_TXHIZ_BIT                (1 << 2) /* TX pin three-state */
+#define MAX3107_MODE1_RTSHIZ_BIT       (1 << 3) /* RTS pin three-state */
+#define MAX3107_MODE1_TRNSCVCTRL_BIT   (1 << 4) /* Transceiver ctrl enable */
+#define MAX3107_MODE1_FORCESLEEP_BIT   (1 << 5) /* Force sleep mode */
+#define MAX3107_MODE1_AUTOSLEEP_BIT    (1 << 6) /* Auto sleep enable */
+#define MAX3107_MODE1_IRQSEL_BIT       (1 << 7) /* IRQ pin enable */
+
+/* MODE2 register bits */
+#define MAX3107_MODE2_RST_BIT          (1 << 0) /* Chip reset */
+#define MAX3107_MODE2_FIFORST_BIT      (1 << 1) /* FIFO reset */
+#define MAX3107_MODE2_RXTRIGINV_BIT    (1 << 2) /* RX FIFO INT invert */
+#define MAX3107_MODE2_RXEMPTINV_BIT    (1 << 3) /* RX FIFO empty INT invert */
+#define MAX3107_MODE2_SPCHR_BIT                (1 << 4) /* Special chr detect enable */
+#define MAX3107_MODE2_LOOPBACK_BIT     (1 << 5) /* Internal loopback enable */
+#define MAX3107_MODE2_MULTIDROP_BIT    (1 << 6) /* 9-bit multidrop enable */
+#define MAX3107_MODE2_ECHOSUPR_BIT     (1 << 7) /* ECHO suppression enable */
+
+/* LCR register bits */
+#define MAX3107_LCR_LENGTH0_BIT                (1 << 0) /* Word length bit 0 */
+#define MAX3107_LCR_LENGTH1_BIT                (1 << 1) /* Word length bit 1
+                                                 *
+                                                 * Word length bits table:
+                                                 * 00 -> 5 bit words
+                                                 * 01 -> 6 bit words
+                                                 * 10 -> 7 bit words
+                                                 * 11 -> 8 bit words
+                                                 */
+#define MAX3107_LCR_STOPLEN_BIT                (1 << 2) /* STOP length bit
+                                                 *
+                                                 * STOP length bit table:
+                                                 * 0 -> 1 stop bit
+                                                 * 1 -> 1-1.5 stop bits if
+                                                 *      word length is 5,
+                                                 *      2 stop bits otherwise
+                                                 */
+#define MAX3107_LCR_PARITY_BIT         (1 << 3) /* Parity bit enable */
+#define MAX3107_LCR_EVENPARITY_BIT     (1 << 4) /* Even parity bit enable */
+#define MAX3107_LCR_FORCEPARITY_BIT    (1 << 5) /* 9-bit multidrop parity */
+#define MAX3107_LCR_TXBREAK_BIT                (1 << 6) /* TX break enable */
+#define MAX3107_LCR_RTS_BIT            (1 << 7) /* RTS pin control */
+#define MAX3107_LCR_WORD_LEN_5         (0x0000)
+#define MAX3107_LCR_WORD_LEN_6         (0x0001)
+#define MAX3107_LCR_WORD_LEN_7         (0x0002)
+#define MAX3107_LCR_WORD_LEN_8         (0x0003)
+
+
+/* IRDA register bits */
+#define MAX3107_IRDA_IRDAEN_BIT                (1 << 0) /* IRDA mode enable */
+#define MAX3107_IRDA_SIR_BIT           (1 << 1) /* SIR mode enable */
+#define MAX3107_IRDA_SHORTIR_BIT       (1 << 2) /* Short SIR mode enable */
+#define MAX3107_IRDA_MIR_BIT           (1 << 3) /* MIR mode enable */
+#define MAX3107_IRDA_RXINV_BIT         (1 << 4) /* RX logic inversion enable */
+#define MAX3107_IRDA_TXINV_BIT         (1 << 5) /* TX logic inversion enable */
+#define MAX3107_IRDA_UNDEF6_BIT                (1 << 6) /* Undefined/not used */
+#define MAX3107_IRDA_UNDEF7_BIT                (1 << 7) /* Undefined/not used */
+
+/* Flow control trigger level register masks */
+#define MAX3107_FLOWLVL_HALT_MASK      (0x000f) /* Flow control halt level */
+#define MAX3107_FLOWLVL_RES_MASK       (0x00f0) /* Flow control resume level */
+#define MAX3107_FLOWLVL_HALT(words)    ((words/8) & 0x000f)
+#define MAX3107_FLOWLVL_RES(words)     (((words/8) & 0x000f) << 4)
+
+/* FIFO interrupt trigger level register masks */
+#define MAX3107_FIFOTRIGLVL_TX_MASK    (0x000f) /* TX FIFO trigger level */
+#define MAX3107_FIFOTRIGLVL_RX_MASK    (0x00f0) /* RX FIFO trigger level */
+#define MAX3107_FIFOTRIGLVL_TX(words)  ((words/8) & 0x000f)
+#define MAX3107_FIFOTRIGLVL_RX(words)  (((words/8) & 0x000f) << 4)
+
+/* Flow control register bits */
+#define MAX3107_FLOWCTRL_AUTORTS_BIT   (1 << 0) /* Auto RTS flow ctrl enable */
+#define MAX3107_FLOWCTRL_AUTOCTS_BIT   (1 << 1) /* Auto CTS flow ctrl enable */
+#define MAX3107_FLOWCTRL_GPIADDR_BIT   (1 << 2) /* Enables that GPIO inputs
+                                                 * are used in conjunction with
+                                                 * XOFF2 for definition of
+                                                 * special character */
+#define MAX3107_FLOWCTRL_SWFLOWEN_BIT  (1 << 3) /* Auto SW flow ctrl enable */
+#define MAX3107_FLOWCTRL_SWFLOW0_BIT   (1 << 4) /* SWFLOW bit 0 */
+#define MAX3107_FLOWCTRL_SWFLOW1_BIT   (1 << 5) /* SWFLOW bit 1
+                                                 *
+                                                 * SWFLOW bits 1 & 0 table:
+                                                 * 00 -> no transmitter flow
+                                                 *       control
+                                                 * 01 -> receiver compares
+                                                 *       XON2 and XOFF2
+                                                 *       and controls
+                                                 *       transmitter
+                                                 * 10 -> receiver compares
+                                                 *       XON1 and XOFF1
+                                                 *       and controls
+                                                 *       transmitter
+                                                 * 11 -> receiver compares
+                                                 *       XON1, XON2, XOFF1 and
+                                                 *       XOFF2 and controls
+                                                 *       transmitter
+                                                 */
+#define MAX3107_FLOWCTRL_SWFLOW2_BIT   (1 << 6) /* SWFLOW bit 2 */
+#define MAX3107_FLOWCTRL_SWFLOW3_BIT   (1 << 7) /* SWFLOW bit 3
+                                                 *
+                                                 * SWFLOW bits 3 & 2 table:
+                                                 * 00 -> no received flow
+                                                 *       control
+                                                 * 01 -> transmitter generates
+                                                 *       XON2 and XOFF2
+                                                 * 10 -> transmitter generates
+                                                 *       XON1 and XOFF1
+                                                 * 11 -> transmitter generates
+                                                 *       XON1, XON2, XOFF1 and
+                                                 *       XOFF2
+                                                 */
+
+/* GPIO configuration register bits */
+#define MAX3107_GPIOCFG_GP0OUT_BIT     (1 << 0) /* GPIO 0 output enable */
+#define MAX3107_GPIOCFG_GP1OUT_BIT     (1 << 1) /* GPIO 1 output enable */
+#define MAX3107_GPIOCFG_GP2OUT_BIT     (1 << 2) /* GPIO 2 output enable */
+#define MAX3107_GPIOCFG_GP3OUT_BIT     (1 << 3) /* GPIO 3 output enable */
+#define MAX3107_GPIOCFG_GP0OD_BIT      (1 << 4) /* GPIO 0 open-drain enable */
+#define MAX3107_GPIOCFG_GP1OD_BIT      (1 << 5) /* GPIO 1 open-drain enable */
+#define MAX3107_GPIOCFG_GP2OD_BIT      (1 << 6) /* GPIO 2 open-drain enable */
+#define MAX3107_GPIOCFG_GP3OD_BIT      (1 << 7) /* GPIO 3 open-drain enable */
+
+/* GPIO DATA register bits */
+#define MAX3107_GPIODATA_GP0OUT_BIT    (1 << 0) /* GPIO 0 output value */
+#define MAX3107_GPIODATA_GP1OUT_BIT    (1 << 1) /* GPIO 1 output value */
+#define MAX3107_GPIODATA_GP2OUT_BIT    (1 << 2) /* GPIO 2 output value */
+#define MAX3107_GPIODATA_GP3OUT_BIT    (1 << 3) /* GPIO 3 output value */
+#define MAX3107_GPIODATA_GP0IN_BIT     (1 << 4) /* GPIO 0 input value */
+#define MAX3107_GPIODATA_GP1IN_BIT     (1 << 5) /* GPIO 1 input value */
+#define MAX3107_GPIODATA_GP2IN_BIT     (1 << 6) /* GPIO 2 input value */
+#define MAX3107_GPIODATA_GP3IN_BIT     (1 << 7) /* GPIO 3 input value */
+
+/* PLL configuration register masks */
+#define MAX3107_PLLCFG_PREDIV_MASK     (0x003f) /* PLL predivision value */
+#define MAX3107_PLLCFG_PLLFACTOR_MASK  (0x00c0) /* PLL multiplication factor */
+
+/* Baud rate generator configuration register masks and bits */
+#define MAX3107_BRGCFG_FRACT_MASK      (0x000f) /* Fractional portion of
+                                                 * Baud rate generator divisor
+                                                 */
+#define MAX3107_BRGCFG_2XMODE_BIT      (1 << 4) /* Double baud rate */
+#define MAX3107_BRGCFG_4XMODE_BIT      (1 << 5) /* Quadruple baud rate */
+#define MAX3107_BRGCFG_UNDEF6_BIT      (1 << 6) /* Undefined/not used */
+#define MAX3107_BRGCFG_UNDEF7_BIT      (1 << 7) /* Undefined/not used */
+
+/* Clock source register bits */
+#define MAX3107_CLKSRC_INTOSC_BIT      (1 << 0) /* Internal osc enable */
+#define MAX3107_CLKSRC_CRYST_BIT       (1 << 1) /* Crystal osc enable */
+#define MAX3107_CLKSRC_PLL_BIT         (1 << 2) /* PLL enable */
+#define MAX3107_CLKSRC_PLLBYP_BIT      (1 << 3) /* PLL bypass */
+#define MAX3107_CLKSRC_EXTCLK_BIT      (1 << 4) /* External clock enable */
+#define MAX3107_CLKSRC_UNDEF5_BIT      (1 << 5) /* Undefined/not used */
+#define MAX3107_CLKSRC_UNDEF6_BIT      (1 << 6) /* Undefined/not used */
+#define MAX3107_CLKSRC_CLK2RTS_BIT     (1 << 7) /* Baud clk to RTS pin */
+
+
+/* HW definitions */
+#define MAX3107_RX_FIFO_SIZE   128
+#define MAX3107_TX_FIFO_SIZE   128
+#define MAX3107_REVID1         0x00a0
+#define MAX3107_REVID2         0x00a1
+
+
+/* Baud rate generator configuration values for external clock 13MHz */
+#define MAX3107_BRG13_B300     (0x0A9400 | 0x05)
+#define MAX3107_BRG13_B600     (0x054A00 | 0x03)
+#define MAX3107_BRG13_B1200    (0x02A500 | 0x01)
+#define MAX3107_BRG13_B2400    (0x015200 | 0x09)
+#define MAX3107_BRG13_B4800    (0x00A900 | 0x04)
+#define MAX3107_BRG13_B9600    (0x005400 | 0x0A)
+#define MAX3107_BRG13_B19200   (0x002A00 | 0x05)
+#define MAX3107_BRG13_B38400   (0x001500 | 0x03)
+#define MAX3107_BRG13_B57600   (0x000E00 | 0x02)
+#define MAX3107_BRG13_B115200  (0x000700 | 0x01)
+#define MAX3107_BRG13_B230400  (0x000300 | 0x08)
+#define MAX3107_BRG13_B460800  (0x000100 | 0x0c)
+#define MAX3107_BRG13_B921600  (0x000100 | 0x1c)
+
+/* Baud rate generator configuration values for external clock 26MHz */
+#define MAX3107_BRG26_B300     (0x152800 | 0x0A)
+#define MAX3107_BRG26_B600     (0x0A9400 | 0x05)
+#define MAX3107_BRG26_B1200    (0x054A00 | 0x03)
+#define MAX3107_BRG26_B2400    (0x02A500 | 0x01)
+#define MAX3107_BRG26_B4800    (0x015200 | 0x09)
+#define MAX3107_BRG26_B9600    (0x00A900 | 0x04)
+#define MAX3107_BRG26_B19200   (0x005400 | 0x0A)
+#define MAX3107_BRG26_B38400   (0x002A00 | 0x05)
+#define MAX3107_BRG26_B57600   (0x001C00 | 0x03)
+#define MAX3107_BRG26_B115200  (0x000E00 | 0x02)
+#define MAX3107_BRG26_B230400  (0x000700 | 0x01)
+#define MAX3107_BRG26_B460800  (0x000300 | 0x08)
+#define MAX3107_BRG26_B921600  (0x000100 | 0x0C)
+
+/* Baud rate generator configuration values for internal clock */
+#define MAX3107_BRG13_IB300    (0x008000 | 0x00)
+#define MAX3107_BRG13_IB600    (0x004000 | 0x00)
+#define MAX3107_BRG13_IB1200   (0x002000 | 0x00)
+#define MAX3107_BRG13_IB2400   (0x001000 | 0x00)
+#define MAX3107_BRG13_IB4800   (0x000800 | 0x00)
+#define MAX3107_BRG13_IB9600   (0x000400 | 0x00)
+#define MAX3107_BRG13_IB19200  (0x000200 | 0x00)
+#define MAX3107_BRG13_IB38400  (0x000100 | 0x00)
+#define MAX3107_BRG13_IB57600  (0x000000 | 0x0B)
+#define MAX3107_BRG13_IB115200 (0x000000 | 0x05)
+#define MAX3107_BRG13_IB230400 (0x000000 | 0x03)
+#define MAX3107_BRG13_IB460800 (0x000000 | 0x00)
+#define MAX3107_BRG13_IB921600 (0x000000 | 0x00)
+
+
+struct baud_table {
+       int baud;
+       u32 new_brg;
+};
+
+struct max3107_port {
+       /* UART port structure */
+       struct uart_port port;
+
+       /* SPI device structure */
+       struct spi_device *spi;
+
+#if defined(CONFIG_GPIOLIB)
+       /* GPIO chip stucture */
+       struct gpio_chip chip;
+#endif
+
+       /* Workqueue that does all the magic */
+       struct workqueue_struct *workqueue;
+       struct work_struct work;
+
+       /* Lock for shared data */
+       spinlock_t data_lock;
+
+       /* Device configuration */
+       int ext_clk;            /* 1 if external clock used */
+       int loopback;           /* Current loopback mode state */
+       int baud;                       /* Current baud rate */
+
+       /* State flags */
+       int suspended;          /* Indicates suspend mode */
+       int tx_fifo_empty;      /* Flag for TX FIFO state */
+       int rx_enabled;         /* Flag for receiver state */
+       int tx_enabled;         /* Flag for transmitter state */
+
+       u16 irqen_reg;          /* Current IRQ enable register value */
+       /* Shared data */
+       u16 mode1_reg;          /* Current mode1 register value*/
+       int mode1_commit;       /* Flag for setting new mode1 register value */
+       u16 lcr_reg;            /* Current LCR register value */
+       int lcr_commit;         /* Flag for setting new LCR register value */
+       u32 brg_cfg;            /* Current Baud rate generator config  */
+       int brg_commit;         /* Flag for setting new baud rate generator
+                                * config
+                                */
+       struct baud_table *baud_tbl;
+       int handle_irq;         /* Indicates that IRQ should be handled */
+
+       /* Rx buffer and str*/
+       u16 *rxbuf;
+       u8  *rxstr;
+       /* Tx buffer*/
+       u16 *txbuf;
+
+       struct max3107_plat *pdata;     /* Platform data */
+};
+
+/* Platform data structure */
+struct max3107_plat {
+       /* Loopback mode enable */
+       int loopback;
+       /* External clock enable */
+       int ext_clk;
+       /* Called during the register initialisation */
+       void (*init)(struct max3107_port *s);
+       /* Called when the port is found and configured */
+       int (*configure)(struct max3107_port *s);
+       /* HW suspend function */
+       void (*hw_suspend) (struct max3107_port *s, int suspend);
+       /* Polling mode enable */
+       int polled_mode;
+       /* Polling period if polling mode enabled */
+       int poll_time;
+};
+
+extern int max3107_rw(struct max3107_port *s, u8 *tx, u8 *rx, int len);
+extern void max3107_hw_susp(struct max3107_port *s, int suspend);
+extern int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata);
+extern int max3107_remove(struct spi_device *spi);
+extern int max3107_suspend(struct spi_device *spi, pm_message_t state);
+extern int max3107_resume(struct spi_device *spi);
+
+#endif /* _LINUX_SERIAL_MAX3107_H */
diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c
new file mode 100644 (file)
index 0000000..3394b7c
--- /dev/null
@@ -0,0 +1,662 @@
+/****************************************************************************/
+
+/*
+ *     mcf.c -- Freescale ColdFire UART driver
+ *
+ *     (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
+ *
+ * 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.
+ */
+
+/****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+#include <asm/nettel.h>
+
+/****************************************************************************/
+
+/*
+ *     Some boards implement the DTR/DCD lines using GPIO lines, most
+ *     don't. Dummy out the access macros for those that don't. Those
+ *     that do should define these macros somewhere in there board
+ *     specific inlude files.
+ */
+#if !defined(mcf_getppdcd)
+#define        mcf_getppdcd(p)         (1)
+#endif
+#if !defined(mcf_getppdtr)
+#define        mcf_getppdtr(p)         (1)
+#endif
+#if !defined(mcf_setppdtr)
+#define        mcf_setppdtr(p, v)      do { } while (0)
+#endif
+
+/****************************************************************************/
+
+/*
+ *     Local per-uart structure.
+ */
+struct mcf_uart {
+       struct uart_port        port;
+       unsigned int            sigs;           /* Local copy of line sigs */
+       unsigned char           imr;            /* Local IMR mirror */
+};
+
+/****************************************************************************/
+
+static unsigned int mcf_tx_empty(struct uart_port *port)
+{
+       return (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXEMPTY) ?
+               TIOCSER_TEMT : 0;
+}
+
+/****************************************************************************/
+
+static unsigned int mcf_get_mctrl(struct uart_port *port)
+{
+       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
+       unsigned int sigs;
+
+       sigs = (readb(port->membase + MCFUART_UIPR) & MCFUART_UIPR_CTS) ?
+               0 : TIOCM_CTS;
+       sigs |= (pp->sigs & TIOCM_RTS);
+       sigs |= (mcf_getppdcd(port->line) ? TIOCM_CD : 0);
+       sigs |= (mcf_getppdtr(port->line) ? TIOCM_DTR : 0);
+
+       return sigs;
+}
+
+/****************************************************************************/
+
+static void mcf_set_mctrl(struct uart_port *port, unsigned int sigs)
+{
+       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
+
+       pp->sigs = sigs;
+       mcf_setppdtr(port->line, (sigs & TIOCM_DTR));
+       if (sigs & TIOCM_RTS)
+               writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP1);
+       else
+               writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP0);
+}
+
+/****************************************************************************/
+
+static void mcf_start_tx(struct uart_port *port)
+{
+       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
+
+       pp->imr |= MCFUART_UIR_TXREADY;
+       writeb(pp->imr, port->membase + MCFUART_UIMR);
+}
+
+/****************************************************************************/
+
+static void mcf_stop_tx(struct uart_port *port)
+{
+       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
+
+       pp->imr &= ~MCFUART_UIR_TXREADY;
+       writeb(pp->imr, port->membase + MCFUART_UIMR);
+}
+
+/****************************************************************************/
+
+static void mcf_stop_rx(struct uart_port *port)
+{
+       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
+
+       pp->imr &= ~MCFUART_UIR_RXREADY;
+       writeb(pp->imr, port->membase + MCFUART_UIMR);
+}
+
+/****************************************************************************/
+
+static void mcf_break_ctl(struct uart_port *port, int break_state)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       if (break_state == -1)
+               writeb(MCFUART_UCR_CMDBREAKSTART, port->membase + MCFUART_UCR);
+       else
+               writeb(MCFUART_UCR_CMDBREAKSTOP, port->membase + MCFUART_UCR);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/****************************************************************************/
+
+static void mcf_enable_ms(struct uart_port *port)
+{
+}
+
+/****************************************************************************/
+
+static int mcf_startup(struct uart_port *port)
+{
+       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Reset UART, get it into known state... */
+       writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
+       writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
+
+       /* Enable the UART transmitter and receiver */
+       writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE,
+               port->membase + MCFUART_UCR);
+
+       /* Enable RX interrupts now */
+       pp->imr = MCFUART_UIR_RXREADY;
+       writeb(pp->imr, port->membase + MCFUART_UIMR);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       return 0;
+}
+
+/****************************************************************************/
+
+static void mcf_shutdown(struct uart_port *port)
+{
+       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Disable all interrupts now */
+       pp->imr = 0;
+       writeb(pp->imr, port->membase + MCFUART_UIMR);
+
+       /* Disable UART transmitter and receiver */
+       writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
+       writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/****************************************************************************/
+
+static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
+       struct ktermios *old)
+{
+       unsigned long flags;
+       unsigned int baud, baudclk;
+#if defined(CONFIG_M5272)
+       unsigned int baudfr;
+#endif
+       unsigned char mr1, mr2;
+
+       baud = uart_get_baud_rate(port, termios, old, 0, 230400);
+#if defined(CONFIG_M5272)
+       baudclk = (MCF_BUSCLK / baud) / 32;
+       baudfr = (((MCF_BUSCLK / baud) + 1) / 2) % 16;
+#else
+       baudclk = ((MCF_BUSCLK / baud) + 16) / 32;
+#endif
+
+       mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR;
+       mr2 = 0;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5: mr1 |= MCFUART_MR1_CS5; break;
+       case CS6: mr1 |= MCFUART_MR1_CS6; break;
+       case CS7: mr1 |= MCFUART_MR1_CS7; break;
+       case CS8:
+       default:  mr1 |= MCFUART_MR1_CS8; break;
+       }
+
+       if (termios->c_cflag & PARENB) {
+               if (termios->c_cflag & CMSPAR) {
+                       if (termios->c_cflag & PARODD)
+                               mr1 |= MCFUART_MR1_PARITYMARK;
+                       else
+                               mr1 |= MCFUART_MR1_PARITYSPACE;
+               } else {
+                       if (termios->c_cflag & PARODD)
+                               mr1 |= MCFUART_MR1_PARITYODD;
+                       else
+                               mr1 |= MCFUART_MR1_PARITYEVEN;
+               }
+       } else {
+               mr1 |= MCFUART_MR1_PARITYNONE;
+       }
+
+       if (termios->c_cflag & CSTOPB)
+               mr2 |= MCFUART_MR2_STOP2;
+       else
+               mr2 |= MCFUART_MR2_STOP1;
+
+       if (termios->c_cflag & CRTSCTS) {
+               mr1 |= MCFUART_MR1_RXRTS;
+               mr2 |= MCFUART_MR2_TXCTS;
+       }
+
+       spin_lock_irqsave(&port->lock, flags);
+       uart_update_timeout(port, termios->c_cflag, baud);
+       writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
+       writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
+       writeb(MCFUART_UCR_CMDRESETMRPTR, port->membase + MCFUART_UCR);
+       writeb(mr1, port->membase + MCFUART_UMR);
+       writeb(mr2, port->membase + MCFUART_UMR);
+       writeb((baudclk & 0xff00) >> 8, port->membase + MCFUART_UBG1);
+       writeb((baudclk & 0xff), port->membase + MCFUART_UBG2);
+#if defined(CONFIG_M5272)
+       writeb((baudfr & 0x0f), port->membase + MCFUART_UFPD);
+#endif
+       writeb(MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER,
+               port->membase + MCFUART_UCSR);
+       writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE,
+               port->membase + MCFUART_UCR);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/****************************************************************************/
+
+static void mcf_rx_chars(struct mcf_uart *pp)
+{
+       struct uart_port *port = &pp->port;
+       unsigned char status, ch, flag;
+
+       while ((status = readb(port->membase + MCFUART_USR)) & MCFUART_USR_RXREADY) {
+               ch = readb(port->membase + MCFUART_URB);
+               flag = TTY_NORMAL;
+               port->icount.rx++;
+
+               if (status & MCFUART_USR_RXERR) {
+                       writeb(MCFUART_UCR_CMDRESETERR,
+                               port->membase + MCFUART_UCR);
+
+                       if (status & MCFUART_USR_RXBREAK) {
+                               port->icount.brk++;
+                               if (uart_handle_break(port))
+                                       continue;
+                       } else if (status & MCFUART_USR_RXPARITY) {
+                               port->icount.parity++;
+                       } else if (status & MCFUART_USR_RXOVERRUN) {
+                               port->icount.overrun++;
+                       } else if (status & MCFUART_USR_RXFRAMING) {
+                               port->icount.frame++;
+                       }
+
+                       status &= port->read_status_mask;
+
+                       if (status & MCFUART_USR_RXBREAK)
+                               flag = TTY_BREAK;
+                       else if (status & MCFUART_USR_RXPARITY)
+                               flag = TTY_PARITY;
+                       else if (status & MCFUART_USR_RXFRAMING)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(port, ch))
+                       continue;
+               uart_insert_char(port, status, MCFUART_USR_RXOVERRUN, ch, flag);
+       }
+
+       tty_flip_buffer_push(port->state->port.tty);
+}
+
+/****************************************************************************/
+
+static void mcf_tx_chars(struct mcf_uart *pp)
+{
+       struct uart_port *port = &pp->port;
+       struct circ_buf *xmit = &port->state->xmit;
+
+       if (port->x_char) {
+               /* Send special char - probably flow control */
+               writeb(port->x_char, port->membase + MCFUART_UTB);
+               port->x_char = 0;
+               port->icount.tx++;
+               return;
+       }
+
+       while (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) {
+               if (xmit->head == xmit->tail)
+                       break;
+               writeb(xmit->buf[xmit->tail], port->membase + MCFUART_UTB);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1);
+               port->icount.tx++;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (xmit->head == xmit->tail) {
+               pp->imr &= ~MCFUART_UIR_TXREADY;
+               writeb(pp->imr, port->membase + MCFUART_UIMR);
+       }
+}
+
+/****************************************************************************/
+
+static irqreturn_t mcf_interrupt(int irq, void *data)
+{
+       struct uart_port *port = data;
+       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
+       unsigned int isr;
+       irqreturn_t ret = IRQ_NONE;
+
+       isr = readb(port->membase + MCFUART_UISR) & pp->imr;
+
+       spin_lock(&port->lock);
+       if (isr & MCFUART_UIR_RXREADY) {
+               mcf_rx_chars(pp);
+               ret = IRQ_HANDLED;
+       }
+       if (isr & MCFUART_UIR_TXREADY) {
+               mcf_tx_chars(pp);
+               ret = IRQ_HANDLED;
+       }
+       spin_unlock(&port->lock);
+
+       return ret;
+}
+
+/****************************************************************************/
+
+static void mcf_config_port(struct uart_port *port, int flags)
+{
+       port->type = PORT_MCF;
+       port->fifosize = MCFUART_TXFIFOSIZE;
+
+       /* Clear mask, so no surprise interrupts. */
+       writeb(0, port->membase + MCFUART_UIMR);
+
+       if (request_irq(port->irq, mcf_interrupt, IRQF_DISABLED, "UART", port))
+               printk(KERN_ERR "MCF: unable to attach ColdFire UART %d "
+                       "interrupt vector=%d\n", port->line, port->irq);
+}
+
+/****************************************************************************/
+
+static const char *mcf_type(struct uart_port *port)
+{
+       return (port->type == PORT_MCF) ? "ColdFire UART" : NULL;
+}
+
+/****************************************************************************/
+
+static int mcf_request_port(struct uart_port *port)
+{
+       /* UARTs always present */
+       return 0;
+}
+
+/****************************************************************************/
+
+static void mcf_release_port(struct uart_port *port)
+{
+       /* Nothing to release... */
+}
+
+/****************************************************************************/
+
+static int mcf_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_MCF))
+               return -EINVAL;
+       return 0;
+}
+
+/****************************************************************************/
+
+/*
+ *     Define the basic serial functions we support.
+ */
+static const struct uart_ops mcf_uart_ops = {
+       .tx_empty       = mcf_tx_empty,
+       .get_mctrl      = mcf_get_mctrl,
+       .set_mctrl      = mcf_set_mctrl,
+       .start_tx       = mcf_start_tx,
+       .stop_tx        = mcf_stop_tx,
+       .stop_rx        = mcf_stop_rx,
+       .enable_ms      = mcf_enable_ms,
+       .break_ctl      = mcf_break_ctl,
+       .startup        = mcf_startup,
+       .shutdown       = mcf_shutdown,
+       .set_termios    = mcf_set_termios,
+       .type           = mcf_type,
+       .request_port   = mcf_request_port,
+       .release_port   = mcf_release_port,
+       .config_port    = mcf_config_port,
+       .verify_port    = mcf_verify_port,
+};
+
+static struct mcf_uart mcf_ports[4];
+
+#define        MCF_MAXPORTS    ARRAY_SIZE(mcf_ports)
+
+/****************************************************************************/
+#if defined(CONFIG_SERIAL_MCF_CONSOLE)
+/****************************************************************************/
+
+int __init early_mcf_setup(struct mcf_platform_uart *platp)
+{
+       struct uart_port *port;
+       int i;
+
+       for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) {
+               port = &mcf_ports[i].port;
+
+               port->line = i;
+               port->type = PORT_MCF;
+               port->mapbase = platp[i].mapbase;
+               port->membase = (platp[i].membase) ? platp[i].membase :
+                       (unsigned char __iomem *) port->mapbase;
+               port->iotype = SERIAL_IO_MEM;
+               port->irq = platp[i].irq;
+               port->uartclk = MCF_BUSCLK;
+               port->flags = ASYNC_BOOT_AUTOCONF;
+               port->ops = &mcf_uart_ops;
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+
+static void mcf_console_putc(struct console *co, const char c)
+{
+       struct uart_port *port = &(mcf_ports + co->index)->port;
+       int i;
+
+       for (i = 0; (i < 0x10000); i++) {
+               if (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY)
+                       break;
+       }
+       writeb(c, port->membase + MCFUART_UTB);
+       for (i = 0; (i < 0x10000); i++) {
+               if (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY)
+                       break;
+       }
+}
+
+/****************************************************************************/
+
+static void mcf_console_write(struct console *co, const char *s, unsigned int count)
+{
+       for (; (count); count--, s++) {
+               mcf_console_putc(co, *s);
+               if (*s == '\n')
+                       mcf_console_putc(co, '\r');
+       }
+}
+
+/****************************************************************************/
+
+static int __init mcf_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       int baud = CONFIG_SERIAL_MCF_BAUDRATE;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if ((co->index < 0) || (co->index >= MCF_MAXPORTS))
+               co->index = 0;
+       port = &mcf_ports[co->index].port;
+       if (port->membase == 0)
+               return -ENODEV;
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+/****************************************************************************/
+
+static struct uart_driver mcf_driver;
+
+static struct console mcf_console = {
+       .name           = "ttyS",
+       .write          = mcf_console_write,
+       .device         = uart_console_device,
+       .setup          = mcf_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &mcf_driver,
+};
+
+static int __init mcf_console_init(void)
+{
+       register_console(&mcf_console);
+       return 0;
+}
+
+console_initcall(mcf_console_init);
+
+#define        MCF_CONSOLE     &mcf_console
+
+/****************************************************************************/
+#else
+/****************************************************************************/
+
+#define        MCF_CONSOLE     NULL
+
+/****************************************************************************/
+#endif /* CONFIG_MCF_CONSOLE */
+/****************************************************************************/
+
+/*
+ *     Define the mcf UART driver structure.
+ */
+static struct uart_driver mcf_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "mcf",
+       .dev_name       = "ttyS",
+       .major          = TTY_MAJOR,
+       .minor          = 64,
+       .nr             = MCF_MAXPORTS,
+       .cons           = MCF_CONSOLE,
+};
+
+/****************************************************************************/
+
+static int __devinit mcf_probe(struct platform_device *pdev)
+{
+       struct mcf_platform_uart *platp = pdev->dev.platform_data;
+       struct uart_port *port;
+       int i;
+
+       for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) {
+               port = &mcf_ports[i].port;
+
+               port->line = i;
+               port->type = PORT_MCF;
+               port->mapbase = platp[i].mapbase;
+               port->membase = (platp[i].membase) ? platp[i].membase :
+                       (unsigned char __iomem *) platp[i].mapbase;
+               port->iotype = SERIAL_IO_MEM;
+               port->irq = platp[i].irq;
+               port->uartclk = MCF_BUSCLK;
+               port->ops = &mcf_uart_ops;
+               port->flags = ASYNC_BOOT_AUTOCONF;
+
+               uart_add_one_port(&mcf_driver, port);
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+
+static int __devexit mcf_remove(struct platform_device *pdev)
+{
+       struct uart_port *port;
+       int i;
+
+       for (i = 0; (i < MCF_MAXPORTS); i++) {
+               port = &mcf_ports[i].port;
+               if (port)
+                       uart_remove_one_port(&mcf_driver, port);
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+
+static struct platform_driver mcf_platform_driver = {
+       .probe          = mcf_probe,
+       .remove         = __devexit_p(mcf_remove),
+       .driver         = {
+               .name   = "mcfuart",
+               .owner  = THIS_MODULE,
+       },
+};
+
+/****************************************************************************/
+
+static int __init mcf_init(void)
+{
+       int rc;
+
+       printk("ColdFire internal UART serial driver\n");
+
+       rc = uart_register_driver(&mcf_driver);
+       if (rc)
+               return rc;
+       rc = platform_driver_register(&mcf_platform_driver);
+       if (rc)
+               return rc;
+       return 0;
+}
+
+/****************************************************************************/
+
+static void __exit mcf_exit(void)
+{
+       platform_driver_unregister(&mcf_platform_driver);
+       uart_unregister_driver(&mcf_driver);
+}
+
+/****************************************************************************/
+
+module_init(mcf_init);
+module_exit(mcf_exit);
+
+MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>");
+MODULE_DESCRIPTION("Freescale ColdFire UART driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mcfuart");
+
+/****************************************************************************/
diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c
new file mode 100644 (file)
index 0000000..d40010a
--- /dev/null
@@ -0,0 +1,1513 @@
+/*
+ * mfd.c: driver for High Speed UART device of Intel Medfield platform
+ *
+ * Refer pxa.c, 8250.c and some other drivers in drivers/serial/
+ *
+ * (C) Copyright 2010 Intel Corporation
+ *
+ * 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; version 2
+ * of the License.
+ */
+
+/* Notes:
+ * 1. DMA channel allocation: 0/1 channel are assigned to port 0,
+ *    2/3 chan to port 1, 4/5 chan to port 3. Even number chans
+ *    are used for RX, odd chans for TX
+ *
+ * 2. In A0 stepping, UART will not support TX half empty flag
+ *
+ * 3. The RI/DSR/DCD/DTR are not pinned out, DCD & DSR are always
+ *    asserted, only when the HW is reset the DDCD and DDSR will
+ *    be triggered
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/slab.h>
+#include <linux/serial_reg.h>
+#include <linux/circ_buf.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial_mfd.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/debugfs.h>
+
+#define  MFD_HSU_A0_STEPPING   1
+
+#define HSU_DMA_BUF_SIZE       2048
+
+#define chan_readl(chan, offset)       readl(chan->reg + offset)
+#define chan_writel(chan, offset, val) writel(val, chan->reg + offset)
+
+#define mfd_readl(obj, offset)         readl(obj->reg + offset)
+#define mfd_writel(obj, offset, val)   writel(val, obj->reg + offset)
+
+#define HSU_DMA_TIMEOUT_CHECK_FREQ     (HZ/10)
+
+struct hsu_dma_buffer {
+       u8              *buf;
+       dma_addr_t      dma_addr;
+       u32             dma_size;
+       u32             ofs;
+};
+
+struct hsu_dma_chan {
+       u32     id;
+       enum dma_data_direction dirt;
+       struct uart_hsu_port    *uport;
+       void __iomem            *reg;
+       struct timer_list       rx_timer; /* only needed by RX channel */
+};
+
+struct uart_hsu_port {
+       struct uart_port        port;
+       unsigned char           ier;
+       unsigned char           lcr;
+       unsigned char           mcr;
+       unsigned int            lsr_break_flag;
+       char                    name[12];
+       int                     index;
+       struct device           *dev;
+
+       struct hsu_dma_chan     *txc;
+       struct hsu_dma_chan     *rxc;
+       struct hsu_dma_buffer   txbuf;
+       struct hsu_dma_buffer   rxbuf;
+       int                     use_dma;        /* flag for DMA/PIO */
+       int                     running;
+       int                     dma_tx_on;
+};
+
+/* Top level data structure of HSU */
+struct hsu_port {
+       void __iomem    *reg;
+       unsigned long   paddr;
+       unsigned long   iolen;
+       u32             irq;
+
+       struct uart_hsu_port    port[3];
+       struct hsu_dma_chan     chans[10];
+
+       struct dentry *debugfs;
+};
+
+static inline unsigned int serial_in(struct uart_hsu_port *up, int offset)
+{
+       unsigned int val;
+
+       if (offset > UART_MSR) {
+               offset <<= 2;
+               val = readl(up->port.membase + offset);
+       } else
+               val = (unsigned int)readb(up->port.membase + offset);
+
+       return val;
+}
+
+static inline void serial_out(struct uart_hsu_port *up, int offset, int value)
+{
+       if (offset > UART_MSR) {
+               offset <<= 2;
+               writel(value, up->port.membase + offset);
+       } else {
+               unsigned char val = value & 0xff;
+               writeb(val, up->port.membase + offset);
+       }
+}
+
+#ifdef CONFIG_DEBUG_FS
+
+#define HSU_REGS_BUFSIZE       1024
+
+static int hsu_show_regs_open(struct inode *inode, struct file *file)
+{
+       file->private_data = inode->i_private;
+       return 0;
+}
+
+static ssize_t port_show_regs(struct file *file, char __user *user_buf,
+                               size_t count, loff_t *ppos)
+{
+       struct uart_hsu_port *up = file->private_data;
+       char *buf;
+       u32 len = 0;
+       ssize_t ret;
+
+       buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL);
+       if (!buf)
+               return 0;
+
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "MFD HSU port[%d] regs:\n", up->index);
+
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "=================================\n");
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "IER: \t\t0x%08x\n", serial_in(up, UART_IER));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "IIR: \t\t0x%08x\n", serial_in(up, UART_IIR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "LCR: \t\t0x%08x\n", serial_in(up, UART_LCR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "MCR: \t\t0x%08x\n", serial_in(up, UART_MCR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "LSR: \t\t0x%08x\n", serial_in(up, UART_LSR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "MSR: \t\t0x%08x\n", serial_in(up, UART_MSR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "FOR: \t\t0x%08x\n", serial_in(up, UART_FOR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "PS: \t\t0x%08x\n", serial_in(up, UART_PS));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "MUL: \t\t0x%08x\n", serial_in(up, UART_MUL));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "DIV: \t\t0x%08x\n", serial_in(up, UART_DIV));
+
+       if (len > HSU_REGS_BUFSIZE)
+               len = HSU_REGS_BUFSIZE;
+
+       ret =  simple_read_from_buffer(user_buf, count, ppos, buf, len);
+       kfree(buf);
+       return ret;
+}
+
+static ssize_t dma_show_regs(struct file *file, char __user *user_buf,
+                               size_t count, loff_t *ppos)
+{
+       struct hsu_dma_chan *chan = file->private_data;
+       char *buf;
+       u32 len = 0;
+       ssize_t ret;
+
+       buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL);
+       if (!buf)
+               return 0;
+
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "MFD HSU DMA channel [%d] regs:\n", chan->id);
+
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "=================================\n");
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "CR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_CR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "DCR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_DCR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "BSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_BSR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "MOTSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_MOTSR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0SAR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0TSR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1SAR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1TSR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2SAR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2TSR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3SAR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3TSR));
+
+       if (len > HSU_REGS_BUFSIZE)
+               len = HSU_REGS_BUFSIZE;
+
+       ret =  simple_read_from_buffer(user_buf, count, ppos, buf, len);
+       kfree(buf);
+       return ret;
+}
+
+static const struct file_operations port_regs_ops = {
+       .owner          = THIS_MODULE,
+       .open           = hsu_show_regs_open,
+       .read           = port_show_regs,
+       .llseek         = default_llseek,
+};
+
+static const struct file_operations dma_regs_ops = {
+       .owner          = THIS_MODULE,
+       .open           = hsu_show_regs_open,
+       .read           = dma_show_regs,
+       .llseek         = default_llseek,
+};
+
+static int hsu_debugfs_init(struct hsu_port *hsu)
+{
+       int i;
+       char name[32];
+
+       hsu->debugfs = debugfs_create_dir("hsu", NULL);
+       if (!hsu->debugfs)
+               return -ENOMEM;
+
+       for (i = 0; i < 3; i++) {
+               snprintf(name, sizeof(name), "port_%d_regs", i);
+               debugfs_create_file(name, S_IFREG | S_IRUGO,
+                       hsu->debugfs, (void *)(&hsu->port[i]), &port_regs_ops);
+       }
+
+       for (i = 0; i < 6; i++) {
+               snprintf(name, sizeof(name), "dma_chan_%d_regs", i);
+               debugfs_create_file(name, S_IFREG | S_IRUGO,
+                       hsu->debugfs, (void *)&hsu->chans[i], &dma_regs_ops);
+       }
+
+       return 0;
+}
+
+static void hsu_debugfs_remove(struct hsu_port *hsu)
+{
+       if (hsu->debugfs)
+               debugfs_remove_recursive(hsu->debugfs);
+}
+
+#else
+static inline int hsu_debugfs_init(struct hsu_port *hsu)
+{
+       return 0;
+}
+
+static inline void hsu_debugfs_remove(struct hsu_port *hsu)
+{
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static void serial_hsu_enable_ms(struct uart_port *port)
+{
+       struct uart_hsu_port *up =
+               container_of(port, struct uart_hsu_port, port);
+
+       up->ier |= UART_IER_MSI;
+       serial_out(up, UART_IER, up->ier);
+}
+
+void hsu_dma_tx(struct uart_hsu_port *up)
+{
+       struct circ_buf *xmit = &up->port.state->xmit;
+       struct hsu_dma_buffer *dbuf = &up->txbuf;
+       int count;
+
+       /* test_and_set_bit may be better, but anyway it's in lock protected mode */
+       if (up->dma_tx_on)
+               return;
+
+       /* Update the circ buf info */
+       xmit->tail += dbuf->ofs;
+       xmit->tail &= UART_XMIT_SIZE - 1;
+
+       up->port.icount.tx += dbuf->ofs;
+       dbuf->ofs = 0;
+
+       /* Disable the channel */
+       chan_writel(up->txc, HSU_CH_CR, 0x0);
+
+       if (!uart_circ_empty(xmit) && !uart_tx_stopped(&up->port)) {
+               dma_sync_single_for_device(up->port.dev,
+                                          dbuf->dma_addr,
+                                          dbuf->dma_size,
+                                          DMA_TO_DEVICE);
+
+               count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+               dbuf->ofs = count;
+
+               /* Reprogram the channel */
+               chan_writel(up->txc, HSU_CH_D0SAR, dbuf->dma_addr + xmit->tail);
+               chan_writel(up->txc, HSU_CH_D0TSR, count);
+
+               /* Reenable the channel */
+               chan_writel(up->txc, HSU_CH_DCR, 0x1
+                                                | (0x1 << 8)
+                                                | (0x1 << 16)
+                                                | (0x1 << 24));
+               up->dma_tx_on = 1;
+               chan_writel(up->txc, HSU_CH_CR, 0x1);
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+}
+
+/* The buffer is already cache coherent */
+void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc, struct hsu_dma_buffer *dbuf)
+{
+       dbuf->ofs = 0;
+
+       chan_writel(rxc, HSU_CH_BSR, 32);
+       chan_writel(rxc, HSU_CH_MOTSR, 4);
+
+       chan_writel(rxc, HSU_CH_D0SAR, dbuf->dma_addr);
+       chan_writel(rxc, HSU_CH_D0TSR, dbuf->dma_size);
+       chan_writel(rxc, HSU_CH_DCR, 0x1 | (0x1 << 8)
+                                        | (0x1 << 16)
+                                        | (0x1 << 24)  /* timeout bit, see HSU Errata 1 */
+                                        );
+       chan_writel(rxc, HSU_CH_CR, 0x3);
+
+       mod_timer(&rxc->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ);
+}
+
+/* Protected by spin_lock_irqsave(port->lock) */
+static void serial_hsu_start_tx(struct uart_port *port)
+{
+       struct uart_hsu_port *up =
+               container_of(port, struct uart_hsu_port, port);
+
+       if (up->use_dma) {
+               hsu_dma_tx(up);
+       } else if (!(up->ier & UART_IER_THRI)) {
+               up->ier |= UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+       }
+}
+
+static void serial_hsu_stop_tx(struct uart_port *port)
+{
+       struct uart_hsu_port *up =
+               container_of(port, struct uart_hsu_port, port);
+       struct hsu_dma_chan *txc = up->txc;
+
+       if (up->use_dma)
+               chan_writel(txc, HSU_CH_CR, 0x0);
+       else if (up->ier & UART_IER_THRI) {
+               up->ier &= ~UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+       }
+}
+
+/* This is always called in spinlock protected mode, so
+ * modify timeout timer is safe here */
+void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts)
+{
+       struct hsu_dma_buffer *dbuf = &up->rxbuf;
+       struct hsu_dma_chan *chan = up->rxc;
+       struct uart_port *port = &up->port;
+       struct tty_struct *tty = port->state->port.tty;
+       int count;
+
+       if (!tty)
+               return;
+
+       /*
+        * First need to know how many is already transferred,
+        * then check if its a timeout DMA irq, and return
+        * the trail bytes out, push them up and reenable the
+        * channel
+        */
+
+       /* Timeout IRQ, need wait some time, see Errata 2 */
+       if (int_sts & 0xf00)
+               udelay(2);
+
+       /* Stop the channel */
+       chan_writel(chan, HSU_CH_CR, 0x0);
+
+       count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr;
+       if (!count) {
+               /* Restart the channel before we leave */
+               chan_writel(chan, HSU_CH_CR, 0x3);
+               return;
+       }
+       del_timer(&chan->rx_timer);
+
+       dma_sync_single_for_cpu(port->dev, dbuf->dma_addr,
+                       dbuf->dma_size, DMA_FROM_DEVICE);
+
+       /*
+        * Head will only wrap around when we recycle
+        * the DMA buffer, and when that happens, we
+        * explicitly set tail to 0. So head will
+        * always be greater than tail.
+        */
+       tty_insert_flip_string(tty, dbuf->buf, count);
+       port->icount.rx += count;
+
+       dma_sync_single_for_device(up->port.dev, dbuf->dma_addr,
+                       dbuf->dma_size, DMA_FROM_DEVICE);
+
+       /* Reprogram the channel */
+       chan_writel(chan, HSU_CH_D0SAR, dbuf->dma_addr);
+       chan_writel(chan, HSU_CH_D0TSR, dbuf->dma_size);
+       chan_writel(chan, HSU_CH_DCR, 0x1
+                                        | (0x1 << 8)
+                                        | (0x1 << 16)
+                                        | (0x1 << 24)  /* timeout bit, see HSU Errata 1 */
+                                        );
+       tty_flip_buffer_push(tty);
+
+       chan_writel(chan, HSU_CH_CR, 0x3);
+       chan->rx_timer.expires = jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ;
+       add_timer(&chan->rx_timer);
+
+}
+
+static void serial_hsu_stop_rx(struct uart_port *port)
+{
+       struct uart_hsu_port *up =
+               container_of(port, struct uart_hsu_port, port);
+       struct hsu_dma_chan *chan = up->rxc;
+
+       if (up->use_dma)
+               chan_writel(chan, HSU_CH_CR, 0x2);
+       else {
+               up->ier &= ~UART_IER_RLSI;
+               up->port.read_status_mask &= ~UART_LSR_DR;
+               serial_out(up, UART_IER, up->ier);
+       }
+}
+
+static inline void receive_chars(struct uart_hsu_port *up, int *status)
+{
+       struct tty_struct *tty = up->port.state->port.tty;
+       unsigned int ch, flag;
+       unsigned int max_count = 256;
+
+       if (!tty)
+               return;
+
+       do {
+               ch = serial_in(up, UART_RX);
+               flag = TTY_NORMAL;
+               up->port.icount.rx++;
+
+               if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
+                                      UART_LSR_FE | UART_LSR_OE))) {
+
+                       dev_warn(up->dev, "We really rush into ERR/BI case"
+                               "status = 0x%02x", *status);
+                       /* For statistics only */
+                       if (*status & UART_LSR_BI) {
+                               *status &= ~(UART_LSR_FE | UART_LSR_PE);
+                               up->port.icount.brk++;
+                               /*
+                                * We do the SysRQ and SAK checking
+                                * here because otherwise the break
+                                * may get masked by ignore_status_mask
+                                * or read_status_mask.
+                                */
+                               if (uart_handle_break(&up->port))
+                                       goto ignore_char;
+                       } else if (*status & UART_LSR_PE)
+                               up->port.icount.parity++;
+                       else if (*status & UART_LSR_FE)
+                               up->port.icount.frame++;
+                       if (*status & UART_LSR_OE)
+                               up->port.icount.overrun++;
+
+                       /* Mask off conditions which should be ignored. */
+                       *status &= up->port.read_status_mask;
+
+#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE
+                       if (up->port.cons &&
+                               up->port.cons->index == up->port.line) {
+                               /* Recover the break flag from console xmit */
+                               *status |= up->lsr_break_flag;
+                               up->lsr_break_flag = 0;
+                       }
+#endif
+                       if (*status & UART_LSR_BI) {
+                               flag = TTY_BREAK;
+                       } else if (*status & UART_LSR_PE)
+                               flag = TTY_PARITY;
+                       else if (*status & UART_LSR_FE)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(&up->port, ch))
+                       goto ignore_char;
+
+               uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag);
+       ignore_char:
+               *status = serial_in(up, UART_LSR);
+       } while ((*status & UART_LSR_DR) && max_count--);
+       tty_flip_buffer_push(tty);
+}
+
+static void transmit_chars(struct uart_hsu_port *up)
+{
+       struct circ_buf *xmit = &up->port.state->xmit;
+       int count;
+
+       if (up->port.x_char) {
+               serial_out(up, UART_TX, up->port.x_char);
+               up->port.icount.tx++;
+               up->port.x_char = 0;
+               return;
+       }
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+               serial_hsu_stop_tx(&up->port);
+               return;
+       }
+
+#ifndef MFD_HSU_A0_STEPPING
+       count = up->port.fifosize / 2;
+#else
+       /*
+        * A0 only supports fully empty IRQ, and the first char written
+        * into it won't clear the EMPT bit, so we may need be cautious
+        * by useing a shorter buffer
+        */
+       count = up->port.fifosize - 4;
+#endif
+       do {
+               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+
+               up->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (--count > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+       if (uart_circ_empty(xmit))
+               serial_hsu_stop_tx(&up->port);
+}
+
+static inline void check_modem_status(struct uart_hsu_port *up)
+{
+       int status;
+
+       status = serial_in(up, UART_MSR);
+
+       if ((status & UART_MSR_ANY_DELTA) == 0)
+               return;
+
+       if (status & UART_MSR_TERI)
+               up->port.icount.rng++;
+       if (status & UART_MSR_DDSR)
+               up->port.icount.dsr++;
+       /* We may only get DDCD when HW init and reset */
+       if (status & UART_MSR_DDCD)
+               uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
+       /* Will start/stop_tx accordingly */
+       if (status & UART_MSR_DCTS)
+               uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
+
+       wake_up_interruptible(&up->port.state->port.delta_msr_wait);
+}
+
+/*
+ * This handles the interrupt from one port.
+ */
+static irqreturn_t port_irq(int irq, void *dev_id)
+{
+       struct uart_hsu_port *up = dev_id;
+       unsigned int iir, lsr;
+       unsigned long flags;
+
+       if (unlikely(!up->running))
+               return IRQ_NONE;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       if (up->use_dma) {
+               lsr = serial_in(up, UART_LSR);
+               if (unlikely(lsr & (UART_LSR_BI | UART_LSR_PE |
+                                      UART_LSR_FE | UART_LSR_OE)))
+                       dev_warn(up->dev,
+                               "Got lsr irq while using DMA, lsr = 0x%2x\n",
+                               lsr);
+               check_modem_status(up);
+               spin_unlock_irqrestore(&up->port.lock, flags);
+               return IRQ_HANDLED;
+       }
+
+       iir = serial_in(up, UART_IIR);
+       if (iir & UART_IIR_NO_INT) {
+               spin_unlock_irqrestore(&up->port.lock, flags);
+               return IRQ_NONE;
+       }
+
+       lsr = serial_in(up, UART_LSR);
+       if (lsr & UART_LSR_DR)
+               receive_chars(up, &lsr);
+       check_modem_status(up);
+
+       /* lsr will be renewed during the receive_chars */
+       if (lsr & UART_LSR_THRE)
+               transmit_chars(up);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+       return IRQ_HANDLED;
+}
+
+static inline void dma_chan_irq(struct hsu_dma_chan *chan)
+{
+       struct uart_hsu_port *up = chan->uport;
+       unsigned long flags;
+       u32 int_sts;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       if (!up->use_dma || !up->running)
+               goto exit;
+
+       /*
+        * No matter what situation, need read clear the IRQ status
+        * There is a bug, see Errata 5, HSD 2900918
+        */
+       int_sts = chan_readl(chan, HSU_CH_SR);
+
+       /* Rx channel */
+       if (chan->dirt == DMA_FROM_DEVICE)
+               hsu_dma_rx(up, int_sts);
+
+       /* Tx channel */
+       if (chan->dirt == DMA_TO_DEVICE) {
+               chan_writel(chan, HSU_CH_CR, 0x0);
+               up->dma_tx_on = 0;
+               hsu_dma_tx(up);
+       }
+
+exit:
+       spin_unlock_irqrestore(&up->port.lock, flags);
+       return;
+}
+
+static irqreturn_t dma_irq(int irq, void *dev_id)
+{
+       struct hsu_port *hsu = dev_id;
+       u32 int_sts, i;
+
+       int_sts = mfd_readl(hsu, HSU_GBL_DMAISR);
+
+       /* Currently we only have 6 channels may be used */
+       for (i = 0; i < 6; i++) {
+               if (int_sts & 0x1)
+                       dma_chan_irq(&hsu->chans[i]);
+               int_sts >>= 1;
+       }
+
+       return IRQ_HANDLED;
+}
+
+static unsigned int serial_hsu_tx_empty(struct uart_port *port)
+{
+       struct uart_hsu_port *up =
+               container_of(port, struct uart_hsu_port, port);
+       unsigned long flags;
+       unsigned int ret;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       return ret;
+}
+
+static unsigned int serial_hsu_get_mctrl(struct uart_port *port)
+{
+       struct uart_hsu_port *up =
+               container_of(port, struct uart_hsu_port, port);
+       unsigned char status;
+       unsigned int ret;
+
+       status = serial_in(up, UART_MSR);
+
+       ret = 0;
+       if (status & UART_MSR_DCD)
+               ret |= TIOCM_CAR;
+       if (status & UART_MSR_RI)
+               ret |= TIOCM_RNG;
+       if (status & UART_MSR_DSR)
+               ret |= TIOCM_DSR;
+       if (status & UART_MSR_CTS)
+               ret |= TIOCM_CTS;
+       return ret;
+}
+
+static void serial_hsu_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_hsu_port *up =
+               container_of(port, struct uart_hsu_port, port);
+       unsigned char mcr = 0;
+
+       if (mctrl & TIOCM_RTS)
+               mcr |= UART_MCR_RTS;
+       if (mctrl & TIOCM_DTR)
+               mcr |= UART_MCR_DTR;
+       if (mctrl & TIOCM_OUT1)
+               mcr |= UART_MCR_OUT1;
+       if (mctrl & TIOCM_OUT2)
+               mcr |= UART_MCR_OUT2;
+       if (mctrl & TIOCM_LOOP)
+               mcr |= UART_MCR_LOOP;
+
+       mcr |= up->mcr;
+
+       serial_out(up, UART_MCR, mcr);
+}
+
+static void serial_hsu_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_hsu_port *up =
+               container_of(port, struct uart_hsu_port, port);
+       unsigned long flags;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       if (break_state == -1)
+               up->lcr |= UART_LCR_SBC;
+       else
+               up->lcr &= ~UART_LCR_SBC;
+       serial_out(up, UART_LCR, up->lcr);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+/*
+ * What special to do:
+ * 1. chose the 64B fifo mode
+ * 2. make sure not to select half empty mode for A0 stepping
+ * 3. start dma or pio depends on configuration
+ * 4. we only allocate dma memory when needed
+ */
+static int serial_hsu_startup(struct uart_port *port)
+{
+       struct uart_hsu_port *up =
+               container_of(port, struct uart_hsu_port, port);
+       unsigned long flags;
+
+       /*
+        * Clear the FIFO buffers and disable them.
+        * (they will be reenabled in set_termios())
+        */
+       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+                       UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+       serial_out(up, UART_FCR, 0);
+
+       /* Clear the interrupt registers. */
+       (void) serial_in(up, UART_LSR);
+       (void) serial_in(up, UART_RX);
+       (void) serial_in(up, UART_IIR);
+       (void) serial_in(up, UART_MSR);
+
+       /* Now, initialize the UART, default is 8n1 */
+       serial_out(up, UART_LCR, UART_LCR_WLEN8);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       up->port.mctrl |= TIOCM_OUT2;
+       serial_hsu_set_mctrl(&up->port, up->port.mctrl);
+
+       /*
+        * Finally, enable interrupts.  Note: Modem status interrupts
+        * are set via set_termios(), which will be occurring imminently
+        * anyway, so we don't enable them here.
+        */
+       if (!up->use_dma)
+               up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE;
+       else
+               up->ier = 0;
+       serial_out(up, UART_IER, up->ier);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       /* DMA init */
+       if (up->use_dma) {
+               struct hsu_dma_buffer *dbuf;
+               struct circ_buf *xmit = &port->state->xmit;
+
+               up->dma_tx_on = 0;
+
+               /* First allocate the RX buffer */
+               dbuf = &up->rxbuf;
+               dbuf->buf = kzalloc(HSU_DMA_BUF_SIZE, GFP_KERNEL);
+               if (!dbuf->buf) {
+                       up->use_dma = 0;
+                       goto exit;
+               }
+               dbuf->dma_addr = dma_map_single(port->dev,
+                                               dbuf->buf,
+                                               HSU_DMA_BUF_SIZE,
+                                               DMA_FROM_DEVICE);
+               dbuf->dma_size = HSU_DMA_BUF_SIZE;
+
+               /* Start the RX channel right now */
+               hsu_dma_start_rx_chan(up->rxc, dbuf);
+
+               /* Next init the TX DMA */
+               dbuf = &up->txbuf;
+               dbuf->buf = xmit->buf;
+               dbuf->dma_addr = dma_map_single(port->dev,
+                                              dbuf->buf,
+                                              UART_XMIT_SIZE,
+                                              DMA_TO_DEVICE);
+               dbuf->dma_size = UART_XMIT_SIZE;
+
+               /* This should not be changed all around */
+               chan_writel(up->txc, HSU_CH_BSR, 32);
+               chan_writel(up->txc, HSU_CH_MOTSR, 4);
+               dbuf->ofs = 0;
+       }
+
+exit:
+        /* And clear the interrupt registers again for luck. */
+       (void) serial_in(up, UART_LSR);
+       (void) serial_in(up, UART_RX);
+       (void) serial_in(up, UART_IIR);
+       (void) serial_in(up, UART_MSR);
+
+       up->running = 1;
+       return 0;
+}
+
+static void serial_hsu_shutdown(struct uart_port *port)
+{
+       struct uart_hsu_port *up =
+               container_of(port, struct uart_hsu_port, port);
+       unsigned long flags;
+
+       del_timer_sync(&up->rxc->rx_timer);
+
+       /* Disable interrupts from this port */
+       up->ier = 0;
+       serial_out(up, UART_IER, 0);
+       up->running = 0;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       up->port.mctrl &= ~TIOCM_OUT2;
+       serial_hsu_set_mctrl(&up->port, up->port.mctrl);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       /* Disable break condition and FIFOs */
+       serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
+       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+                                 UART_FCR_CLEAR_RCVR |
+                                 UART_FCR_CLEAR_XMIT);
+       serial_out(up, UART_FCR, 0);
+}
+
+static void
+serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios,
+                      struct ktermios *old)
+{
+       struct uart_hsu_port *up =
+                       container_of(port, struct uart_hsu_port, port);
+       struct tty_struct *tty = port->state->port.tty;
+       unsigned char cval, fcr = 0;
+       unsigned long flags;
+       unsigned int baud, quot;
+       u32 ps, mul;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               cval = UART_LCR_WLEN5;
+               break;
+       case CS6:
+               cval = UART_LCR_WLEN6;
+               break;
+       case CS7:
+               cval = UART_LCR_WLEN7;
+               break;
+       default:
+       case CS8:
+               cval = UART_LCR_WLEN8;
+               break;
+       }
+
+       /* CMSPAR isn't supported by this driver */
+       if (tty)
+               tty->termios->c_cflag &= ~CMSPAR;
+
+       if (termios->c_cflag & CSTOPB)
+               cval |= UART_LCR_STOP;
+       if (termios->c_cflag & PARENB)
+               cval |= UART_LCR_PARITY;
+       if (!(termios->c_cflag & PARODD))
+               cval |= UART_LCR_EPAR;
+
+       /*
+        * The base clk is 50Mhz, and the baud rate come from:
+        *      baud = 50M * MUL / (DIV * PS * DLAB)
+        *
+        * For those basic low baud rate we can get the direct
+        * scalar from 2746800, like 115200 = 2746800/24. For those
+        * higher baud rate, we handle them case by case, mainly by
+        * adjusting the MUL/PS registers, and DIV register is kept
+        * as default value 0x3d09 to make things simple
+        */
+       baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
+
+       quot = 1;
+       ps = 0x10;
+       mul = 0x3600;
+       switch (baud) {
+       case 3500000:
+               mul = 0x3345;
+               ps = 0xC;
+               break;
+       case 1843200:
+               mul = 0x2400;
+               break;
+       case 3000000:
+       case 2500000:
+       case 2000000:
+       case 1500000:
+       case 1000000:
+       case 500000:
+               /* mul/ps/quot = 0x9C4/0x10/0x1 will make a 500000 bps */
+               mul = baud / 500000 * 0x9C4;
+               break;
+       default:
+               /* Use uart_get_divisor to get quot for other baud rates */
+               quot = 0;
+       }
+
+       if (!quot)
+               quot = uart_get_divisor(port, baud);
+
+       if ((up->port.uartclk / quot) < (2400 * 16))
+               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_1B;
+       else if ((up->port.uartclk / quot) < (230400 * 16))
+               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_16B;
+       else
+               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_32B;
+
+       fcr |= UART_FCR_HSU_64B_FIFO;
+#ifdef MFD_HSU_A0_STEPPING
+       /* A0 doesn't support half empty IRQ */
+       fcr |= UART_FCR_FULL_EMPT_TXI;
+#endif
+
+       /*
+        * Ok, we're now changing the port state.  Do it with
+        * interrupts disabled.
+        */
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       /* Update the per-port timeout */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+       if (termios->c_iflag & INPCK)
+               up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               up->port.read_status_mask |= UART_LSR_BI;
+
+       /* Characters to ignore */
+       up->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+       if (termios->c_iflag & IGNBRK) {
+               up->port.ignore_status_mask |= UART_LSR_BI;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       up->port.ignore_status_mask |= UART_LSR_OE;
+       }
+
+       /* Ignore all characters if CREAD is not set */
+       if ((termios->c_cflag & CREAD) == 0)
+               up->port.ignore_status_mask |= UART_LSR_DR;
+
+       /*
+        * CTS flow control flag and modem status interrupts, disable
+        * MSI by default
+        */
+       up->ier &= ~UART_IER_MSI;
+       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
+               up->ier |= UART_IER_MSI;
+
+       serial_out(up, UART_IER, up->ier);
+
+       if (termios->c_cflag & CRTSCTS)
+               up->mcr |= UART_MCR_AFE | UART_MCR_RTS;
+       else
+               up->mcr &= ~UART_MCR_AFE;
+
+       serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
+       serial_out(up, UART_DLL, quot & 0xff);          /* LS of divisor */
+       serial_out(up, UART_DLM, quot >> 8);            /* MS of divisor */
+       serial_out(up, UART_LCR, cval);                 /* reset DLAB */
+       serial_out(up, UART_MUL, mul);                  /* set MUL */
+       serial_out(up, UART_PS, ps);                    /* set PS */
+       up->lcr = cval;                                 /* Save LCR */
+       serial_hsu_set_mctrl(&up->port, up->port.mctrl);
+       serial_out(up, UART_FCR, fcr);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static void
+serial_hsu_pm(struct uart_port *port, unsigned int state,
+             unsigned int oldstate)
+{
+}
+
+static void serial_hsu_release_port(struct uart_port *port)
+{
+}
+
+static int serial_hsu_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static void serial_hsu_config_port(struct uart_port *port, int flags)
+{
+       struct uart_hsu_port *up =
+               container_of(port, struct uart_hsu_port, port);
+       up->port.type = PORT_MFD;
+}
+
+static int
+serial_hsu_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       /* We don't want the core code to modify any port params */
+       return -EINVAL;
+}
+
+static const char *
+serial_hsu_type(struct uart_port *port)
+{
+       struct uart_hsu_port *up =
+               container_of(port, struct uart_hsu_port, port);
+       return up->name;
+}
+
+/* Mainly for uart console use */
+static struct uart_hsu_port *serial_hsu_ports[3];
+static struct uart_driver serial_hsu_reg;
+
+#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+/* Wait for transmitter & holding register to empty */
+static inline void wait_for_xmitr(struct uart_hsu_port *up)
+{
+       unsigned int status, tmout = 1000;
+
+       /* Wait up to 1ms for the character to be sent. */
+       do {
+               status = serial_in(up, UART_LSR);
+
+               if (status & UART_LSR_BI)
+                       up->lsr_break_flag = UART_LSR_BI;
+
+               if (--tmout == 0)
+                       break;
+               udelay(1);
+       } while (!(status & BOTH_EMPTY));
+
+       /* Wait up to 1s for flow control if necessary */
+       if (up->port.flags & UPF_CONS_FLOW) {
+               tmout = 1000000;
+               while (--tmout &&
+                      ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
+                       udelay(1);
+       }
+}
+
+static void serial_hsu_console_putchar(struct uart_port *port, int ch)
+{
+       struct uart_hsu_port *up =
+               container_of(port, struct uart_hsu_port, port);
+
+       wait_for_xmitr(up);
+       serial_out(up, UART_TX, ch);
+}
+
+/*
+ * 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.
+ */
+static void
+serial_hsu_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct uart_hsu_port *up = serial_hsu_ports[co->index];
+       unsigned long flags;
+       unsigned int ier;
+       int locked = 1;
+
+       local_irq_save(flags);
+       if (up->port.sysrq)
+               locked = 0;
+       else if (oops_in_progress) {
+               locked = spin_trylock(&up->port.lock);
+       } else
+               spin_lock(&up->port.lock);
+
+       /* First save the IER then disable the interrupts */
+       ier = serial_in(up, UART_IER);
+       serial_out(up, UART_IER, 0);
+
+       uart_console_write(&up->port, s, count, serial_hsu_console_putchar);
+
+       /*
+        * Finally, wait for transmitter to become empty
+        * and restore the IER
+        */
+       wait_for_xmitr(up);
+       serial_out(up, UART_IER, ier);
+
+       if (locked)
+               spin_unlock(&up->port.lock);
+       local_irq_restore(flags);
+}
+
+static struct console serial_hsu_console;
+
+static int __init
+serial_hsu_console_setup(struct console *co, char *options)
+{
+       struct uart_hsu_port *up;
+       int baud = 115200;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+       int ret;
+
+       if (co->index == -1 || co->index >= serial_hsu_reg.nr)
+               co->index = 0;
+       up = serial_hsu_ports[co->index];
+       if (!up)
+               return -ENODEV;
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       ret = uart_set_options(&up->port, co, baud, parity, bits, flow);
+
+       return ret;
+}
+
+static struct console serial_hsu_console = {
+       .name           = "ttyMFD",
+       .write          = serial_hsu_console_write,
+       .device         = uart_console_device,
+       .setup          = serial_hsu_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = 2,
+       .data           = &serial_hsu_reg,
+};
+#endif
+
+struct uart_ops serial_hsu_pops = {
+       .tx_empty       = serial_hsu_tx_empty,
+       .set_mctrl      = serial_hsu_set_mctrl,
+       .get_mctrl      = serial_hsu_get_mctrl,
+       .stop_tx        = serial_hsu_stop_tx,
+       .start_tx       = serial_hsu_start_tx,
+       .stop_rx        = serial_hsu_stop_rx,
+       .enable_ms      = serial_hsu_enable_ms,
+       .break_ctl      = serial_hsu_break_ctl,
+       .startup        = serial_hsu_startup,
+       .shutdown       = serial_hsu_shutdown,
+       .set_termios    = serial_hsu_set_termios,
+       .pm             = serial_hsu_pm,
+       .type           = serial_hsu_type,
+       .release_port   = serial_hsu_release_port,
+       .request_port   = serial_hsu_request_port,
+       .config_port    = serial_hsu_config_port,
+       .verify_port    = serial_hsu_verify_port,
+};
+
+static struct uart_driver serial_hsu_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "MFD serial",
+       .dev_name       = "ttyMFD",
+       .major          = TTY_MAJOR,
+       .minor          = 128,
+       .nr             = 3,
+};
+
+#ifdef CONFIG_PM
+static int serial_hsu_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       void *priv = pci_get_drvdata(pdev);
+       struct uart_hsu_port *up;
+
+       /* Make sure this is not the internal dma controller */
+       if (priv && (pdev->device != 0x081E)) {
+               up = priv;
+               uart_suspend_port(&serial_hsu_reg, &up->port);
+       }
+
+       pci_save_state(pdev);
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+        return 0;
+}
+
+static int serial_hsu_resume(struct pci_dev *pdev)
+{
+       void *priv = pci_get_drvdata(pdev);
+       struct uart_hsu_port *up;
+       int ret;
+
+       pci_set_power_state(pdev, PCI_D0);
+       pci_restore_state(pdev);
+
+       ret = pci_enable_device(pdev);
+       if (ret)
+               dev_warn(&pdev->dev,
+                       "HSU: can't re-enable device, try to continue\n");
+
+       if (priv && (pdev->device != 0x081E)) {
+               up = priv;
+               uart_resume_port(&serial_hsu_reg, &up->port);
+       }
+       return 0;
+}
+#else
+#define serial_hsu_suspend     NULL
+#define serial_hsu_resume      NULL
+#endif
+
+/* temp global pointer before we settle down on using one or four PCI dev */
+static struct hsu_port *phsu;
+
+static int serial_hsu_probe(struct pci_dev *pdev,
+                               const struct pci_device_id *ent)
+{
+       struct uart_hsu_port *uport;
+       int index, ret;
+
+       printk(KERN_INFO "HSU: found PCI Serial controller(ID: %04x:%04x)\n",
+               pdev->vendor, pdev->device);
+
+       switch (pdev->device) {
+       case 0x081B:
+               index = 0;
+               break;
+       case 0x081C:
+               index = 1;
+               break;
+       case 0x081D:
+               index = 2;
+               break;
+       case 0x081E:
+               /* internal DMA controller */
+               index = 3;
+               break;
+       default:
+               dev_err(&pdev->dev, "HSU: out of index!");
+               return -ENODEV;
+       }
+
+       ret = pci_enable_device(pdev);
+       if (ret)
+               return ret;
+
+       if (index == 3) {
+               /* DMA controller */
+               ret = request_irq(pdev->irq, dma_irq, 0, "hsu_dma", phsu);
+               if (ret) {
+                       dev_err(&pdev->dev, "can not get IRQ\n");
+                       goto err_disable;
+               }
+               pci_set_drvdata(pdev, phsu);
+       } else {
+               /* UART port 0~2 */
+               uport = &phsu->port[index];
+               uport->port.irq = pdev->irq;
+               uport->port.dev = &pdev->dev;
+               uport->dev = &pdev->dev;
+
+               ret = request_irq(pdev->irq, port_irq, 0, uport->name, uport);
+               if (ret) {
+                       dev_err(&pdev->dev, "can not get IRQ\n");
+                       goto err_disable;
+               }
+               uart_add_one_port(&serial_hsu_reg, &uport->port);
+
+#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE
+               if (index == 2) {
+                       register_console(&serial_hsu_console);
+                       uport->port.cons = &serial_hsu_console;
+               }
+#endif
+               pci_set_drvdata(pdev, uport);
+       }
+
+       return 0;
+
+err_disable:
+       pci_disable_device(pdev);
+       return ret;
+}
+
+static void hsu_dma_rx_timeout(unsigned long data)
+{
+       struct hsu_dma_chan *chan = (void *)data;
+       struct uart_hsu_port *up = chan->uport;
+       struct hsu_dma_buffer *dbuf = &up->rxbuf;
+       int count = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr;
+
+       if (!count) {
+               mod_timer(&chan->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ);
+               goto exit;
+       }
+
+       hsu_dma_rx(up, 0);
+exit:
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static void hsu_global_init(void)
+{
+       struct hsu_port *hsu;
+       struct uart_hsu_port *uport;
+       struct hsu_dma_chan *dchan;
+       int i, ret;
+
+       hsu = kzalloc(sizeof(struct hsu_port), GFP_KERNEL);
+       if (!hsu)
+               return;
+
+       /* Get basic io resource and map it */
+       hsu->paddr = 0xffa28000;
+       hsu->iolen = 0x1000;
+
+       if (!(request_mem_region(hsu->paddr, hsu->iolen, "HSU global")))
+               pr_warning("HSU: error in request mem region\n");
+
+       hsu->reg = ioremap_nocache((unsigned long)hsu->paddr, hsu->iolen);
+       if (!hsu->reg) {
+               pr_err("HSU: error in ioremap\n");
+               ret = -ENOMEM;
+               goto err_free_region;
+       }
+
+       /* Initialise the 3 UART ports */
+       uport = hsu->port;
+       for (i = 0; i < 3; i++) {
+               uport->port.type = PORT_MFD;
+               uport->port.iotype = UPIO_MEM;
+               uport->port.mapbase = (resource_size_t)hsu->paddr
+                                       + HSU_PORT_REG_OFFSET
+                                       + i * HSU_PORT_REG_LENGTH;
+               uport->port.membase = hsu->reg + HSU_PORT_REG_OFFSET
+                                       + i * HSU_PORT_REG_LENGTH;
+
+               sprintf(uport->name, "hsu_port%d", i);
+               uport->port.fifosize = 64;
+               uport->port.ops = &serial_hsu_pops;
+               uport->port.line = i;
+               uport->port.flags = UPF_IOREMAP;
+               /* set the scalable maxim support rate to 2746800 bps */
+               uport->port.uartclk = 115200 * 24 * 16;
+
+               uport->running = 0;
+               uport->txc = &hsu->chans[i * 2];
+               uport->rxc = &hsu->chans[i * 2 + 1];
+
+               serial_hsu_ports[i] = uport;
+               uport->index = i;
+               uport++;
+       }
+
+       /* Initialise 6 dma channels */
+       dchan = hsu->chans;
+       for (i = 0; i < 6; i++) {
+               dchan->id = i;
+               dchan->dirt = (i & 0x1) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+               dchan->uport = &hsu->port[i/2];
+               dchan->reg = hsu->reg + HSU_DMA_CHANS_REG_OFFSET +
+                               i * HSU_DMA_CHANS_REG_LENGTH;
+
+               /* Work around for RX */
+               if (dchan->dirt == DMA_FROM_DEVICE) {
+                       init_timer(&dchan->rx_timer);
+                       dchan->rx_timer.function = hsu_dma_rx_timeout;
+                       dchan->rx_timer.data = (unsigned long)dchan;
+               }
+               dchan++;
+       }
+
+       phsu = hsu;
+       hsu_debugfs_init(hsu);
+       return;
+
+err_free_region:
+       release_mem_region(hsu->paddr, hsu->iolen);
+       kfree(hsu);
+       return;
+}
+
+static void serial_hsu_remove(struct pci_dev *pdev)
+{
+       void *priv = pci_get_drvdata(pdev);
+       struct uart_hsu_port *up;
+
+       if (!priv)
+               return;
+
+       /* For port 0/1/2, priv is the address of uart_hsu_port */
+       if (pdev->device != 0x081E) {
+               up = priv;
+               uart_remove_one_port(&serial_hsu_reg, &up->port);
+       }
+
+       pci_set_drvdata(pdev, NULL);
+       free_irq(pdev->irq, priv);
+       pci_disable_device(pdev);
+}
+
+/* First 3 are UART ports, and the 4th is the DMA */
+static const struct pci_device_id pci_ids[] __devinitdata = {
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081B) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081C) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081D) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081E) },
+       {},
+};
+
+static struct pci_driver hsu_pci_driver = {
+       .name =         "HSU serial",
+       .id_table =     pci_ids,
+       .probe =        serial_hsu_probe,
+       .remove =       __devexit_p(serial_hsu_remove),
+       .suspend =      serial_hsu_suspend,
+       .resume =       serial_hsu_resume,
+};
+
+static int __init hsu_pci_init(void)
+{
+       int ret;
+
+       hsu_global_init();
+
+       ret = uart_register_driver(&serial_hsu_reg);
+       if (ret)
+               return ret;
+
+       return pci_register_driver(&hsu_pci_driver);
+}
+
+static void __exit hsu_pci_exit(void)
+{
+       pci_unregister_driver(&hsu_pci_driver);
+       uart_unregister_driver(&serial_hsu_reg);
+
+       hsu_debugfs_remove(phsu);
+
+       kfree(phsu);
+}
+
+module_init(hsu_pci_init);
+module_exit(hsu_pci_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:medfield-hsu");
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
new file mode 100644 (file)
index 0000000..126ec7f
--- /dev/null
@@ -0,0 +1,1527 @@
+/*
+ * Driver for the PSC of the Freescale MPC52xx PSCs configured as UARTs.
+ *
+ * FIXME According to the usermanual the status bits in the status register
+ * are only updated when the peripherals access the FIFO and not when the
+ * CPU access them. So since we use this bits to know when we stop writing
+ * and reading, they may not be updated in-time and a race condition may
+ * exists. But I haven't be able to prove this and I don't care. But if
+ * any problem arises, it might worth checking. The TX/RX FIFO Stats
+ * registers should be used in addition.
+ * Update: Actually, they seem updated ... At least the bits we use.
+ *
+ *
+ * Maintainer : Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Some of the code has been inspired/copied from the 2.4 code written
+ * by Dale Farnsworth <dfarnsworth@mvista.com>.
+ *
+ * Copyright (C) 2008 Freescale Semiconductor Inc.
+ *                    John Rigby <jrigby@gmail.com>
+ * Added support for MPC5121
+ * Copyright (C) 2006 Secret Lab Technologies Ltd.
+ *                    Grant Likely <grant.likely@secretlab.ca>
+ * Copyright (C) 2004-2006 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2003 MontaVista, Software, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#undef DEBUG
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/clk.h>
+
+#include <asm/mpc52xx.h>
+#include <asm/mpc52xx_psc.h>
+
+#if defined(CONFIG_SERIAL_MPC52xx_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+
+/* We've been assigned a range on the "Low-density serial ports" major */
+#define SERIAL_PSC_MAJOR       204
+#define SERIAL_PSC_MINOR       148
+
+
+#define ISR_PASS_LIMIT 256     /* Max number of iteration in the interrupt */
+
+
+static struct uart_port mpc52xx_uart_ports[MPC52xx_PSC_MAXNUM];
+       /* Rem: - We use the read_status_mask as a shadow of
+        *        psc->mpc52xx_psc_imr
+        *      - It's important that is array is all zero on start as we
+        *        use it to know if it's initialized or not ! If it's not sure
+        *        it's cleared, then a memset(...,0,...) should be added to
+        *        the console_init
+        */
+
+/* lookup table for matching device nodes to index numbers */
+static struct device_node *mpc52xx_uart_nodes[MPC52xx_PSC_MAXNUM];
+
+static void mpc52xx_uart_of_enumerate(void);
+
+
+#define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase))
+
+
+/* Forward declaration of the interruption handling routine */
+static irqreturn_t mpc52xx_uart_int(int irq, void *dev_id);
+static irqreturn_t mpc5xxx_uart_process_int(struct uart_port *port);
+
+
+/* Simple macro to test if a port is console or not. This one is taken
+ * for serial_core.c and maybe should be moved to serial_core.h ? */
+#ifdef CONFIG_SERIAL_CORE_CONSOLE
+#define uart_console(port) \
+       ((port)->cons && (port)->cons->index == (port)->line)
+#else
+#define uart_console(port)     (0)
+#endif
+
+/* ======================================================================== */
+/* PSC fifo operations for isolating differences between 52xx and 512x      */
+/* ======================================================================== */
+
+struct psc_ops {
+       void            (*fifo_init)(struct uart_port *port);
+       int             (*raw_rx_rdy)(struct uart_port *port);
+       int             (*raw_tx_rdy)(struct uart_port *port);
+       int             (*rx_rdy)(struct uart_port *port);
+       int             (*tx_rdy)(struct uart_port *port);
+       int             (*tx_empty)(struct uart_port *port);
+       void            (*stop_rx)(struct uart_port *port);
+       void            (*start_tx)(struct uart_port *port);
+       void            (*stop_tx)(struct uart_port *port);
+       void            (*rx_clr_irq)(struct uart_port *port);
+       void            (*tx_clr_irq)(struct uart_port *port);
+       void            (*write_char)(struct uart_port *port, unsigned char c);
+       unsigned char   (*read_char)(struct uart_port *port);
+       void            (*cw_disable_ints)(struct uart_port *port);
+       void            (*cw_restore_ints)(struct uart_port *port);
+       unsigned int    (*set_baudrate)(struct uart_port *port,
+                                       struct ktermios *new,
+                                       struct ktermios *old);
+       int             (*clock)(struct uart_port *port, int enable);
+       int             (*fifoc_init)(void);
+       void            (*fifoc_uninit)(void);
+       void            (*get_irq)(struct uart_port *, struct device_node *);
+       irqreturn_t     (*handle_irq)(struct uart_port *port);
+};
+
+/* setting the prescaler and divisor reg is common for all chips */
+static inline void mpc52xx_set_divisor(struct mpc52xx_psc __iomem *psc,
+                                      u16 prescaler, unsigned int divisor)
+{
+       /* select prescaler */
+       out_be16(&psc->mpc52xx_psc_clock_select, prescaler);
+       out_8(&psc->ctur, divisor >> 8);
+       out_8(&psc->ctlr, divisor & 0xff);
+}
+
+#ifdef CONFIG_PPC_MPC52xx
+#define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1))
+static void mpc52xx_psc_fifo_init(struct uart_port *port)
+{
+       struct mpc52xx_psc __iomem *psc = PSC(port);
+       struct mpc52xx_psc_fifo __iomem *fifo = FIFO_52xx(port);
+
+       out_8(&fifo->rfcntl, 0x00);
+       out_be16(&fifo->rfalarm, 0x1ff);
+       out_8(&fifo->tfcntl, 0x07);
+       out_be16(&fifo->tfalarm, 0x80);
+
+       port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY;
+       out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
+}
+
+static int mpc52xx_psc_raw_rx_rdy(struct uart_port *port)
+{
+       return in_be16(&PSC(port)->mpc52xx_psc_status)
+           & MPC52xx_PSC_SR_RXRDY;
+}
+
+static int mpc52xx_psc_raw_tx_rdy(struct uart_port *port)
+{
+       return in_be16(&PSC(port)->mpc52xx_psc_status)
+           & MPC52xx_PSC_SR_TXRDY;
+}
+
+
+static int mpc52xx_psc_rx_rdy(struct uart_port *port)
+{
+       return in_be16(&PSC(port)->mpc52xx_psc_isr)
+           & port->read_status_mask
+           & MPC52xx_PSC_IMR_RXRDY;
+}
+
+static int mpc52xx_psc_tx_rdy(struct uart_port *port)
+{
+       return in_be16(&PSC(port)->mpc52xx_psc_isr)
+           & port->read_status_mask
+           & MPC52xx_PSC_IMR_TXRDY;
+}
+
+static int mpc52xx_psc_tx_empty(struct uart_port *port)
+{
+       return in_be16(&PSC(port)->mpc52xx_psc_status)
+           & MPC52xx_PSC_SR_TXEMP;
+}
+
+static void mpc52xx_psc_start_tx(struct uart_port *port)
+{
+       port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
+       out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
+}
+
+static void mpc52xx_psc_stop_tx(struct uart_port *port)
+{
+       port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY;
+       out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
+}
+
+static void mpc52xx_psc_stop_rx(struct uart_port *port)
+{
+       port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY;
+       out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
+}
+
+static void mpc52xx_psc_rx_clr_irq(struct uart_port *port)
+{
+}
+
+static void mpc52xx_psc_tx_clr_irq(struct uart_port *port)
+{
+}
+
+static void mpc52xx_psc_write_char(struct uart_port *port, unsigned char c)
+{
+       out_8(&PSC(port)->mpc52xx_psc_buffer_8, c);
+}
+
+static unsigned char mpc52xx_psc_read_char(struct uart_port *port)
+{
+       return in_8(&PSC(port)->mpc52xx_psc_buffer_8);
+}
+
+static void mpc52xx_psc_cw_disable_ints(struct uart_port *port)
+{
+       out_be16(&PSC(port)->mpc52xx_psc_imr, 0);
+}
+
+static void mpc52xx_psc_cw_restore_ints(struct uart_port *port)
+{
+       out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
+}
+
+static unsigned int mpc5200_psc_set_baudrate(struct uart_port *port,
+                                            struct ktermios *new,
+                                            struct ktermios *old)
+{
+       unsigned int baud;
+       unsigned int divisor;
+
+       /* The 5200 has a fixed /32 prescaler, uartclk contains the ipb freq */
+       baud = uart_get_baud_rate(port, new, old,
+                                 port->uartclk / (32 * 0xffff) + 1,
+                                 port->uartclk / 32);
+       divisor = (port->uartclk + 16 * baud) / (32 * baud);
+
+       /* enable the /32 prescaler and set the divisor */
+       mpc52xx_set_divisor(PSC(port), 0xdd00, divisor);
+       return baud;
+}
+
+static unsigned int mpc5200b_psc_set_baudrate(struct uart_port *port,
+                                             struct ktermios *new,
+                                             struct ktermios *old)
+{
+       unsigned int baud;
+       unsigned int divisor;
+       u16 prescaler;
+
+       /* The 5200B has a selectable /4 or /32 prescaler, uartclk contains the
+        * ipb freq */
+       baud = uart_get_baud_rate(port, new, old,
+                                 port->uartclk / (32 * 0xffff) + 1,
+                                 port->uartclk / 4);
+       divisor = (port->uartclk + 2 * baud) / (4 * baud);
+
+       /* select the proper prescaler and set the divisor */
+       if (divisor > 0xffff) {
+               divisor = (divisor + 4) / 8;
+               prescaler = 0xdd00; /* /32 */
+       } else
+               prescaler = 0xff00; /* /4 */
+       mpc52xx_set_divisor(PSC(port), prescaler, divisor);
+       return baud;
+}
+
+static void mpc52xx_psc_get_irq(struct uart_port *port, struct device_node *np)
+{
+       port->irqflags = IRQF_DISABLED;
+       port->irq = irq_of_parse_and_map(np, 0);
+}
+
+/* 52xx specific interrupt handler. The caller holds the port lock */
+static irqreturn_t mpc52xx_psc_handle_irq(struct uart_port *port)
+{
+       return mpc5xxx_uart_process_int(port);
+}
+
+static struct psc_ops mpc52xx_psc_ops = {
+       .fifo_init = mpc52xx_psc_fifo_init,
+       .raw_rx_rdy = mpc52xx_psc_raw_rx_rdy,
+       .raw_tx_rdy = mpc52xx_psc_raw_tx_rdy,
+       .rx_rdy = mpc52xx_psc_rx_rdy,
+       .tx_rdy = mpc52xx_psc_tx_rdy,
+       .tx_empty = mpc52xx_psc_tx_empty,
+       .stop_rx = mpc52xx_psc_stop_rx,
+       .start_tx = mpc52xx_psc_start_tx,
+       .stop_tx = mpc52xx_psc_stop_tx,
+       .rx_clr_irq = mpc52xx_psc_rx_clr_irq,
+       .tx_clr_irq = mpc52xx_psc_tx_clr_irq,
+       .write_char = mpc52xx_psc_write_char,
+       .read_char = mpc52xx_psc_read_char,
+       .cw_disable_ints = mpc52xx_psc_cw_disable_ints,
+       .cw_restore_ints = mpc52xx_psc_cw_restore_ints,
+       .set_baudrate = mpc5200_psc_set_baudrate,
+       .get_irq = mpc52xx_psc_get_irq,
+       .handle_irq = mpc52xx_psc_handle_irq,
+};
+
+static struct psc_ops mpc5200b_psc_ops = {
+       .fifo_init = mpc52xx_psc_fifo_init,
+       .raw_rx_rdy = mpc52xx_psc_raw_rx_rdy,
+       .raw_tx_rdy = mpc52xx_psc_raw_tx_rdy,
+       .rx_rdy = mpc52xx_psc_rx_rdy,
+       .tx_rdy = mpc52xx_psc_tx_rdy,
+       .tx_empty = mpc52xx_psc_tx_empty,
+       .stop_rx = mpc52xx_psc_stop_rx,
+       .start_tx = mpc52xx_psc_start_tx,
+       .stop_tx = mpc52xx_psc_stop_tx,
+       .rx_clr_irq = mpc52xx_psc_rx_clr_irq,
+       .tx_clr_irq = mpc52xx_psc_tx_clr_irq,
+       .write_char = mpc52xx_psc_write_char,
+       .read_char = mpc52xx_psc_read_char,
+       .cw_disable_ints = mpc52xx_psc_cw_disable_ints,
+       .cw_restore_ints = mpc52xx_psc_cw_restore_ints,
+       .set_baudrate = mpc5200b_psc_set_baudrate,
+       .get_irq = mpc52xx_psc_get_irq,
+       .handle_irq = mpc52xx_psc_handle_irq,
+};
+
+#endif /* CONFIG_MPC52xx */
+
+#ifdef CONFIG_PPC_MPC512x
+#define FIFO_512x(port) ((struct mpc512x_psc_fifo __iomem *)(PSC(port)+1))
+
+/* PSC FIFO Controller for mpc512x */
+struct psc_fifoc {
+       u32 fifoc_cmd;
+       u32 fifoc_int;
+       u32 fifoc_dma;
+       u32 fifoc_axe;
+       u32 fifoc_debug;
+};
+
+static struct psc_fifoc __iomem *psc_fifoc;
+static unsigned int psc_fifoc_irq;
+
+static void mpc512x_psc_fifo_init(struct uart_port *port)
+{
+       /* /32 prescaler */
+       out_be16(&PSC(port)->mpc52xx_psc_clock_select, 0xdd00);
+
+       out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_RESET_SLICE);
+       out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_ENABLE_SLICE);
+       out_be32(&FIFO_512x(port)->txalarm, 1);
+       out_be32(&FIFO_512x(port)->tximr, 0);
+
+       out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_RESET_SLICE);
+       out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_ENABLE_SLICE);
+       out_be32(&FIFO_512x(port)->rxalarm, 1);
+       out_be32(&FIFO_512x(port)->rximr, 0);
+
+       out_be32(&FIFO_512x(port)->tximr, MPC512x_PSC_FIFO_ALARM);
+       out_be32(&FIFO_512x(port)->rximr, MPC512x_PSC_FIFO_ALARM);
+}
+
+static int mpc512x_psc_raw_rx_rdy(struct uart_port *port)
+{
+       return !(in_be32(&FIFO_512x(port)->rxsr) & MPC512x_PSC_FIFO_EMPTY);
+}
+
+static int mpc512x_psc_raw_tx_rdy(struct uart_port *port)
+{
+       return !(in_be32(&FIFO_512x(port)->txsr) & MPC512x_PSC_FIFO_FULL);
+}
+
+static int mpc512x_psc_rx_rdy(struct uart_port *port)
+{
+       return in_be32(&FIFO_512x(port)->rxsr)
+           & in_be32(&FIFO_512x(port)->rximr)
+           & MPC512x_PSC_FIFO_ALARM;
+}
+
+static int mpc512x_psc_tx_rdy(struct uart_port *port)
+{
+       return in_be32(&FIFO_512x(port)->txsr)
+           & in_be32(&FIFO_512x(port)->tximr)
+           & MPC512x_PSC_FIFO_ALARM;
+}
+
+static int mpc512x_psc_tx_empty(struct uart_port *port)
+{
+       return in_be32(&FIFO_512x(port)->txsr)
+           & MPC512x_PSC_FIFO_EMPTY;
+}
+
+static void mpc512x_psc_stop_rx(struct uart_port *port)
+{
+       unsigned long rx_fifo_imr;
+
+       rx_fifo_imr = in_be32(&FIFO_512x(port)->rximr);
+       rx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM;
+       out_be32(&FIFO_512x(port)->rximr, rx_fifo_imr);
+}
+
+static void mpc512x_psc_start_tx(struct uart_port *port)
+{
+       unsigned long tx_fifo_imr;
+
+       tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr);
+       tx_fifo_imr |= MPC512x_PSC_FIFO_ALARM;
+       out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr);
+}
+
+static void mpc512x_psc_stop_tx(struct uart_port *port)
+{
+       unsigned long tx_fifo_imr;
+
+       tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr);
+       tx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM;
+       out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr);
+}
+
+static void mpc512x_psc_rx_clr_irq(struct uart_port *port)
+{
+       out_be32(&FIFO_512x(port)->rxisr, in_be32(&FIFO_512x(port)->rxisr));
+}
+
+static void mpc512x_psc_tx_clr_irq(struct uart_port *port)
+{
+       out_be32(&FIFO_512x(port)->txisr, in_be32(&FIFO_512x(port)->txisr));
+}
+
+static void mpc512x_psc_write_char(struct uart_port *port, unsigned char c)
+{
+       out_8(&FIFO_512x(port)->txdata_8, c);
+}
+
+static unsigned char mpc512x_psc_read_char(struct uart_port *port)
+{
+       return in_8(&FIFO_512x(port)->rxdata_8);
+}
+
+static void mpc512x_psc_cw_disable_ints(struct uart_port *port)
+{
+       port->read_status_mask =
+               in_be32(&FIFO_512x(port)->tximr) << 16 |
+               in_be32(&FIFO_512x(port)->rximr);
+       out_be32(&FIFO_512x(port)->tximr, 0);
+       out_be32(&FIFO_512x(port)->rximr, 0);
+}
+
+static void mpc512x_psc_cw_restore_ints(struct uart_port *port)
+{
+       out_be32(&FIFO_512x(port)->tximr,
+               (port->read_status_mask >> 16) & 0x7f);
+       out_be32(&FIFO_512x(port)->rximr, port->read_status_mask & 0x7f);
+}
+
+static unsigned int mpc512x_psc_set_baudrate(struct uart_port *port,
+                                            struct ktermios *new,
+                                            struct ktermios *old)
+{
+       unsigned int baud;
+       unsigned int divisor;
+
+       /*
+        * The "MPC5121e Microcontroller Reference Manual, Rev. 3" says on
+        * pg. 30-10 that the chip supports a /32 and a /10 prescaler.
+        * Furthermore, it states that "After reset, the prescaler by 10
+        * for the UART mode is selected", but the reset register value is
+        * 0x0000 which means a /32 prescaler. This is wrong.
+        *
+        * In reality using /32 prescaler doesn't work, as it is not supported!
+        * Use /16 or /10 prescaler, see "MPC5121e Hardware Design Guide",
+        * Chapter 4.1 PSC in UART Mode.
+        * Calculate with a /16 prescaler here.
+        */
+
+       /* uartclk contains the ips freq */
+       baud = uart_get_baud_rate(port, new, old,
+                                 port->uartclk / (16 * 0xffff) + 1,
+                                 port->uartclk / 16);
+       divisor = (port->uartclk + 8 * baud) / (16 * baud);
+
+       /* enable the /16 prescaler and set the divisor */
+       mpc52xx_set_divisor(PSC(port), 0xdd00, divisor);
+       return baud;
+}
+
+/* Init PSC FIFO Controller */
+static int __init mpc512x_psc_fifoc_init(void)
+{
+       struct device_node *np;
+
+       np = of_find_compatible_node(NULL, NULL,
+                                    "fsl,mpc5121-psc-fifo");
+       if (!np) {
+               pr_err("%s: Can't find FIFOC node\n", __func__);
+               return -ENODEV;
+       }
+
+       psc_fifoc = of_iomap(np, 0);
+       if (!psc_fifoc) {
+               pr_err("%s: Can't map FIFOC\n", __func__);
+               of_node_put(np);
+               return -ENODEV;
+       }
+
+       psc_fifoc_irq = irq_of_parse_and_map(np, 0);
+       of_node_put(np);
+       if (psc_fifoc_irq == NO_IRQ) {
+               pr_err("%s: Can't get FIFOC irq\n", __func__);
+               iounmap(psc_fifoc);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void __exit mpc512x_psc_fifoc_uninit(void)
+{
+       iounmap(psc_fifoc);
+}
+
+/* 512x specific interrupt handler. The caller holds the port lock */
+static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port)
+{
+       unsigned long fifoc_int;
+       int psc_num;
+
+       /* Read pending PSC FIFOC interrupts */
+       fifoc_int = in_be32(&psc_fifoc->fifoc_int);
+
+       /* Check if it is an interrupt for this port */
+       psc_num = (port->mapbase & 0xf00) >> 8;
+       if (test_bit(psc_num, &fifoc_int) ||
+           test_bit(psc_num + 16, &fifoc_int))
+               return mpc5xxx_uart_process_int(port);
+
+       return IRQ_NONE;
+}
+
+static int mpc512x_psc_clock(struct uart_port *port, int enable)
+{
+       struct clk *psc_clk;
+       int psc_num;
+       char clk_name[10];
+
+       if (uart_console(port))
+               return 0;
+
+       psc_num = (port->mapbase & 0xf00) >> 8;
+       snprintf(clk_name, sizeof(clk_name), "psc%d_clk", psc_num);
+       psc_clk = clk_get(port->dev, clk_name);
+       if (IS_ERR(psc_clk)) {
+               dev_err(port->dev, "Failed to get PSC clock entry!\n");
+               return -ENODEV;
+       }
+
+       dev_dbg(port->dev, "%s %sable\n", clk_name, enable ? "en" : "dis");
+
+       if (enable)
+               clk_enable(psc_clk);
+       else
+               clk_disable(psc_clk);
+
+       return 0;
+}
+
+static void mpc512x_psc_get_irq(struct uart_port *port, struct device_node *np)
+{
+       port->irqflags = IRQF_SHARED;
+       port->irq = psc_fifoc_irq;
+}
+
+static struct psc_ops mpc512x_psc_ops = {
+       .fifo_init = mpc512x_psc_fifo_init,
+       .raw_rx_rdy = mpc512x_psc_raw_rx_rdy,
+       .raw_tx_rdy = mpc512x_psc_raw_tx_rdy,
+       .rx_rdy = mpc512x_psc_rx_rdy,
+       .tx_rdy = mpc512x_psc_tx_rdy,
+       .tx_empty = mpc512x_psc_tx_empty,
+       .stop_rx = mpc512x_psc_stop_rx,
+       .start_tx = mpc512x_psc_start_tx,
+       .stop_tx = mpc512x_psc_stop_tx,
+       .rx_clr_irq = mpc512x_psc_rx_clr_irq,
+       .tx_clr_irq = mpc512x_psc_tx_clr_irq,
+       .write_char = mpc512x_psc_write_char,
+       .read_char = mpc512x_psc_read_char,
+       .cw_disable_ints = mpc512x_psc_cw_disable_ints,
+       .cw_restore_ints = mpc512x_psc_cw_restore_ints,
+       .set_baudrate = mpc512x_psc_set_baudrate,
+       .clock = mpc512x_psc_clock,
+       .fifoc_init = mpc512x_psc_fifoc_init,
+       .fifoc_uninit = mpc512x_psc_fifoc_uninit,
+       .get_irq = mpc512x_psc_get_irq,
+       .handle_irq = mpc512x_psc_handle_irq,
+};
+#endif
+
+static struct psc_ops *psc_ops;
+
+/* ======================================================================== */
+/* UART operations                                                          */
+/* ======================================================================== */
+
+static unsigned int
+mpc52xx_uart_tx_empty(struct uart_port *port)
+{
+       return psc_ops->tx_empty(port) ? TIOCSER_TEMT : 0;
+}
+
+static void
+mpc52xx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       if (mctrl & TIOCM_RTS)
+               out_8(&PSC(port)->op1, MPC52xx_PSC_OP_RTS);
+       else
+               out_8(&PSC(port)->op0, MPC52xx_PSC_OP_RTS);
+}
+
+static unsigned int
+mpc52xx_uart_get_mctrl(struct uart_port *port)
+{
+       unsigned int ret = TIOCM_DSR;
+       u8 status = in_8(&PSC(port)->mpc52xx_psc_ipcr);
+
+       if (!(status & MPC52xx_PSC_CTS))
+               ret |= TIOCM_CTS;
+       if (!(status & MPC52xx_PSC_DCD))
+               ret |= TIOCM_CAR;
+
+       return ret;
+}
+
+static void
+mpc52xx_uart_stop_tx(struct uart_port *port)
+{
+       /* port->lock taken by caller */
+       psc_ops->stop_tx(port);
+}
+
+static void
+mpc52xx_uart_start_tx(struct uart_port *port)
+{
+       /* port->lock taken by caller */
+       psc_ops->start_tx(port);
+}
+
+static void
+mpc52xx_uart_send_xchar(struct uart_port *port, char ch)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&port->lock, flags);
+
+       port->x_char = ch;
+       if (ch) {
+               /* Make sure tx interrupts are on */
+               /* Truly necessary ??? They should be anyway */
+               psc_ops->start_tx(port);
+       }
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void
+mpc52xx_uart_stop_rx(struct uart_port *port)
+{
+       /* port->lock taken by caller */
+       psc_ops->stop_rx(port);
+}
+
+static void
+mpc52xx_uart_enable_ms(struct uart_port *port)
+{
+       struct mpc52xx_psc __iomem *psc = PSC(port);
+
+       /* clear D_*-bits by reading them */
+       in_8(&psc->mpc52xx_psc_ipcr);
+       /* enable CTS and DCD as IPC interrupts */
+       out_8(&psc->mpc52xx_psc_acr, MPC52xx_PSC_IEC_CTS | MPC52xx_PSC_IEC_DCD);
+
+       port->read_status_mask |= MPC52xx_PSC_IMR_IPC;
+       out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
+}
+
+static void
+mpc52xx_uart_break_ctl(struct uart_port *port, int ctl)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&port->lock, flags);
+
+       if (ctl == -1)
+               out_8(&PSC(port)->command, MPC52xx_PSC_START_BRK);
+       else
+               out_8(&PSC(port)->command, MPC52xx_PSC_STOP_BRK);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int
+mpc52xx_uart_startup(struct uart_port *port)
+{
+       struct mpc52xx_psc __iomem *psc = PSC(port);
+       int ret;
+
+       if (psc_ops->clock) {
+               ret = psc_ops->clock(port, 1);
+               if (ret)
+                       return ret;
+       }
+
+       /* Request IRQ */
+       ret = request_irq(port->irq, mpc52xx_uart_int,
+                         port->irqflags, "mpc52xx_psc_uart", port);
+       if (ret)
+               return ret;
+
+       /* Reset/activate the port, clear and enable interrupts */
+       out_8(&psc->command, MPC52xx_PSC_RST_RX);
+       out_8(&psc->command, MPC52xx_PSC_RST_TX);
+
+       out_be32(&psc->sicr, 0);        /* UART mode DCD ignored */
+
+       psc_ops->fifo_init(port);
+
+       out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
+       out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
+
+       return 0;
+}
+
+static void
+mpc52xx_uart_shutdown(struct uart_port *port)
+{
+       struct mpc52xx_psc __iomem *psc = PSC(port);
+
+       /* Shut down the port.  Leave TX active if on a console port */
+       out_8(&psc->command, MPC52xx_PSC_RST_RX);
+       if (!uart_console(port))
+               out_8(&psc->command, MPC52xx_PSC_RST_TX);
+
+       port->read_status_mask = 0;
+       out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
+
+       if (psc_ops->clock)
+               psc_ops->clock(port, 0);
+
+       /* Release interrupt */
+       free_irq(port->irq, port);
+}
+
+static void
+mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
+                        struct ktermios *old)
+{
+       struct mpc52xx_psc __iomem *psc = PSC(port);
+       unsigned long flags;
+       unsigned char mr1, mr2;
+       unsigned int j;
+       unsigned int baud;
+
+       /* Prepare what we're gonna write */
+       mr1 = 0;
+
+       switch (new->c_cflag & CSIZE) {
+       case CS5:       mr1 |= MPC52xx_PSC_MODE_5_BITS;
+               break;
+       case CS6:       mr1 |= MPC52xx_PSC_MODE_6_BITS;
+               break;
+       case CS7:       mr1 |= MPC52xx_PSC_MODE_7_BITS;
+               break;
+       case CS8:
+       default:        mr1 |= MPC52xx_PSC_MODE_8_BITS;
+       }
+
+       if (new->c_cflag & PARENB) {
+               mr1 |= (new->c_cflag & PARODD) ?
+                       MPC52xx_PSC_MODE_PARODD : MPC52xx_PSC_MODE_PAREVEN;
+       } else
+               mr1 |= MPC52xx_PSC_MODE_PARNONE;
+
+
+       mr2 = 0;
+
+       if (new->c_cflag & CSTOPB)
+               mr2 |= MPC52xx_PSC_MODE_TWO_STOP;
+       else
+               mr2 |= ((new->c_cflag & CSIZE) == CS5) ?
+                       MPC52xx_PSC_MODE_ONE_STOP_5_BITS :
+                       MPC52xx_PSC_MODE_ONE_STOP;
+
+       if (new->c_cflag & CRTSCTS) {
+               mr1 |= MPC52xx_PSC_MODE_RXRTS;
+               mr2 |= MPC52xx_PSC_MODE_TXCTS;
+       }
+
+       /* Get the lock */
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Do our best to flush TX & RX, so we don't lose anything */
+       /* But we don't wait indefinitely ! */
+       j = 5000000;    /* Maximum wait */
+       /* FIXME Can't receive chars since set_termios might be called at early
+        * boot for the console, all stuff is not yet ready to receive at that
+        * time and that just makes the kernel oops */
+       /* while (j-- && mpc52xx_uart_int_rx_chars(port)); */
+       while (!mpc52xx_uart_tx_empty(port) && --j)
+               udelay(1);
+
+       if (!j)
+               printk(KERN_ERR "mpc52xx_uart.c: "
+                       "Unable to flush RX & TX fifos in-time in set_termios."
+                       "Some chars may have been lost.\n");
+
+       /* Reset the TX & RX */
+       out_8(&psc->command, MPC52xx_PSC_RST_RX);
+       out_8(&psc->command, MPC52xx_PSC_RST_TX);
+
+       /* Send new mode settings */
+       out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
+       out_8(&psc->mode, mr1);
+       out_8(&psc->mode, mr2);
+       baud = psc_ops->set_baudrate(port, new, old);
+
+       /* Update the per-port timeout */
+       uart_update_timeout(port, new->c_cflag, baud);
+
+       if (UART_ENABLE_MS(port, new->c_cflag))
+               mpc52xx_uart_enable_ms(port);
+
+       /* Reenable TX & RX */
+       out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
+       out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
+
+       /* We're all set, release the lock */
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *
+mpc52xx_uart_type(struct uart_port *port)
+{
+       /*
+        * We keep using PORT_MPC52xx for historic reasons although it applies
+        * for MPC512x, too, but print "MPC5xxx" to not irritate users
+        */
+       return port->type == PORT_MPC52xx ? "MPC5xxx PSC" : NULL;
+}
+
+static void
+mpc52xx_uart_release_port(struct uart_port *port)
+{
+       /* remapped by us ? */
+       if (port->flags & UPF_IOREMAP) {
+               iounmap(port->membase);
+               port->membase = NULL;
+       }
+
+       release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc));
+}
+
+static int
+mpc52xx_uart_request_port(struct uart_port *port)
+{
+       int err;
+
+       if (port->flags & UPF_IOREMAP) /* Need to remap ? */
+               port->membase = ioremap(port->mapbase,
+                                       sizeof(struct mpc52xx_psc));
+
+       if (!port->membase)
+               return -EINVAL;
+
+       err = request_mem_region(port->mapbase, sizeof(struct mpc52xx_psc),
+                       "mpc52xx_psc_uart") != NULL ? 0 : -EBUSY;
+
+       if (err && (port->flags & UPF_IOREMAP)) {
+               iounmap(port->membase);
+               port->membase = NULL;
+       }
+
+       return err;
+}
+
+static void
+mpc52xx_uart_config_port(struct uart_port *port, int flags)
+{
+       if ((flags & UART_CONFIG_TYPE)
+               && (mpc52xx_uart_request_port(port) == 0))
+               port->type = PORT_MPC52xx;
+}
+
+static int
+mpc52xx_uart_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_MPC52xx)
+               return -EINVAL;
+
+       if ((ser->irq != port->irq) ||
+           (ser->io_type != UPIO_MEM) ||
+           (ser->baud_base != port->uartclk)  ||
+           (ser->iomem_base != (void *)port->mapbase) ||
+           (ser->hub6 != 0))
+               return -EINVAL;
+
+       return 0;
+}
+
+
+static struct uart_ops mpc52xx_uart_ops = {
+       .tx_empty       = mpc52xx_uart_tx_empty,
+       .set_mctrl      = mpc52xx_uart_set_mctrl,
+       .get_mctrl      = mpc52xx_uart_get_mctrl,
+       .stop_tx        = mpc52xx_uart_stop_tx,
+       .start_tx       = mpc52xx_uart_start_tx,
+       .send_xchar     = mpc52xx_uart_send_xchar,
+       .stop_rx        = mpc52xx_uart_stop_rx,
+       .enable_ms      = mpc52xx_uart_enable_ms,
+       .break_ctl      = mpc52xx_uart_break_ctl,
+       .startup        = mpc52xx_uart_startup,
+       .shutdown       = mpc52xx_uart_shutdown,
+       .set_termios    = mpc52xx_uart_set_termios,
+/*     .pm             = mpc52xx_uart_pm,              Not supported yet */
+/*     .set_wake       = mpc52xx_uart_set_wake,        Not supported yet */
+       .type           = mpc52xx_uart_type,
+       .release_port   = mpc52xx_uart_release_port,
+       .request_port   = mpc52xx_uart_request_port,
+       .config_port    = mpc52xx_uart_config_port,
+       .verify_port    = mpc52xx_uart_verify_port
+};
+
+
+/* ======================================================================== */
+/* Interrupt handling                                                       */
+/* ======================================================================== */
+
+static inline int
+mpc52xx_uart_int_rx_chars(struct uart_port *port)
+{
+       struct tty_struct *tty = port->state->port.tty;
+       unsigned char ch, flag;
+       unsigned short status;
+
+       /* While we can read, do so ! */
+       while (psc_ops->raw_rx_rdy(port)) {
+               /* Get the char */
+               ch = psc_ops->read_char(port);
+
+               /* Handle sysreq char */
+#ifdef SUPPORT_SYSRQ
+               if (uart_handle_sysrq_char(port, ch)) {
+                       port->sysrq = 0;
+                       continue;
+               }
+#endif
+
+               /* Store it */
+
+               flag = TTY_NORMAL;
+               port->icount.rx++;
+
+               status = in_be16(&PSC(port)->mpc52xx_psc_status);
+
+               if (status & (MPC52xx_PSC_SR_PE |
+                             MPC52xx_PSC_SR_FE |
+                             MPC52xx_PSC_SR_RB)) {
+
+                       if (status & MPC52xx_PSC_SR_RB) {
+                               flag = TTY_BREAK;
+                               uart_handle_break(port);
+                               port->icount.brk++;
+                       } else if (status & MPC52xx_PSC_SR_PE) {
+                               flag = TTY_PARITY;
+                               port->icount.parity++;
+                       }
+                       else if (status & MPC52xx_PSC_SR_FE) {
+                               flag = TTY_FRAME;
+                               port->icount.frame++;
+                       }
+
+                       /* Clear error condition */
+                       out_8(&PSC(port)->command, MPC52xx_PSC_RST_ERR_STAT);
+
+               }
+               tty_insert_flip_char(tty, ch, flag);
+               if (status & MPC52xx_PSC_SR_OE) {
+                       /*
+                        * Overrun is special, since it's
+                        * reported immediately, and doesn't
+                        * affect the current character
+                        */
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+                       port->icount.overrun++;
+               }
+       }
+
+       spin_unlock(&port->lock);
+       tty_flip_buffer_push(tty);
+       spin_lock(&port->lock);
+
+       return psc_ops->raw_rx_rdy(port);
+}
+
+static inline int
+mpc52xx_uart_int_tx_chars(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->state->xmit;
+
+       /* Process out of band chars */
+       if (port->x_char) {
+               psc_ops->write_char(port, port->x_char);
+               port->icount.tx++;
+               port->x_char = 0;
+               return 1;
+       }
+
+       /* Nothing to do ? */
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               mpc52xx_uart_stop_tx(port);
+               return 0;
+       }
+
+       /* Send chars */
+       while (psc_ops->raw_tx_rdy(port)) {
+               psc_ops->write_char(port, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       }
+
+       /* Wake up */
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       /* Maybe we're done after all */
+       if (uart_circ_empty(xmit)) {
+               mpc52xx_uart_stop_tx(port);
+               return 0;
+       }
+
+       return 1;
+}
+
+static irqreturn_t
+mpc5xxx_uart_process_int(struct uart_port *port)
+{
+       unsigned long pass = ISR_PASS_LIMIT;
+       unsigned int keepgoing;
+       u8 status;
+
+       /* While we have stuff to do, we continue */
+       do {
+               /* If we don't find anything to do, we stop */
+               keepgoing = 0;
+
+               psc_ops->rx_clr_irq(port);
+               if (psc_ops->rx_rdy(port))
+                       keepgoing |= mpc52xx_uart_int_rx_chars(port);
+
+               psc_ops->tx_clr_irq(port);
+               if (psc_ops->tx_rdy(port))
+                       keepgoing |= mpc52xx_uart_int_tx_chars(port);
+
+               status = in_8(&PSC(port)->mpc52xx_psc_ipcr);
+               if (status & MPC52xx_PSC_D_DCD)
+                       uart_handle_dcd_change(port, !(status & MPC52xx_PSC_DCD));
+
+               if (status & MPC52xx_PSC_D_CTS)
+                       uart_handle_cts_change(port, !(status & MPC52xx_PSC_CTS));
+
+               /* Limit number of iteration */
+               if (!(--pass))
+                       keepgoing = 0;
+
+       } while (keepgoing);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t
+mpc52xx_uart_int(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       irqreturn_t ret;
+
+       spin_lock(&port->lock);
+
+       ret = psc_ops->handle_irq(port);
+
+       spin_unlock(&port->lock);
+
+       return ret;
+}
+
+/* ======================================================================== */
+/* Console ( if applicable )                                                */
+/* ======================================================================== */
+
+#ifdef CONFIG_SERIAL_MPC52xx_CONSOLE
+
+static void __init
+mpc52xx_console_get_options(struct uart_port *port,
+                           int *baud, int *parity, int *bits, int *flow)
+{
+       struct mpc52xx_psc __iomem *psc = PSC(port);
+       unsigned char mr1;
+
+       pr_debug("mpc52xx_console_get_options(port=%p)\n", port);
+
+       /* Read the mode registers */
+       out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
+       mr1 = in_8(&psc->mode);
+
+       /* CT{U,L}R are write-only ! */
+       *baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
+
+       /* Parse them */
+       switch (mr1 & MPC52xx_PSC_MODE_BITS_MASK) {
+       case MPC52xx_PSC_MODE_5_BITS:
+               *bits = 5;
+               break;
+       case MPC52xx_PSC_MODE_6_BITS:
+               *bits = 6;
+               break;
+       case MPC52xx_PSC_MODE_7_BITS:
+               *bits = 7;
+               break;
+       case MPC52xx_PSC_MODE_8_BITS:
+       default:
+               *bits = 8;
+       }
+
+       if (mr1 & MPC52xx_PSC_MODE_PARNONE)
+               *parity = 'n';
+       else
+               *parity = mr1 & MPC52xx_PSC_MODE_PARODD ? 'o' : 'e';
+}
+
+static void
+mpc52xx_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct uart_port *port = &mpc52xx_uart_ports[co->index];
+       unsigned int i, j;
+
+       /* Disable interrupts */
+       psc_ops->cw_disable_ints(port);
+
+       /* Wait the TX buffer to be empty */
+       j = 5000000;    /* Maximum wait */
+       while (!mpc52xx_uart_tx_empty(port) && --j)
+               udelay(1);
+
+       /* Write all the chars */
+       for (i = 0; i < count; i++, s++) {
+               /* Line return handling */
+               if (*s == '\n')
+                       psc_ops->write_char(port, '\r');
+
+               /* Send the char */
+               psc_ops->write_char(port, *s);
+
+               /* Wait the TX buffer to be empty */
+               j = 20000;      /* Maximum wait */
+               while (!mpc52xx_uart_tx_empty(port) && --j)
+                       udelay(1);
+       }
+
+       /* Restore interrupt state */
+       psc_ops->cw_restore_ints(port);
+}
+
+
+static int __init
+mpc52xx_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port = &mpc52xx_uart_ports[co->index];
+       struct device_node *np = mpc52xx_uart_nodes[co->index];
+       unsigned int uartclk;
+       struct resource res;
+       int ret;
+
+       int baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       pr_debug("mpc52xx_console_setup co=%p, co->index=%i, options=%s\n",
+                co, co->index, options);
+
+       if ((co->index < 0) || (co->index >= MPC52xx_PSC_MAXNUM)) {
+               pr_debug("PSC%x out of range\n", co->index);
+               return -EINVAL;
+       }
+
+       if (!np) {
+               pr_debug("PSC%x not found in device tree\n", co->index);
+               return -EINVAL;
+       }
+
+       pr_debug("Console on ttyPSC%x is %s\n",
+                co->index, mpc52xx_uart_nodes[co->index]->full_name);
+
+       /* Fetch register locations */
+       ret = of_address_to_resource(np, 0, &res);
+       if (ret) {
+               pr_debug("Could not get resources for PSC%x\n", co->index);
+               return ret;
+       }
+
+       uartclk = mpc5xxx_get_bus_frequency(np);
+       if (uartclk == 0) {
+               pr_debug("Could not find uart clock frequency!\n");
+               return -EINVAL;
+       }
+
+       /* Basic port init. Needed since we use some uart_??? func before
+        * real init for early access */
+       spin_lock_init(&port->lock);
+       port->uartclk = uartclk;
+       port->ops       = &mpc52xx_uart_ops;
+       port->mapbase = res.start;
+       port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc));
+       port->irq = irq_of_parse_and_map(np, 0);
+
+       if (port->membase == NULL)
+               return -EINVAL;
+
+       pr_debug("mpc52xx-psc uart at %p, mapped to %p, irq=%x, freq=%i\n",
+                (void *)port->mapbase, port->membase,
+                port->irq, port->uartclk);
+
+       /* Setup the port parameters accoding to options */
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               mpc52xx_console_get_options(port, &baud, &parity, &bits, &flow);
+
+       pr_debug("Setting console parameters: %i %i%c1 flow=%c\n",
+                baud, bits, parity, flow);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+
+static struct uart_driver mpc52xx_uart_driver;
+
+static struct console mpc52xx_console = {
+       .name   = "ttyPSC",
+       .write  = mpc52xx_console_write,
+       .device = uart_console_device,
+       .setup  = mpc52xx_console_setup,
+       .flags  = CON_PRINTBUFFER,
+       .index  = -1,   /* Specified on the cmdline (e.g. console=ttyPSC0) */
+       .data   = &mpc52xx_uart_driver,
+};
+
+
+static int __init
+mpc52xx_console_init(void)
+{
+       mpc52xx_uart_of_enumerate();
+       register_console(&mpc52xx_console);
+       return 0;
+}
+
+console_initcall(mpc52xx_console_init);
+
+#define MPC52xx_PSC_CONSOLE &mpc52xx_console
+#else
+#define MPC52xx_PSC_CONSOLE NULL
+#endif
+
+
+/* ======================================================================== */
+/* UART Driver                                                              */
+/* ======================================================================== */
+
+static struct uart_driver mpc52xx_uart_driver = {
+       .driver_name    = "mpc52xx_psc_uart",
+       .dev_name       = "ttyPSC",
+       .major          = SERIAL_PSC_MAJOR,
+       .minor          = SERIAL_PSC_MINOR,
+       .nr             = MPC52xx_PSC_MAXNUM,
+       .cons           = MPC52xx_PSC_CONSOLE,
+};
+
+/* ======================================================================== */
+/* OF Platform Driver                                                       */
+/* ======================================================================== */
+
+static struct of_device_id mpc52xx_uart_of_match[] = {
+#ifdef CONFIG_PPC_MPC52xx
+       { .compatible = "fsl,mpc5200b-psc-uart", .data = &mpc5200b_psc_ops, },
+       { .compatible = "fsl,mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
+       /* binding used by old lite5200 device trees: */
+       { .compatible = "mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
+       /* binding used by efika: */
+       { .compatible = "mpc5200-serial", .data = &mpc52xx_psc_ops, },
+#endif
+#ifdef CONFIG_PPC_MPC512x
+       { .compatible = "fsl,mpc5121-psc-uart", .data = &mpc512x_psc_ops, },
+#endif
+       {},
+};
+
+static int __devinit
+mpc52xx_uart_of_probe(struct platform_device *op, const struct of_device_id *match)
+{
+       int idx = -1;
+       unsigned int uartclk;
+       struct uart_port *port = NULL;
+       struct resource res;
+       int ret;
+
+       dev_dbg(&op->dev, "mpc52xx_uart_probe(op=%p, match=%p)\n", op, match);
+
+       /* Check validity & presence */
+       for (idx = 0; idx < MPC52xx_PSC_MAXNUM; idx++)
+               if (mpc52xx_uart_nodes[idx] == op->dev.of_node)
+                       break;
+       if (idx >= MPC52xx_PSC_MAXNUM)
+               return -EINVAL;
+       pr_debug("Found %s assigned to ttyPSC%x\n",
+                mpc52xx_uart_nodes[idx]->full_name, idx);
+
+       /* set the uart clock to the input clock of the psc, the different
+        * prescalers are taken into account in the set_baudrate() methods
+        * of the respective chip */
+       uartclk = mpc5xxx_get_bus_frequency(op->dev.of_node);
+       if (uartclk == 0) {
+               dev_dbg(&op->dev, "Could not find uart clock frequency!\n");
+               return -EINVAL;
+       }
+
+       /* Init the port structure */
+       port = &mpc52xx_uart_ports[idx];
+
+       spin_lock_init(&port->lock);
+       port->uartclk = uartclk;
+       port->fifosize  = 512;
+       port->iotype    = UPIO_MEM;
+       port->flags     = UPF_BOOT_AUTOCONF |
+                         (uart_console(port) ? 0 : UPF_IOREMAP);
+       port->line      = idx;
+       port->ops       = &mpc52xx_uart_ops;
+       port->dev       = &op->dev;
+
+       /* Search for IRQ and mapbase */
+       ret = of_address_to_resource(op->dev.of_node, 0, &res);
+       if (ret)
+               return ret;
+
+       port->mapbase = res.start;
+       if (!port->mapbase) {
+               dev_dbg(&op->dev, "Could not allocate resources for PSC\n");
+               return -EINVAL;
+       }
+
+       psc_ops->get_irq(port, op->dev.of_node);
+       if (port->irq == NO_IRQ) {
+               dev_dbg(&op->dev, "Could not get irq\n");
+               return -EINVAL;
+       }
+
+       dev_dbg(&op->dev, "mpc52xx-psc uart at %p, irq=%x, freq=%i\n",
+               (void *)port->mapbase, port->irq, port->uartclk);
+
+       /* Add the port to the uart sub-system */
+       ret = uart_add_one_port(&mpc52xx_uart_driver, port);
+       if (ret)
+               return ret;
+
+       dev_set_drvdata(&op->dev, (void *)port);
+       return 0;
+}
+
+static int
+mpc52xx_uart_of_remove(struct platform_device *op)
+{
+       struct uart_port *port = dev_get_drvdata(&op->dev);
+       dev_set_drvdata(&op->dev, NULL);
+
+       if (port)
+               uart_remove_one_port(&mpc52xx_uart_driver, port);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int
+mpc52xx_uart_of_suspend(struct platform_device *op, pm_message_t state)
+{
+       struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev);
+
+       if (port)
+               uart_suspend_port(&mpc52xx_uart_driver, port);
+
+       return 0;
+}
+
+static int
+mpc52xx_uart_of_resume(struct platform_device *op)
+{
+       struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev);
+
+       if (port)
+               uart_resume_port(&mpc52xx_uart_driver, port);
+
+       return 0;
+}
+#endif
+
+static void
+mpc52xx_uart_of_assign(struct device_node *np)
+{
+       int i;
+
+       /* Find the first free PSC number */
+       for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) {
+               if (mpc52xx_uart_nodes[i] == NULL) {
+                       of_node_get(np);
+                       mpc52xx_uart_nodes[i] = np;
+                       return;
+               }
+       }
+}
+
+static void
+mpc52xx_uart_of_enumerate(void)
+{
+       static int enum_done;
+       struct device_node *np;
+       const struct  of_device_id *match;
+       int i;
+
+       if (enum_done)
+               return;
+
+       /* Assign index to each PSC in device tree */
+       for_each_matching_node(np, mpc52xx_uart_of_match) {
+               match = of_match_node(mpc52xx_uart_of_match, np);
+               psc_ops = match->data;
+               mpc52xx_uart_of_assign(np);
+       }
+
+       enum_done = 1;
+
+       for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) {
+               if (mpc52xx_uart_nodes[i])
+                       pr_debug("%s assigned to ttyPSC%x\n",
+                                mpc52xx_uart_nodes[i]->full_name, i);
+       }
+}
+
+MODULE_DEVICE_TABLE(of, mpc52xx_uart_of_match);
+
+static struct of_platform_driver mpc52xx_uart_of_driver = {
+       .probe          = mpc52xx_uart_of_probe,
+       .remove         = mpc52xx_uart_of_remove,
+#ifdef CONFIG_PM
+       .suspend        = mpc52xx_uart_of_suspend,
+       .resume         = mpc52xx_uart_of_resume,
+#endif
+       .driver = {
+               .name = "mpc52xx-psc-uart",
+               .owner = THIS_MODULE,
+               .of_match_table = mpc52xx_uart_of_match,
+       },
+};
+
+
+/* ======================================================================== */
+/* Module                                                                   */
+/* ======================================================================== */
+
+static int __init
+mpc52xx_uart_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "Serial: MPC52xx PSC UART driver\n");
+
+       ret = uart_register_driver(&mpc52xx_uart_driver);
+       if (ret) {
+               printk(KERN_ERR "%s: uart_register_driver failed (%i)\n",
+                      __FILE__, ret);
+               return ret;
+       }
+
+       mpc52xx_uart_of_enumerate();
+
+       /*
+        * Map the PSC FIFO Controller and init if on MPC512x.
+        */
+       if (psc_ops && psc_ops->fifoc_init) {
+               ret = psc_ops->fifoc_init();
+               if (ret)
+                       return ret;
+       }
+
+       ret = of_register_platform_driver(&mpc52xx_uart_of_driver);
+       if (ret) {
+               printk(KERN_ERR "%s: of_register_platform_driver failed (%i)\n",
+                      __FILE__, ret);
+               uart_unregister_driver(&mpc52xx_uart_driver);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void __exit
+mpc52xx_uart_exit(void)
+{
+       if (psc_ops->fifoc_uninit)
+               psc_ops->fifoc_uninit();
+
+       of_unregister_platform_driver(&mpc52xx_uart_of_driver);
+       uart_unregister_driver(&mpc52xx_uart_driver);
+}
+
+
+module_init(mpc52xx_uart_init);
+module_exit(mpc52xx_uart_exit);
+
+MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>");
+MODULE_DESCRIPTION("Freescale MPC52xx PSC UART");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/mpsc.c b/drivers/tty/serial/mpsc.c
new file mode 100644 (file)
index 0000000..6a9c660
--- /dev/null
@@ -0,0 +1,2159 @@
+/*
+ * Generic driver for the MPSC (UART mode) on Marvell parts (e.g., GT64240,
+ * GT64260, MV64340, MV64360, GT96100, ... ).
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * Based on an old MPSC driver that was in the linuxppc tree.  It appears to
+ * have been created by Chris Zankel (formerly of MontaVista) but there
+ * is no proper Copyright so I'm not sure.  Apparently, parts were also
+ * taken from PPCBoot (now U-Boot).  Also based on drivers/serial/8250.c
+ * by Russell King.
+ *
+ * 2004 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+/*
+ * The MPSC interface is much like a typical network controller's interface.
+ * That is, you set up separate rings of descriptors for transmitting and
+ * receiving data.  There is also a pool of buffers with (one buffer per
+ * descriptor) that incoming data are dma'd into or outgoing data are dma'd
+ * out of.
+ *
+ * The MPSC requires two other controllers to be able to work.  The Baud Rate
+ * Generator (BRG) provides a clock at programmable frequencies which determines
+ * the baud rate.  The Serial DMA Controller (SDMA) takes incoming data from the
+ * MPSC and DMA's it into memory or DMA's outgoing data and passes it to the
+ * MPSC.  It is actually the SDMA interrupt that the driver uses to keep the
+ * transmit and receive "engines" going (i.e., indicate data has been
+ * transmitted or received).
+ *
+ * NOTES:
+ *
+ * 1) Some chips have an erratum where several regs cannot be
+ * read.  To work around that, we keep a local copy of those regs in
+ * 'mpsc_port_info'.
+ *
+ * 2) Some chips have an erratum where the ctlr will hang when the SDMA ctlr
+ * accesses system mem with coherency enabled.  For that reason, the driver
+ * assumes that coherency for that ctlr has been disabled.  This means
+ * that when in a cache coherent system, the driver has to manually manage
+ * the data cache on the areas that it touches because the dma_* macro are
+ * basically no-ops.
+ *
+ * 3) There is an erratum (on PPC) where you can't use the instruction to do
+ * a DMA_TO_DEVICE/cache clean so DMA_BIDIRECTIONAL/flushes are used in places
+ * where a DMA_TO_DEVICE/clean would have [otherwise] sufficed.
+ *
+ * 4) AFAICT, hardware flow control isn't supported by the controller --MAG.
+ */
+
+
+#if defined(CONFIG_SERIAL_MPSC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/mv643xx.h>
+#include <linux/platform_device.h>
+#include <linux/gfp.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#define        MPSC_NUM_CTLRS          2
+
+/*
+ * Descriptors and buffers must be cache line aligned.
+ * Buffers lengths must be multiple of cache line size.
+ * Number of Tx & Rx descriptors must be powers of 2.
+ */
+#define        MPSC_RXR_ENTRIES        32
+#define        MPSC_RXRE_SIZE          dma_get_cache_alignment()
+#define        MPSC_RXR_SIZE           (MPSC_RXR_ENTRIES * MPSC_RXRE_SIZE)
+#define        MPSC_RXBE_SIZE          dma_get_cache_alignment()
+#define        MPSC_RXB_SIZE           (MPSC_RXR_ENTRIES * MPSC_RXBE_SIZE)
+
+#define        MPSC_TXR_ENTRIES        32
+#define        MPSC_TXRE_SIZE          dma_get_cache_alignment()
+#define        MPSC_TXR_SIZE           (MPSC_TXR_ENTRIES * MPSC_TXRE_SIZE)
+#define        MPSC_TXBE_SIZE          dma_get_cache_alignment()
+#define        MPSC_TXB_SIZE           (MPSC_TXR_ENTRIES * MPSC_TXBE_SIZE)
+
+#define        MPSC_DMA_ALLOC_SIZE     (MPSC_RXR_SIZE + MPSC_RXB_SIZE + MPSC_TXR_SIZE \
+               + MPSC_TXB_SIZE + dma_get_cache_alignment() /* for alignment */)
+
+/* Rx and Tx Ring entry descriptors -- assume entry size is <= cacheline size */
+struct mpsc_rx_desc {
+       u16 bufsize;
+       u16 bytecnt;
+       u32 cmdstat;
+       u32 link;
+       u32 buf_ptr;
+} __attribute((packed));
+
+struct mpsc_tx_desc {
+       u16 bytecnt;
+       u16 shadow;
+       u32 cmdstat;
+       u32 link;
+       u32 buf_ptr;
+} __attribute((packed));
+
+/*
+ * Some regs that have the erratum that you can't read them are are shared
+ * between the two MPSC controllers.  This struct contains those shared regs.
+ */
+struct mpsc_shared_regs {
+       phys_addr_t mpsc_routing_base_p;
+       phys_addr_t sdma_intr_base_p;
+
+       void __iomem *mpsc_routing_base;
+       void __iomem *sdma_intr_base;
+
+       u32 MPSC_MRR_m;
+       u32 MPSC_RCRR_m;
+       u32 MPSC_TCRR_m;
+       u32 SDMA_INTR_CAUSE_m;
+       u32 SDMA_INTR_MASK_m;
+};
+
+/* The main driver data structure */
+struct mpsc_port_info {
+       struct uart_port port;  /* Overlay uart_port structure */
+
+       /* Internal driver state for this ctlr */
+       u8 ready;
+       u8 rcv_data;
+       tcflag_t c_iflag;       /* save termios->c_iflag */
+       tcflag_t c_cflag;       /* save termios->c_cflag */
+
+       /* Info passed in from platform */
+       u8 mirror_regs;         /* Need to mirror regs? */
+       u8 cache_mgmt;          /* Need manual cache mgmt? */
+       u8 brg_can_tune;        /* BRG has baud tuning? */
+       u32 brg_clk_src;
+       u16 mpsc_max_idle;
+       int default_baud;
+       int default_bits;
+       int default_parity;
+       int default_flow;
+
+       /* Physical addresses of various blocks of registers (from platform) */
+       phys_addr_t mpsc_base_p;
+       phys_addr_t sdma_base_p;
+       phys_addr_t brg_base_p;
+
+       /* Virtual addresses of various blocks of registers (from platform) */
+       void __iomem *mpsc_base;
+       void __iomem *sdma_base;
+       void __iomem *brg_base;
+
+       /* Descriptor ring and buffer allocations */
+       void *dma_region;
+       dma_addr_t dma_region_p;
+
+       dma_addr_t rxr;         /* Rx descriptor ring */
+       dma_addr_t rxr_p;       /* Phys addr of rxr */
+       u8 *rxb;                /* Rx Ring I/O buf */
+       u8 *rxb_p;              /* Phys addr of rxb */
+       u32 rxr_posn;           /* First desc w/ Rx data */
+
+       dma_addr_t txr;         /* Tx descriptor ring */
+       dma_addr_t txr_p;       /* Phys addr of txr */
+       u8 *txb;                /* Tx Ring I/O buf */
+       u8 *txb_p;              /* Phys addr of txb */
+       int txr_head;           /* Where new data goes */
+       int txr_tail;           /* Where sent data comes off */
+       spinlock_t tx_lock;     /* transmit lock */
+
+       /* Mirrored values of regs we can't read (if 'mirror_regs' set) */
+       u32 MPSC_MPCR_m;
+       u32 MPSC_CHR_1_m;
+       u32 MPSC_CHR_2_m;
+       u32 MPSC_CHR_10_m;
+       u32 BRG_BCR_m;
+       struct mpsc_shared_regs *shared_regs;
+};
+
+/* Hooks to platform-specific code */
+int mpsc_platform_register_driver(void);
+void mpsc_platform_unregister_driver(void);
+
+/* Hooks back in to mpsc common to be called by platform-specific code */
+struct mpsc_port_info *mpsc_device_probe(int index);
+struct mpsc_port_info *mpsc_device_remove(int index);
+
+/* Main MPSC Configuration Register Offsets */
+#define        MPSC_MMCRL                      0x0000
+#define        MPSC_MMCRH                      0x0004
+#define        MPSC_MPCR                       0x0008
+#define        MPSC_CHR_1                      0x000c
+#define        MPSC_CHR_2                      0x0010
+#define        MPSC_CHR_3                      0x0014
+#define        MPSC_CHR_4                      0x0018
+#define        MPSC_CHR_5                      0x001c
+#define        MPSC_CHR_6                      0x0020
+#define        MPSC_CHR_7                      0x0024
+#define        MPSC_CHR_8                      0x0028
+#define        MPSC_CHR_9                      0x002c
+#define        MPSC_CHR_10                     0x0030
+#define        MPSC_CHR_11                     0x0034
+
+#define        MPSC_MPCR_FRZ                   (1 << 9)
+#define        MPSC_MPCR_CL_5                  0
+#define        MPSC_MPCR_CL_6                  1
+#define        MPSC_MPCR_CL_7                  2
+#define        MPSC_MPCR_CL_8                  3
+#define        MPSC_MPCR_SBL_1                 0
+#define        MPSC_MPCR_SBL_2                 1
+
+#define        MPSC_CHR_2_TEV                  (1<<1)
+#define        MPSC_CHR_2_TA                   (1<<7)
+#define        MPSC_CHR_2_TTCS                 (1<<9)
+#define        MPSC_CHR_2_REV                  (1<<17)
+#define        MPSC_CHR_2_RA                   (1<<23)
+#define        MPSC_CHR_2_CRD                  (1<<25)
+#define        MPSC_CHR_2_EH                   (1<<31)
+#define        MPSC_CHR_2_PAR_ODD              0
+#define        MPSC_CHR_2_PAR_SPACE            1
+#define        MPSC_CHR_2_PAR_EVEN             2
+#define        MPSC_CHR_2_PAR_MARK             3
+
+/* MPSC Signal Routing */
+#define        MPSC_MRR                        0x0000
+#define        MPSC_RCRR                       0x0004
+#define        MPSC_TCRR                       0x0008
+
+/* Serial DMA Controller Interface Registers */
+#define        SDMA_SDC                        0x0000
+#define        SDMA_SDCM                       0x0008
+#define        SDMA_RX_DESC                    0x0800
+#define        SDMA_RX_BUF_PTR                 0x0808
+#define        SDMA_SCRDP                      0x0810
+#define        SDMA_TX_DESC                    0x0c00
+#define        SDMA_SCTDP                      0x0c10
+#define        SDMA_SFTDP                      0x0c14
+
+#define        SDMA_DESC_CMDSTAT_PE            (1<<0)
+#define        SDMA_DESC_CMDSTAT_CDL           (1<<1)
+#define        SDMA_DESC_CMDSTAT_FR            (1<<3)
+#define        SDMA_DESC_CMDSTAT_OR            (1<<6)
+#define        SDMA_DESC_CMDSTAT_BR            (1<<9)
+#define        SDMA_DESC_CMDSTAT_MI            (1<<10)
+#define        SDMA_DESC_CMDSTAT_A             (1<<11)
+#define        SDMA_DESC_CMDSTAT_AM            (1<<12)
+#define        SDMA_DESC_CMDSTAT_CT            (1<<13)
+#define        SDMA_DESC_CMDSTAT_C             (1<<14)
+#define        SDMA_DESC_CMDSTAT_ES            (1<<15)
+#define        SDMA_DESC_CMDSTAT_L             (1<<16)
+#define        SDMA_DESC_CMDSTAT_F             (1<<17)
+#define        SDMA_DESC_CMDSTAT_P             (1<<18)
+#define        SDMA_DESC_CMDSTAT_EI            (1<<23)
+#define        SDMA_DESC_CMDSTAT_O             (1<<31)
+
+#define SDMA_DESC_DFLT                 (SDMA_DESC_CMDSTAT_O \
+               | SDMA_DESC_CMDSTAT_EI)
+
+#define        SDMA_SDC_RFT                    (1<<0)
+#define        SDMA_SDC_SFM                    (1<<1)
+#define        SDMA_SDC_BLMR                   (1<<6)
+#define        SDMA_SDC_BLMT                   (1<<7)
+#define        SDMA_SDC_POVR                   (1<<8)
+#define        SDMA_SDC_RIFB                   (1<<9)
+
+#define        SDMA_SDCM_ERD                   (1<<7)
+#define        SDMA_SDCM_AR                    (1<<15)
+#define        SDMA_SDCM_STD                   (1<<16)
+#define        SDMA_SDCM_TXD                   (1<<23)
+#define        SDMA_SDCM_AT                    (1<<31)
+
+#define        SDMA_0_CAUSE_RXBUF              (1<<0)
+#define        SDMA_0_CAUSE_RXERR              (1<<1)
+#define        SDMA_0_CAUSE_TXBUF              (1<<2)
+#define        SDMA_0_CAUSE_TXEND              (1<<3)
+#define        SDMA_1_CAUSE_RXBUF              (1<<8)
+#define        SDMA_1_CAUSE_RXERR              (1<<9)
+#define        SDMA_1_CAUSE_TXBUF              (1<<10)
+#define        SDMA_1_CAUSE_TXEND              (1<<11)
+
+#define        SDMA_CAUSE_RX_MASK      (SDMA_0_CAUSE_RXBUF | SDMA_0_CAUSE_RXERR \
+               | SDMA_1_CAUSE_RXBUF | SDMA_1_CAUSE_RXERR)
+#define        SDMA_CAUSE_TX_MASK      (SDMA_0_CAUSE_TXBUF | SDMA_0_CAUSE_TXEND \
+               | SDMA_1_CAUSE_TXBUF | SDMA_1_CAUSE_TXEND)
+
+/* SDMA Interrupt registers */
+#define        SDMA_INTR_CAUSE                 0x0000
+#define        SDMA_INTR_MASK                  0x0080
+
+/* Baud Rate Generator Interface Registers */
+#define        BRG_BCR                         0x0000
+#define        BRG_BTR                         0x0004
+
+/*
+ * Define how this driver is known to the outside (we've been assigned a
+ * range on the "Low-density serial ports" major).
+ */
+#define MPSC_MAJOR                     204
+#define MPSC_MINOR_START               44
+#define        MPSC_DRIVER_NAME                "MPSC"
+#define        MPSC_DEV_NAME                   "ttyMM"
+#define        MPSC_VERSION                    "1.00"
+
+static struct mpsc_port_info mpsc_ports[MPSC_NUM_CTLRS];
+static struct mpsc_shared_regs mpsc_shared_regs;
+static struct uart_driver mpsc_reg;
+
+static void mpsc_start_rx(struct mpsc_port_info *pi);
+static void mpsc_free_ring_mem(struct mpsc_port_info *pi);
+static void mpsc_release_port(struct uart_port *port);
+/*
+ ******************************************************************************
+ *
+ * Baud Rate Generator Routines (BRG)
+ *
+ ******************************************************************************
+ */
+static void mpsc_brg_init(struct mpsc_port_info *pi, u32 clk_src)
+{
+       u32     v;
+
+       v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR);
+       v = (v & ~(0xf << 18)) | ((clk_src & 0xf) << 18);
+
+       if (pi->brg_can_tune)
+               v &= ~(1 << 25);
+
+       if (pi->mirror_regs)
+               pi->BRG_BCR_m = v;
+       writel(v, pi->brg_base + BRG_BCR);
+
+       writel(readl(pi->brg_base + BRG_BTR) & 0xffff0000,
+               pi->brg_base + BRG_BTR);
+}
+
+static void mpsc_brg_enable(struct mpsc_port_info *pi)
+{
+       u32     v;
+
+       v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR);
+       v |= (1 << 16);
+
+       if (pi->mirror_regs)
+               pi->BRG_BCR_m = v;
+       writel(v, pi->brg_base + BRG_BCR);
+}
+
+static void mpsc_brg_disable(struct mpsc_port_info *pi)
+{
+       u32     v;
+
+       v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR);
+       v &= ~(1 << 16);
+
+       if (pi->mirror_regs)
+               pi->BRG_BCR_m = v;
+       writel(v, pi->brg_base + BRG_BCR);
+}
+
+/*
+ * To set the baud, we adjust the CDV field in the BRG_BCR reg.
+ * From manual: Baud = clk / ((CDV+1)*2) ==> CDV = (clk / (baud*2)) - 1.
+ * However, the input clock is divided by 16 in the MPSC b/c of how
+ * 'MPSC_MMCRH' was set up so we have to divide the 'clk' used in our
+ * calculation by 16 to account for that.  So the real calculation
+ * that accounts for the way the mpsc is set up is:
+ * CDV = (clk / (baud*2*16)) - 1 ==> CDV = (clk / (baud << 5)) - 1.
+ */
+static void mpsc_set_baudrate(struct mpsc_port_info *pi, u32 baud)
+{
+       u32     cdv = (pi->port.uartclk / (baud << 5)) - 1;
+       u32     v;
+
+       mpsc_brg_disable(pi);
+       v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR);
+       v = (v & 0xffff0000) | (cdv & 0xffff);
+
+       if (pi->mirror_regs)
+               pi->BRG_BCR_m = v;
+       writel(v, pi->brg_base + BRG_BCR);
+       mpsc_brg_enable(pi);
+}
+
+/*
+ ******************************************************************************
+ *
+ * Serial DMA Routines (SDMA)
+ *
+ ******************************************************************************
+ */
+
+static void mpsc_sdma_burstsize(struct mpsc_port_info *pi, u32 burst_size)
+{
+       u32     v;
+
+       pr_debug("mpsc_sdma_burstsize[%d]: burst_size: %d\n",
+                       pi->port.line, burst_size);
+
+       burst_size >>= 3; /* Divide by 8 b/c reg values are 8-byte chunks */
+
+       if (burst_size < 2)
+               v = 0x0;        /* 1 64-bit word */
+       else if (burst_size < 4)
+               v = 0x1;        /* 2 64-bit words */
+       else if (burst_size < 8)
+               v = 0x2;        /* 4 64-bit words */
+       else
+               v = 0x3;        /* 8 64-bit words */
+
+       writel((readl(pi->sdma_base + SDMA_SDC) & (0x3 << 12)) | (v << 12),
+               pi->sdma_base + SDMA_SDC);
+}
+
+static void mpsc_sdma_init(struct mpsc_port_info *pi, u32 burst_size)
+{
+       pr_debug("mpsc_sdma_init[%d]: burst_size: %d\n", pi->port.line,
+               burst_size);
+
+       writel((readl(pi->sdma_base + SDMA_SDC) & 0x3ff) | 0x03f,
+               pi->sdma_base + SDMA_SDC);
+       mpsc_sdma_burstsize(pi, burst_size);
+}
+
+static u32 mpsc_sdma_intr_mask(struct mpsc_port_info *pi, u32 mask)
+{
+       u32     old, v;
+
+       pr_debug("mpsc_sdma_intr_mask[%d]: mask: 0x%x\n", pi->port.line, mask);
+
+       old = v = (pi->mirror_regs) ? pi->shared_regs->SDMA_INTR_MASK_m :
+               readl(pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
+
+       mask &= 0xf;
+       if (pi->port.line)
+               mask <<= 8;
+       v &= ~mask;
+
+       if (pi->mirror_regs)
+               pi->shared_regs->SDMA_INTR_MASK_m = v;
+       writel(v, pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
+
+       if (pi->port.line)
+               old >>= 8;
+       return old & 0xf;
+}
+
+static void mpsc_sdma_intr_unmask(struct mpsc_port_info *pi, u32 mask)
+{
+       u32     v;
+
+       pr_debug("mpsc_sdma_intr_unmask[%d]: mask: 0x%x\n", pi->port.line,mask);
+
+       v = (pi->mirror_regs) ? pi->shared_regs->SDMA_INTR_MASK_m
+               : readl(pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
+
+       mask &= 0xf;
+       if (pi->port.line)
+               mask <<= 8;
+       v |= mask;
+
+       if (pi->mirror_regs)
+               pi->shared_regs->SDMA_INTR_MASK_m = v;
+       writel(v, pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
+}
+
+static void mpsc_sdma_intr_ack(struct mpsc_port_info *pi)
+{
+       pr_debug("mpsc_sdma_intr_ack[%d]: Acknowledging IRQ\n", pi->port.line);
+
+       if (pi->mirror_regs)
+               pi->shared_regs->SDMA_INTR_CAUSE_m = 0;
+       writeb(0x00, pi->shared_regs->sdma_intr_base + SDMA_INTR_CAUSE
+                       + pi->port.line);
+}
+
+static void mpsc_sdma_set_rx_ring(struct mpsc_port_info *pi,
+               struct mpsc_rx_desc *rxre_p)
+{
+       pr_debug("mpsc_sdma_set_rx_ring[%d]: rxre_p: 0x%x\n",
+               pi->port.line, (u32)rxre_p);
+
+       writel((u32)rxre_p, pi->sdma_base + SDMA_SCRDP);
+}
+
+static void mpsc_sdma_set_tx_ring(struct mpsc_port_info *pi,
+               struct mpsc_tx_desc *txre_p)
+{
+       writel((u32)txre_p, pi->sdma_base + SDMA_SFTDP);
+       writel((u32)txre_p, pi->sdma_base + SDMA_SCTDP);
+}
+
+static void mpsc_sdma_cmd(struct mpsc_port_info *pi, u32 val)
+{
+       u32     v;
+
+       v = readl(pi->sdma_base + SDMA_SDCM);
+       if (val)
+               v |= val;
+       else
+               v = 0;
+       wmb();
+       writel(v, pi->sdma_base + SDMA_SDCM);
+       wmb();
+}
+
+static uint mpsc_sdma_tx_active(struct mpsc_port_info *pi)
+{
+       return readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_TXD;
+}
+
+static void mpsc_sdma_start_tx(struct mpsc_port_info *pi)
+{
+       struct mpsc_tx_desc *txre, *txre_p;
+
+       /* If tx isn't running & there's a desc ready to go, start it */
+       if (!mpsc_sdma_tx_active(pi)) {
+               txre = (struct mpsc_tx_desc *)(pi->txr
+                               + (pi->txr_tail * MPSC_TXRE_SIZE));
+               dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE,
+                               DMA_FROM_DEVICE);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+                       invalidate_dcache_range((ulong)txre,
+                                       (ulong)txre + MPSC_TXRE_SIZE);
+#endif
+
+               if (be32_to_cpu(txre->cmdstat) & SDMA_DESC_CMDSTAT_O) {
+                       txre_p = (struct mpsc_tx_desc *)
+                               (pi->txr_p + (pi->txr_tail * MPSC_TXRE_SIZE));
+
+                       mpsc_sdma_set_tx_ring(pi, txre_p);
+                       mpsc_sdma_cmd(pi, SDMA_SDCM_STD | SDMA_SDCM_TXD);
+               }
+       }
+}
+
+static void mpsc_sdma_stop(struct mpsc_port_info *pi)
+{
+       pr_debug("mpsc_sdma_stop[%d]: Stopping SDMA\n", pi->port.line);
+
+       /* Abort any SDMA transfers */
+       mpsc_sdma_cmd(pi, 0);
+       mpsc_sdma_cmd(pi, SDMA_SDCM_AR | SDMA_SDCM_AT);
+
+       /* Clear the SDMA current and first TX and RX pointers */
+       mpsc_sdma_set_tx_ring(pi, NULL);
+       mpsc_sdma_set_rx_ring(pi, NULL);
+
+       /* Disable interrupts */
+       mpsc_sdma_intr_mask(pi, 0xf);
+       mpsc_sdma_intr_ack(pi);
+}
+
+/*
+ ******************************************************************************
+ *
+ * Multi-Protocol Serial Controller Routines (MPSC)
+ *
+ ******************************************************************************
+ */
+
+static void mpsc_hw_init(struct mpsc_port_info *pi)
+{
+       u32     v;
+
+       pr_debug("mpsc_hw_init[%d]: Initializing hardware\n", pi->port.line);
+
+       /* Set up clock routing */
+       if (pi->mirror_regs) {
+               v = pi->shared_regs->MPSC_MRR_m;
+               v &= ~0x1c7;
+               pi->shared_regs->MPSC_MRR_m = v;
+               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_MRR);
+
+               v = pi->shared_regs->MPSC_RCRR_m;
+               v = (v & ~0xf0f) | 0x100;
+               pi->shared_regs->MPSC_RCRR_m = v;
+               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_RCRR);
+
+               v = pi->shared_regs->MPSC_TCRR_m;
+               v = (v & ~0xf0f) | 0x100;
+               pi->shared_regs->MPSC_TCRR_m = v;
+               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_TCRR);
+       } else {
+               v = readl(pi->shared_regs->mpsc_routing_base + MPSC_MRR);
+               v &= ~0x1c7;
+               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_MRR);
+
+               v = readl(pi->shared_regs->mpsc_routing_base + MPSC_RCRR);
+               v = (v & ~0xf0f) | 0x100;
+               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_RCRR);
+
+               v = readl(pi->shared_regs->mpsc_routing_base + MPSC_TCRR);
+               v = (v & ~0xf0f) | 0x100;
+               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_TCRR);
+       }
+
+       /* Put MPSC in UART mode & enabel Tx/Rx egines */
+       writel(0x000004c4, pi->mpsc_base + MPSC_MMCRL);
+
+       /* No preamble, 16x divider, low-latency, */
+       writel(0x04400400, pi->mpsc_base + MPSC_MMCRH);
+       mpsc_set_baudrate(pi, pi->default_baud);
+
+       if (pi->mirror_regs) {
+               pi->MPSC_CHR_1_m = 0;
+               pi->MPSC_CHR_2_m = 0;
+       }
+       writel(0, pi->mpsc_base + MPSC_CHR_1);
+       writel(0, pi->mpsc_base + MPSC_CHR_2);
+       writel(pi->mpsc_max_idle, pi->mpsc_base + MPSC_CHR_3);
+       writel(0, pi->mpsc_base + MPSC_CHR_4);
+       writel(0, pi->mpsc_base + MPSC_CHR_5);
+       writel(0, pi->mpsc_base + MPSC_CHR_6);
+       writel(0, pi->mpsc_base + MPSC_CHR_7);
+       writel(0, pi->mpsc_base + MPSC_CHR_8);
+       writel(0, pi->mpsc_base + MPSC_CHR_9);
+       writel(0, pi->mpsc_base + MPSC_CHR_10);
+}
+
+static void mpsc_enter_hunt(struct mpsc_port_info *pi)
+{
+       pr_debug("mpsc_enter_hunt[%d]: Hunting...\n", pi->port.line);
+
+       if (pi->mirror_regs) {
+               writel(pi->MPSC_CHR_2_m | MPSC_CHR_2_EH,
+                       pi->mpsc_base + MPSC_CHR_2);
+               /* Erratum prevents reading CHR_2 so just delay for a while */
+               udelay(100);
+       } else {
+               writel(readl(pi->mpsc_base + MPSC_CHR_2) | MPSC_CHR_2_EH,
+                               pi->mpsc_base + MPSC_CHR_2);
+
+               while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_EH)
+                       udelay(10);
+       }
+}
+
+static void mpsc_freeze(struct mpsc_port_info *pi)
+{
+       u32     v;
+
+       pr_debug("mpsc_freeze[%d]: Freezing\n", pi->port.line);
+
+       v = (pi->mirror_regs) ? pi->MPSC_MPCR_m :
+               readl(pi->mpsc_base + MPSC_MPCR);
+       v |= MPSC_MPCR_FRZ;
+
+       if (pi->mirror_regs)
+               pi->MPSC_MPCR_m = v;
+       writel(v, pi->mpsc_base + MPSC_MPCR);
+}
+
+static void mpsc_unfreeze(struct mpsc_port_info *pi)
+{
+       u32     v;
+
+       v = (pi->mirror_regs) ? pi->MPSC_MPCR_m :
+               readl(pi->mpsc_base + MPSC_MPCR);
+       v &= ~MPSC_MPCR_FRZ;
+
+       if (pi->mirror_regs)
+               pi->MPSC_MPCR_m = v;
+       writel(v, pi->mpsc_base + MPSC_MPCR);
+
+       pr_debug("mpsc_unfreeze[%d]: Unfrozen\n", pi->port.line);
+}
+
+static void mpsc_set_char_length(struct mpsc_port_info *pi, u32 len)
+{
+       u32     v;
+
+       pr_debug("mpsc_set_char_length[%d]: char len: %d\n", pi->port.line,len);
+
+       v = (pi->mirror_regs) ? pi->MPSC_MPCR_m :
+               readl(pi->mpsc_base + MPSC_MPCR);
+       v = (v & ~(0x3 << 12)) | ((len & 0x3) << 12);
+
+       if (pi->mirror_regs)
+               pi->MPSC_MPCR_m = v;
+       writel(v, pi->mpsc_base + MPSC_MPCR);
+}
+
+static void mpsc_set_stop_bit_length(struct mpsc_port_info *pi, u32 len)
+{
+       u32     v;
+
+       pr_debug("mpsc_set_stop_bit_length[%d]: stop bits: %d\n",
+               pi->port.line, len);
+
+       v = (pi->mirror_regs) ? pi->MPSC_MPCR_m :
+               readl(pi->mpsc_base + MPSC_MPCR);
+
+       v = (v & ~(1 << 14)) | ((len & 0x1) << 14);
+
+       if (pi->mirror_regs)
+               pi->MPSC_MPCR_m = v;
+       writel(v, pi->mpsc_base + MPSC_MPCR);
+}
+
+static void mpsc_set_parity(struct mpsc_port_info *pi, u32 p)
+{
+       u32     v;
+
+       pr_debug("mpsc_set_parity[%d]: parity bits: 0x%x\n", pi->port.line, p);
+
+       v = (pi->mirror_regs) ? pi->MPSC_CHR_2_m :
+               readl(pi->mpsc_base + MPSC_CHR_2);
+
+       p &= 0x3;
+       v = (v & ~0xc000c) | (p << 18) | (p << 2);
+
+       if (pi->mirror_regs)
+               pi->MPSC_CHR_2_m = v;
+       writel(v, pi->mpsc_base + MPSC_CHR_2);
+}
+
+/*
+ ******************************************************************************
+ *
+ * Driver Init Routines
+ *
+ ******************************************************************************
+ */
+
+static void mpsc_init_hw(struct mpsc_port_info *pi)
+{
+       pr_debug("mpsc_init_hw[%d]: Initializing\n", pi->port.line);
+
+       mpsc_brg_init(pi, pi->brg_clk_src);
+       mpsc_brg_enable(pi);
+       mpsc_sdma_init(pi, dma_get_cache_alignment());  /* burst a cacheline */
+       mpsc_sdma_stop(pi);
+       mpsc_hw_init(pi);
+}
+
+static int mpsc_alloc_ring_mem(struct mpsc_port_info *pi)
+{
+       int rc = 0;
+
+       pr_debug("mpsc_alloc_ring_mem[%d]: Allocating ring mem\n",
+               pi->port.line);
+
+       if (!pi->dma_region) {
+               if (!dma_supported(pi->port.dev, 0xffffffff)) {
+                       printk(KERN_ERR "MPSC: Inadequate DMA support\n");
+                       rc = -ENXIO;
+               } else if ((pi->dma_region = dma_alloc_noncoherent(pi->port.dev,
+                                               MPSC_DMA_ALLOC_SIZE,
+                                               &pi->dma_region_p, GFP_KERNEL))
+                               == NULL) {
+                       printk(KERN_ERR "MPSC: Can't alloc Desc region\n");
+                       rc = -ENOMEM;
+               }
+       }
+
+       return rc;
+}
+
+static void mpsc_free_ring_mem(struct mpsc_port_info *pi)
+{
+       pr_debug("mpsc_free_ring_mem[%d]: Freeing ring mem\n", pi->port.line);
+
+       if (pi->dma_region) {
+               dma_free_noncoherent(pi->port.dev, MPSC_DMA_ALLOC_SIZE,
+                               pi->dma_region, pi->dma_region_p);
+               pi->dma_region = NULL;
+               pi->dma_region_p = (dma_addr_t)NULL;
+       }
+}
+
+static void mpsc_init_rings(struct mpsc_port_info *pi)
+{
+       struct mpsc_rx_desc *rxre;
+       struct mpsc_tx_desc *txre;
+       dma_addr_t dp, dp_p;
+       u8 *bp, *bp_p;
+       int i;
+
+       pr_debug("mpsc_init_rings[%d]: Initializing rings\n", pi->port.line);
+
+       BUG_ON(pi->dma_region == NULL);
+
+       memset(pi->dma_region, 0, MPSC_DMA_ALLOC_SIZE);
+
+       /*
+        * Descriptors & buffers are multiples of cacheline size and must be
+        * cacheline aligned.
+        */
+       dp = ALIGN((u32)pi->dma_region, dma_get_cache_alignment());
+       dp_p = ALIGN((u32)pi->dma_region_p, dma_get_cache_alignment());
+
+       /*
+        * Partition dma region into rx ring descriptor, rx buffers,
+        * tx ring descriptors, and tx buffers.
+        */
+       pi->rxr = dp;
+       pi->rxr_p = dp_p;
+       dp += MPSC_RXR_SIZE;
+       dp_p += MPSC_RXR_SIZE;
+
+       pi->rxb = (u8 *)dp;
+       pi->rxb_p = (u8 *)dp_p;
+       dp += MPSC_RXB_SIZE;
+       dp_p += MPSC_RXB_SIZE;
+
+       pi->rxr_posn = 0;
+
+       pi->txr = dp;
+       pi->txr_p = dp_p;
+       dp += MPSC_TXR_SIZE;
+       dp_p += MPSC_TXR_SIZE;
+
+       pi->txb = (u8 *)dp;
+       pi->txb_p = (u8 *)dp_p;
+
+       pi->txr_head = 0;
+       pi->txr_tail = 0;
+
+       /* Init rx ring descriptors */
+       dp = pi->rxr;
+       dp_p = pi->rxr_p;
+       bp = pi->rxb;
+       bp_p = pi->rxb_p;
+
+       for (i = 0; i < MPSC_RXR_ENTRIES; i++) {
+               rxre = (struct mpsc_rx_desc *)dp;
+
+               rxre->bufsize = cpu_to_be16(MPSC_RXBE_SIZE);
+               rxre->bytecnt = cpu_to_be16(0);
+               rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O
+                               | SDMA_DESC_CMDSTAT_EI | SDMA_DESC_CMDSTAT_F
+                               | SDMA_DESC_CMDSTAT_L);
+               rxre->link = cpu_to_be32(dp_p + MPSC_RXRE_SIZE);
+               rxre->buf_ptr = cpu_to_be32(bp_p);
+
+               dp += MPSC_RXRE_SIZE;
+               dp_p += MPSC_RXRE_SIZE;
+               bp += MPSC_RXBE_SIZE;
+               bp_p += MPSC_RXBE_SIZE;
+       }
+       rxre->link = cpu_to_be32(pi->rxr_p);    /* Wrap last back to first */
+
+       /* Init tx ring descriptors */
+       dp = pi->txr;
+       dp_p = pi->txr_p;
+       bp = pi->txb;
+       bp_p = pi->txb_p;
+
+       for (i = 0; i < MPSC_TXR_ENTRIES; i++) {
+               txre = (struct mpsc_tx_desc *)dp;
+
+               txre->link = cpu_to_be32(dp_p + MPSC_TXRE_SIZE);
+               txre->buf_ptr = cpu_to_be32(bp_p);
+
+               dp += MPSC_TXRE_SIZE;
+               dp_p += MPSC_TXRE_SIZE;
+               bp += MPSC_TXBE_SIZE;
+               bp_p += MPSC_TXBE_SIZE;
+       }
+       txre->link = cpu_to_be32(pi->txr_p);    /* Wrap last back to first */
+
+       dma_cache_sync(pi->port.dev, (void *)pi->dma_region,
+                       MPSC_DMA_ALLOC_SIZE, DMA_BIDIRECTIONAL);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+                       flush_dcache_range((ulong)pi->dma_region,
+                                       (ulong)pi->dma_region
+                                       + MPSC_DMA_ALLOC_SIZE);
+#endif
+
+       return;
+}
+
+static void mpsc_uninit_rings(struct mpsc_port_info *pi)
+{
+       pr_debug("mpsc_uninit_rings[%d]: Uninitializing rings\n",pi->port.line);
+
+       BUG_ON(pi->dma_region == NULL);
+
+       pi->rxr = 0;
+       pi->rxr_p = 0;
+       pi->rxb = NULL;
+       pi->rxb_p = NULL;
+       pi->rxr_posn = 0;
+
+       pi->txr = 0;
+       pi->txr_p = 0;
+       pi->txb = NULL;
+       pi->txb_p = NULL;
+       pi->txr_head = 0;
+       pi->txr_tail = 0;
+}
+
+static int mpsc_make_ready(struct mpsc_port_info *pi)
+{
+       int rc;
+
+       pr_debug("mpsc_make_ready[%d]: Making cltr ready\n", pi->port.line);
+
+       if (!pi->ready) {
+               mpsc_init_hw(pi);
+               if ((rc = mpsc_alloc_ring_mem(pi)))
+                       return rc;
+               mpsc_init_rings(pi);
+               pi->ready = 1;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+static int serial_polled;
+#endif
+
+/*
+ ******************************************************************************
+ *
+ * Interrupt Handling Routines
+ *
+ ******************************************************************************
+ */
+
+static int mpsc_rx_intr(struct mpsc_port_info *pi)
+{
+       struct mpsc_rx_desc *rxre;
+       struct tty_struct *tty = pi->port.state->port.tty;
+       u32     cmdstat, bytes_in, i;
+       int     rc = 0;
+       u8      *bp;
+       char    flag = TTY_NORMAL;
+
+       pr_debug("mpsc_rx_intr[%d]: Handling Rx intr\n", pi->port.line);
+
+       rxre = (struct mpsc_rx_desc *)(pi->rxr + (pi->rxr_posn*MPSC_RXRE_SIZE));
+
+       dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE,
+                       DMA_FROM_DEVICE);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+               invalidate_dcache_range((ulong)rxre,
+                               (ulong)rxre + MPSC_RXRE_SIZE);
+#endif
+
+       /*
+        * Loop through Rx descriptors handling ones that have been completed.
+        */
+       while (!((cmdstat = be32_to_cpu(rxre->cmdstat))
+                               & SDMA_DESC_CMDSTAT_O)) {
+               bytes_in = be16_to_cpu(rxre->bytecnt);
+#ifdef CONFIG_CONSOLE_POLL
+               if (unlikely(serial_polled)) {
+                       serial_polled = 0;
+                       return 0;
+               }
+#endif
+               /* Following use of tty struct directly is deprecated */
+               if (unlikely(tty_buffer_request_room(tty, bytes_in)
+                                       < bytes_in)) {
+                       if (tty->low_latency)
+                               tty_flip_buffer_push(tty);
+                       /*
+                        * If this failed then we will throw away the bytes
+                        * but must do so to clear interrupts.
+                        */
+               }
+
+               bp = pi->rxb + (pi->rxr_posn * MPSC_RXBE_SIZE);
+               dma_cache_sync(pi->port.dev, (void *)bp, MPSC_RXBE_SIZE,
+                               DMA_FROM_DEVICE);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+                       invalidate_dcache_range((ulong)bp,
+                                       (ulong)bp + MPSC_RXBE_SIZE);
+#endif
+
+               /*
+                * Other than for parity error, the manual provides little
+                * info on what data will be in a frame flagged by any of
+                * these errors.  For parity error, it is the last byte in
+                * the buffer that had the error.  As for the rest, I guess
+                * we'll assume there is no data in the buffer.
+                * If there is...it gets lost.
+                */
+               if (unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR
+                                               | SDMA_DESC_CMDSTAT_FR
+                                               | SDMA_DESC_CMDSTAT_OR))) {
+
+                       pi->port.icount.rx++;
+
+                       if (cmdstat & SDMA_DESC_CMDSTAT_BR) {   /* Break */
+                               pi->port.icount.brk++;
+
+                               if (uart_handle_break(&pi->port))
+                                       goto next_frame;
+                       } else if (cmdstat & SDMA_DESC_CMDSTAT_FR) {
+                               pi->port.icount.frame++;
+                       } else if (cmdstat & SDMA_DESC_CMDSTAT_OR) {
+                               pi->port.icount.overrun++;
+                       }
+
+                       cmdstat &= pi->port.read_status_mask;
+
+                       if (cmdstat & SDMA_DESC_CMDSTAT_BR)
+                               flag = TTY_BREAK;
+                       else if (cmdstat & SDMA_DESC_CMDSTAT_FR)
+                               flag = TTY_FRAME;
+                       else if (cmdstat & SDMA_DESC_CMDSTAT_OR)
+                               flag = TTY_OVERRUN;
+                       else if (cmdstat & SDMA_DESC_CMDSTAT_PE)
+                               flag = TTY_PARITY;
+               }
+
+               if (uart_handle_sysrq_char(&pi->port, *bp)) {
+                       bp++;
+                       bytes_in--;
+#ifdef CONFIG_CONSOLE_POLL
+                       if (unlikely(serial_polled)) {
+                               serial_polled = 0;
+                               return 0;
+                       }
+#endif
+                       goto next_frame;
+               }
+
+               if ((unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR
+                                               | SDMA_DESC_CMDSTAT_FR
+                                               | SDMA_DESC_CMDSTAT_OR)))
+                               && !(cmdstat & pi->port.ignore_status_mask)) {
+                       tty_insert_flip_char(tty, *bp, flag);
+               } else {
+                       for (i=0; i<bytes_in; i++)
+                               tty_insert_flip_char(tty, *bp++, TTY_NORMAL);
+
+                       pi->port.icount.rx += bytes_in;
+               }
+
+next_frame:
+               rxre->bytecnt = cpu_to_be16(0);
+               wmb();
+               rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O
+                               | SDMA_DESC_CMDSTAT_EI | SDMA_DESC_CMDSTAT_F
+                               | SDMA_DESC_CMDSTAT_L);
+               wmb();
+               dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE,
+                               DMA_BIDIRECTIONAL);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+                       flush_dcache_range((ulong)rxre,
+                                       (ulong)rxre + MPSC_RXRE_SIZE);
+#endif
+
+               /* Advance to next descriptor */
+               pi->rxr_posn = (pi->rxr_posn + 1) & (MPSC_RXR_ENTRIES - 1);
+               rxre = (struct mpsc_rx_desc *)
+                       (pi->rxr + (pi->rxr_posn * MPSC_RXRE_SIZE));
+               dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE,
+                               DMA_FROM_DEVICE);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+                       invalidate_dcache_range((ulong)rxre,
+                                       (ulong)rxre + MPSC_RXRE_SIZE);
+#endif
+               rc = 1;
+       }
+
+       /* Restart rx engine, if its stopped */
+       if ((readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_ERD) == 0)
+               mpsc_start_rx(pi);
+
+       tty_flip_buffer_push(tty);
+       return rc;
+}
+
+static void mpsc_setup_tx_desc(struct mpsc_port_info *pi, u32 count, u32 intr)
+{
+       struct mpsc_tx_desc *txre;
+
+       txre = (struct mpsc_tx_desc *)(pi->txr
+                       + (pi->txr_head * MPSC_TXRE_SIZE));
+
+       txre->bytecnt = cpu_to_be16(count);
+       txre->shadow = txre->bytecnt;
+       wmb();                  /* ensure cmdstat is last field updated */
+       txre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O | SDMA_DESC_CMDSTAT_F
+                       | SDMA_DESC_CMDSTAT_L
+                       | ((intr) ? SDMA_DESC_CMDSTAT_EI : 0));
+       wmb();
+       dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE,
+                       DMA_BIDIRECTIONAL);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+               flush_dcache_range((ulong)txre,
+                               (ulong)txre + MPSC_TXRE_SIZE);
+#endif
+}
+
+static void mpsc_copy_tx_data(struct mpsc_port_info *pi)
+{
+       struct circ_buf *xmit = &pi->port.state->xmit;
+       u8 *bp;
+       u32 i;
+
+       /* Make sure the desc ring isn't full */
+       while (CIRC_CNT(pi->txr_head, pi->txr_tail, MPSC_TXR_ENTRIES)
+                       < (MPSC_TXR_ENTRIES - 1)) {
+               if (pi->port.x_char) {
+                       /*
+                        * Ideally, we should use the TCS field in
+                        * CHR_1 to put the x_char out immediately but
+                        * errata prevents us from being able to read
+                        * CHR_2 to know that its safe to write to
+                        * CHR_1.  Instead, just put it in-band with
+                        * all the other Tx data.
+                        */
+                       bp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE);
+                       *bp = pi->port.x_char;
+                       pi->port.x_char = 0;
+                       i = 1;
+               } else if (!uart_circ_empty(xmit)
+                               && !uart_tx_stopped(&pi->port)) {
+                       i = min((u32)MPSC_TXBE_SIZE,
+                               (u32)uart_circ_chars_pending(xmit));
+                       i = min(i, (u32)CIRC_CNT_TO_END(xmit->head, xmit->tail,
+                               UART_XMIT_SIZE));
+                       bp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE);
+                       memcpy(bp, &xmit->buf[xmit->tail], i);
+                       xmit->tail = (xmit->tail + i) & (UART_XMIT_SIZE - 1);
+
+                       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+                               uart_write_wakeup(&pi->port);
+               } else { /* All tx data copied into ring bufs */
+                       return;
+               }
+
+               dma_cache_sync(pi->port.dev, (void *)bp, MPSC_TXBE_SIZE,
+                               DMA_BIDIRECTIONAL);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+                       flush_dcache_range((ulong)bp,
+                                       (ulong)bp + MPSC_TXBE_SIZE);
+#endif
+               mpsc_setup_tx_desc(pi, i, 1);
+
+               /* Advance to next descriptor */
+               pi->txr_head = (pi->txr_head + 1) & (MPSC_TXR_ENTRIES - 1);
+       }
+}
+
+static int mpsc_tx_intr(struct mpsc_port_info *pi)
+{
+       struct mpsc_tx_desc *txre;
+       int rc = 0;
+       unsigned long iflags;
+
+       spin_lock_irqsave(&pi->tx_lock, iflags);
+
+       if (!mpsc_sdma_tx_active(pi)) {
+               txre = (struct mpsc_tx_desc *)(pi->txr
+                               + (pi->txr_tail * MPSC_TXRE_SIZE));
+
+               dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE,
+                               DMA_FROM_DEVICE);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+                       invalidate_dcache_range((ulong)txre,
+                                       (ulong)txre + MPSC_TXRE_SIZE);
+#endif
+
+               while (!(be32_to_cpu(txre->cmdstat) & SDMA_DESC_CMDSTAT_O)) {
+                       rc = 1;
+                       pi->port.icount.tx += be16_to_cpu(txre->bytecnt);
+                       pi->txr_tail = (pi->txr_tail+1) & (MPSC_TXR_ENTRIES-1);
+
+                       /* If no more data to tx, fall out of loop */
+                       if (pi->txr_head == pi->txr_tail)
+                               break;
+
+                       txre = (struct mpsc_tx_desc *)(pi->txr
+                                       + (pi->txr_tail * MPSC_TXRE_SIZE));
+                       dma_cache_sync(pi->port.dev, (void *)txre,
+                                       MPSC_TXRE_SIZE, DMA_FROM_DEVICE);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+                       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+                               invalidate_dcache_range((ulong)txre,
+                                               (ulong)txre + MPSC_TXRE_SIZE);
+#endif
+               }
+
+               mpsc_copy_tx_data(pi);
+               mpsc_sdma_start_tx(pi); /* start next desc if ready */
+       }
+
+       spin_unlock_irqrestore(&pi->tx_lock, iflags);
+       return rc;
+}
+
+/*
+ * This is the driver's interrupt handler.  To avoid a race, we first clear
+ * the interrupt, then handle any completed Rx/Tx descriptors.  When done
+ * handling those descriptors, we restart the Rx/Tx engines if they're stopped.
+ */
+static irqreturn_t mpsc_sdma_intr(int irq, void *dev_id)
+{
+       struct mpsc_port_info *pi = dev_id;
+       ulong iflags;
+       int rc = IRQ_NONE;
+
+       pr_debug("mpsc_sdma_intr[%d]: SDMA Interrupt Received\n",pi->port.line);
+
+       spin_lock_irqsave(&pi->port.lock, iflags);
+       mpsc_sdma_intr_ack(pi);
+       if (mpsc_rx_intr(pi))
+               rc = IRQ_HANDLED;
+       if (mpsc_tx_intr(pi))
+               rc = IRQ_HANDLED;
+       spin_unlock_irqrestore(&pi->port.lock, iflags);
+
+       pr_debug("mpsc_sdma_intr[%d]: SDMA Interrupt Handled\n", pi->port.line);
+       return rc;
+}
+
+/*
+ ******************************************************************************
+ *
+ * serial_core.c Interface routines
+ *
+ ******************************************************************************
+ */
+static uint mpsc_tx_empty(struct uart_port *port)
+{
+       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+       ulong iflags;
+       uint rc;
+
+       spin_lock_irqsave(&pi->port.lock, iflags);
+       rc = mpsc_sdma_tx_active(pi) ? 0 : TIOCSER_TEMT;
+       spin_unlock_irqrestore(&pi->port.lock, iflags);
+
+       return rc;
+}
+
+static void mpsc_set_mctrl(struct uart_port *port, uint mctrl)
+{
+       /* Have no way to set modem control lines AFAICT */
+}
+
+static uint mpsc_get_mctrl(struct uart_port *port)
+{
+       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+       u32 mflags, status;
+
+       status = (pi->mirror_regs) ? pi->MPSC_CHR_10_m
+               : readl(pi->mpsc_base + MPSC_CHR_10);
+
+       mflags = 0;
+       if (status & 0x1)
+               mflags |= TIOCM_CTS;
+       if (status & 0x2)
+               mflags |= TIOCM_CAR;
+
+       return mflags | TIOCM_DSR;      /* No way to tell if DSR asserted */
+}
+
+static void mpsc_stop_tx(struct uart_port *port)
+{
+       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+
+       pr_debug("mpsc_stop_tx[%d]\n", port->line);
+
+       mpsc_freeze(pi);
+}
+
+static void mpsc_start_tx(struct uart_port *port)
+{
+       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+       unsigned long iflags;
+
+       spin_lock_irqsave(&pi->tx_lock, iflags);
+
+       mpsc_unfreeze(pi);
+       mpsc_copy_tx_data(pi);
+       mpsc_sdma_start_tx(pi);
+
+       spin_unlock_irqrestore(&pi->tx_lock, iflags);
+
+       pr_debug("mpsc_start_tx[%d]\n", port->line);
+}
+
+static void mpsc_start_rx(struct mpsc_port_info *pi)
+{
+       pr_debug("mpsc_start_rx[%d]: Starting...\n", pi->port.line);
+
+       if (pi->rcv_data) {
+               mpsc_enter_hunt(pi);
+               mpsc_sdma_cmd(pi, SDMA_SDCM_ERD);
+       }
+}
+
+static void mpsc_stop_rx(struct uart_port *port)
+{
+       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+
+       pr_debug("mpsc_stop_rx[%d]: Stopping...\n", port->line);
+
+       if (pi->mirror_regs) {
+               writel(pi->MPSC_CHR_2_m | MPSC_CHR_2_RA,
+                               pi->mpsc_base + MPSC_CHR_2);
+               /* Erratum prevents reading CHR_2 so just delay for a while */
+               udelay(100);
+       } else {
+               writel(readl(pi->mpsc_base + MPSC_CHR_2) | MPSC_CHR_2_RA,
+                               pi->mpsc_base + MPSC_CHR_2);
+
+               while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_RA)
+                       udelay(10);
+       }
+
+       mpsc_sdma_cmd(pi, SDMA_SDCM_AR);
+}
+
+static void mpsc_enable_ms(struct uart_port *port)
+{
+}
+
+static void mpsc_break_ctl(struct uart_port *port, int ctl)
+{
+       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+       ulong   flags;
+       u32     v;
+
+       v = ctl ? 0x00ff0000 : 0;
+
+       spin_lock_irqsave(&pi->port.lock, flags);
+       if (pi->mirror_regs)
+               pi->MPSC_CHR_1_m = v;
+       writel(v, pi->mpsc_base + MPSC_CHR_1);
+       spin_unlock_irqrestore(&pi->port.lock, flags);
+}
+
+static int mpsc_startup(struct uart_port *port)
+{
+       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+       u32 flag = 0;
+       int rc;
+
+       pr_debug("mpsc_startup[%d]: Starting up MPSC, irq: %d\n",
+               port->line, pi->port.irq);
+
+       if ((rc = mpsc_make_ready(pi)) == 0) {
+               /* Setup IRQ handler */
+               mpsc_sdma_intr_ack(pi);
+
+               /* If irq's are shared, need to set flag */
+               if (mpsc_ports[0].port.irq == mpsc_ports[1].port.irq)
+                       flag = IRQF_SHARED;
+
+               if (request_irq(pi->port.irq, mpsc_sdma_intr, flag,
+                                       "mpsc-sdma", pi))
+                       printk(KERN_ERR "MPSC: Can't get SDMA IRQ %d\n",
+                                       pi->port.irq);
+
+               mpsc_sdma_intr_unmask(pi, 0xf);
+               mpsc_sdma_set_rx_ring(pi, (struct mpsc_rx_desc *)(pi->rxr_p
+                                       + (pi->rxr_posn * MPSC_RXRE_SIZE)));
+       }
+
+       return rc;
+}
+
+static void mpsc_shutdown(struct uart_port *port)
+{
+       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+
+       pr_debug("mpsc_shutdown[%d]: Shutting down MPSC\n", port->line);
+
+       mpsc_sdma_stop(pi);
+       free_irq(pi->port.irq, pi);
+}
+
+static void mpsc_set_termios(struct uart_port *port, struct ktermios *termios,
+                struct ktermios *old)
+{
+       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+       u32 baud;
+       ulong flags;
+       u32 chr_bits, stop_bits, par;
+
+       pi->c_iflag = termios->c_iflag;
+       pi->c_cflag = termios->c_cflag;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               chr_bits = MPSC_MPCR_CL_5;
+               break;
+       case CS6:
+               chr_bits = MPSC_MPCR_CL_6;
+               break;
+       case CS7:
+               chr_bits = MPSC_MPCR_CL_7;
+               break;
+       case CS8:
+       default:
+               chr_bits = MPSC_MPCR_CL_8;
+               break;
+       }
+
+       if (termios->c_cflag & CSTOPB)
+               stop_bits = MPSC_MPCR_SBL_2;
+       else
+               stop_bits = MPSC_MPCR_SBL_1;
+
+       par = MPSC_CHR_2_PAR_EVEN;
+       if (termios->c_cflag & PARENB)
+               if (termios->c_cflag & PARODD)
+                       par = MPSC_CHR_2_PAR_ODD;
+#ifdef CMSPAR
+               if (termios->c_cflag & CMSPAR) {
+                       if (termios->c_cflag & PARODD)
+                               par = MPSC_CHR_2_PAR_MARK;
+                       else
+                               par = MPSC_CHR_2_PAR_SPACE;
+               }
+#endif
+
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk);
+
+       spin_lock_irqsave(&pi->port.lock, flags);
+
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       mpsc_set_char_length(pi, chr_bits);
+       mpsc_set_stop_bit_length(pi, stop_bits);
+       mpsc_set_parity(pi, par);
+       mpsc_set_baudrate(pi, baud);
+
+       /* Characters/events to read */
+       pi->port.read_status_mask = SDMA_DESC_CMDSTAT_OR;
+
+       if (termios->c_iflag & INPCK)
+               pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_PE
+                       | SDMA_DESC_CMDSTAT_FR;
+
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_BR;
+
+       /* Characters/events to ignore */
+       pi->port.ignore_status_mask = 0;
+
+       if (termios->c_iflag & IGNPAR)
+               pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_PE
+                       | SDMA_DESC_CMDSTAT_FR;
+
+       if (termios->c_iflag & IGNBRK) {
+               pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_BR;
+
+               if (termios->c_iflag & IGNPAR)
+                       pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_OR;
+       }
+
+       if ((termios->c_cflag & CREAD)) {
+               if (!pi->rcv_data) {
+                       pi->rcv_data = 1;
+                       mpsc_start_rx(pi);
+               }
+       } else if (pi->rcv_data) {
+               mpsc_stop_rx(port);
+               pi->rcv_data = 0;
+       }
+
+       spin_unlock_irqrestore(&pi->port.lock, flags);
+}
+
+static const char *mpsc_type(struct uart_port *port)
+{
+       pr_debug("mpsc_type[%d]: port type: %s\n", port->line,MPSC_DRIVER_NAME);
+       return MPSC_DRIVER_NAME;
+}
+
+static int mpsc_request_port(struct uart_port *port)
+{
+       /* Should make chip/platform specific call */
+       return 0;
+}
+
+static void mpsc_release_port(struct uart_port *port)
+{
+       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+
+       if (pi->ready) {
+               mpsc_uninit_rings(pi);
+               mpsc_free_ring_mem(pi);
+               pi->ready = 0;
+       }
+}
+
+static void mpsc_config_port(struct uart_port *port, int flags)
+{
+}
+
+static int mpsc_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+       int rc = 0;
+
+       pr_debug("mpsc_verify_port[%d]: Verifying port data\n", pi->port.line);
+
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_MPSC)
+               rc = -EINVAL;
+       else if (pi->port.irq != ser->irq)
+               rc = -EINVAL;
+       else if (ser->io_type != SERIAL_IO_MEM)
+               rc = -EINVAL;
+       else if (pi->port.uartclk / 16 != ser->baud_base) /* Not sure */
+               rc = -EINVAL;
+       else if ((void *)pi->port.mapbase != ser->iomem_base)
+               rc = -EINVAL;
+       else if (pi->port.iobase != ser->port)
+               rc = -EINVAL;
+       else if (ser->hub6 != 0)
+               rc = -EINVAL;
+
+       return rc;
+}
+#ifdef CONFIG_CONSOLE_POLL
+/* Serial polling routines for writing and reading from the uart while
+ * in an interrupt or debug context.
+ */
+
+static char poll_buf[2048];
+static int poll_ptr;
+static int poll_cnt;
+static void mpsc_put_poll_char(struct uart_port *port,
+                                                          unsigned char c);
+
+static int mpsc_get_poll_char(struct uart_port *port)
+{
+       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+       struct mpsc_rx_desc *rxre;
+       u32     cmdstat, bytes_in, i;
+       u8      *bp;
+
+       if (!serial_polled)
+               serial_polled = 1;
+
+       pr_debug("mpsc_rx_intr[%d]: Handling Rx intr\n", pi->port.line);
+
+       if (poll_cnt) {
+               poll_cnt--;
+               return poll_buf[poll_ptr++];
+       }
+       poll_ptr = 0;
+       poll_cnt = 0;
+
+       while (poll_cnt == 0) {
+               rxre = (struct mpsc_rx_desc *)(pi->rxr +
+                      (pi->rxr_posn*MPSC_RXRE_SIZE));
+               dma_cache_sync(pi->port.dev, (void *)rxre,
+                              MPSC_RXRE_SIZE, DMA_FROM_DEVICE);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+                       invalidate_dcache_range((ulong)rxre,
+                       (ulong)rxre + MPSC_RXRE_SIZE);
+#endif
+               /*
+                * Loop through Rx descriptors handling ones that have
+                * been completed.
+                */
+               while (poll_cnt == 0 &&
+                      !((cmdstat = be32_to_cpu(rxre->cmdstat)) &
+                        SDMA_DESC_CMDSTAT_O)){
+                       bytes_in = be16_to_cpu(rxre->bytecnt);
+                       bp = pi->rxb + (pi->rxr_posn * MPSC_RXBE_SIZE);
+                       dma_cache_sync(pi->port.dev, (void *) bp,
+                                      MPSC_RXBE_SIZE, DMA_FROM_DEVICE);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+                       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+                               invalidate_dcache_range((ulong)bp,
+                                       (ulong)bp + MPSC_RXBE_SIZE);
+#endif
+                       if ((unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR |
+                        SDMA_DESC_CMDSTAT_FR | SDMA_DESC_CMDSTAT_OR))) &&
+                               !(cmdstat & pi->port.ignore_status_mask)) {
+                               poll_buf[poll_cnt] = *bp;
+                               poll_cnt++;
+                       } else {
+                               for (i = 0; i < bytes_in; i++) {
+                                       poll_buf[poll_cnt] = *bp++;
+                                       poll_cnt++;
+                               }
+                               pi->port.icount.rx += bytes_in;
+                       }
+                       rxre->bytecnt = cpu_to_be16(0);
+                       wmb();
+                       rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O |
+                                                   SDMA_DESC_CMDSTAT_EI |
+                                                   SDMA_DESC_CMDSTAT_F |
+                                                   SDMA_DESC_CMDSTAT_L);
+                       wmb();
+                       dma_cache_sync(pi->port.dev, (void *)rxre,
+                                      MPSC_RXRE_SIZE, DMA_BIDIRECTIONAL);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+                       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+                               flush_dcache_range((ulong)rxre,
+                                          (ulong)rxre + MPSC_RXRE_SIZE);
+#endif
+
+                       /* Advance to next descriptor */
+                       pi->rxr_posn = (pi->rxr_posn + 1) &
+                               (MPSC_RXR_ENTRIES - 1);
+                       rxre = (struct mpsc_rx_desc *)(pi->rxr +
+                                      (pi->rxr_posn * MPSC_RXRE_SIZE));
+                       dma_cache_sync(pi->port.dev, (void *)rxre,
+                                      MPSC_RXRE_SIZE, DMA_FROM_DEVICE);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+                       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+                               invalidate_dcache_range((ulong)rxre,
+                                               (ulong)rxre + MPSC_RXRE_SIZE);
+#endif
+               }
+
+               /* Restart rx engine, if its stopped */
+               if ((readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_ERD) == 0)
+                       mpsc_start_rx(pi);
+       }
+       if (poll_cnt) {
+               poll_cnt--;
+               return poll_buf[poll_ptr++];
+       }
+
+       return 0;
+}
+
+
+static void mpsc_put_poll_char(struct uart_port *port,
+                        unsigned char c)
+{
+       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+       u32 data;
+
+       data = readl(pi->mpsc_base + MPSC_MPCR);
+       writeb(c, pi->mpsc_base + MPSC_CHR_1);
+       mb();
+       data = readl(pi->mpsc_base + MPSC_CHR_2);
+       data |= MPSC_CHR_2_TTCS;
+       writel(data, pi->mpsc_base + MPSC_CHR_2);
+       mb();
+
+       while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_TTCS);
+}
+#endif
+
+static struct uart_ops mpsc_pops = {
+       .tx_empty       = mpsc_tx_empty,
+       .set_mctrl      = mpsc_set_mctrl,
+       .get_mctrl      = mpsc_get_mctrl,
+       .stop_tx        = mpsc_stop_tx,
+       .start_tx       = mpsc_start_tx,
+       .stop_rx        = mpsc_stop_rx,
+       .enable_ms      = mpsc_enable_ms,
+       .break_ctl      = mpsc_break_ctl,
+       .startup        = mpsc_startup,
+       .shutdown       = mpsc_shutdown,
+       .set_termios    = mpsc_set_termios,
+       .type           = mpsc_type,
+       .release_port   = mpsc_release_port,
+       .request_port   = mpsc_request_port,
+       .config_port    = mpsc_config_port,
+       .verify_port    = mpsc_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char = mpsc_get_poll_char,
+       .poll_put_char = mpsc_put_poll_char,
+#endif
+};
+
+/*
+ ******************************************************************************
+ *
+ * Console Interface Routines
+ *
+ ******************************************************************************
+ */
+
+#ifdef CONFIG_SERIAL_MPSC_CONSOLE
+static void mpsc_console_write(struct console *co, const char *s, uint count)
+{
+       struct mpsc_port_info *pi = &mpsc_ports[co->index];
+       u8 *bp, *dp, add_cr = 0;
+       int i;
+       unsigned long iflags;
+
+       spin_lock_irqsave(&pi->tx_lock, iflags);
+
+       while (pi->txr_head != pi->txr_tail) {
+               while (mpsc_sdma_tx_active(pi))
+                       udelay(100);
+               mpsc_sdma_intr_ack(pi);
+               mpsc_tx_intr(pi);
+       }
+
+       while (mpsc_sdma_tx_active(pi))
+               udelay(100);
+
+       while (count > 0) {
+               bp = dp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE);
+
+               for (i = 0; i < MPSC_TXBE_SIZE; i++) {
+                       if (count == 0)
+                               break;
+
+                       if (add_cr) {
+                               *(dp++) = '\r';
+                               add_cr = 0;
+                       } else {
+                               *(dp++) = *s;
+
+                               if (*(s++) == '\n') { /* add '\r' after '\n' */
+                                       add_cr = 1;
+                                       count++;
+                               }
+                       }
+
+                       count--;
+               }
+
+               dma_cache_sync(pi->port.dev, (void *)bp, MPSC_TXBE_SIZE,
+                               DMA_BIDIRECTIONAL);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+                       flush_dcache_range((ulong)bp,
+                                       (ulong)bp + MPSC_TXBE_SIZE);
+#endif
+               mpsc_setup_tx_desc(pi, i, 0);
+               pi->txr_head = (pi->txr_head + 1) & (MPSC_TXR_ENTRIES - 1);
+               mpsc_sdma_start_tx(pi);
+
+               while (mpsc_sdma_tx_active(pi))
+                       udelay(100);
+
+               pi->txr_tail = (pi->txr_tail + 1) & (MPSC_TXR_ENTRIES - 1);
+       }
+
+       spin_unlock_irqrestore(&pi->tx_lock, iflags);
+}
+
+static int __init mpsc_console_setup(struct console *co, char *options)
+{
+       struct mpsc_port_info *pi;
+       int baud, bits, parity, flow;
+
+       pr_debug("mpsc_console_setup[%d]: options: %s\n", co->index, options);
+
+       if (co->index >= MPSC_NUM_CTLRS)
+               co->index = 0;
+
+       pi = &mpsc_ports[co->index];
+
+       baud = pi->default_baud;
+       bits = pi->default_bits;
+       parity = pi->default_parity;
+       flow = pi->default_flow;
+
+       if (!pi->port.ops)
+               return -ENODEV;
+
+       spin_lock_init(&pi->port.lock); /* Temporary fix--copied from 8250.c */
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(&pi->port, co, baud, parity, bits, flow);
+}
+
+static struct console mpsc_console = {
+       .name   = MPSC_DEV_NAME,
+       .write  = mpsc_console_write,
+       .device = uart_console_device,
+       .setup  = mpsc_console_setup,
+       .flags  = CON_PRINTBUFFER,
+       .index  = -1,
+       .data   = &mpsc_reg,
+};
+
+static int __init mpsc_late_console_init(void)
+{
+       pr_debug("mpsc_late_console_init: Enter\n");
+
+       if (!(mpsc_console.flags & CON_ENABLED))
+               register_console(&mpsc_console);
+       return 0;
+}
+
+late_initcall(mpsc_late_console_init);
+
+#define MPSC_CONSOLE   &mpsc_console
+#else
+#define MPSC_CONSOLE   NULL
+#endif
+/*
+ ******************************************************************************
+ *
+ * Dummy Platform Driver to extract & map shared register regions
+ *
+ ******************************************************************************
+ */
+static void mpsc_resource_err(char *s)
+{
+       printk(KERN_WARNING "MPSC: Platform device resource error in %s\n", s);
+}
+
+static int mpsc_shared_map_regs(struct platform_device *pd)
+{
+       struct resource *r;
+
+       if ((r = platform_get_resource(pd, IORESOURCE_MEM,
+                                       MPSC_ROUTING_BASE_ORDER))
+                       && request_mem_region(r->start,
+                               MPSC_ROUTING_REG_BLOCK_SIZE,
+                               "mpsc_routing_regs")) {
+               mpsc_shared_regs.mpsc_routing_base = ioremap(r->start,
+                               MPSC_ROUTING_REG_BLOCK_SIZE);
+               mpsc_shared_regs.mpsc_routing_base_p = r->start;
+       } else {
+               mpsc_resource_err("MPSC routing base");
+               return -ENOMEM;
+       }
+
+       if ((r = platform_get_resource(pd, IORESOURCE_MEM,
+                                       MPSC_SDMA_INTR_BASE_ORDER))
+                       && request_mem_region(r->start,
+                               MPSC_SDMA_INTR_REG_BLOCK_SIZE,
+                               "sdma_intr_regs")) {
+               mpsc_shared_regs.sdma_intr_base = ioremap(r->start,
+                       MPSC_SDMA_INTR_REG_BLOCK_SIZE);
+               mpsc_shared_regs.sdma_intr_base_p = r->start;
+       } else {
+               iounmap(mpsc_shared_regs.mpsc_routing_base);
+               release_mem_region(mpsc_shared_regs.mpsc_routing_base_p,
+                               MPSC_ROUTING_REG_BLOCK_SIZE);
+               mpsc_resource_err("SDMA intr base");
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void mpsc_shared_unmap_regs(void)
+{
+       if (!mpsc_shared_regs.mpsc_routing_base) {
+               iounmap(mpsc_shared_regs.mpsc_routing_base);
+               release_mem_region(mpsc_shared_regs.mpsc_routing_base_p,
+                               MPSC_ROUTING_REG_BLOCK_SIZE);
+       }
+       if (!mpsc_shared_regs.sdma_intr_base) {
+               iounmap(mpsc_shared_regs.sdma_intr_base);
+               release_mem_region(mpsc_shared_regs.sdma_intr_base_p,
+                               MPSC_SDMA_INTR_REG_BLOCK_SIZE);
+       }
+
+       mpsc_shared_regs.mpsc_routing_base = NULL;
+       mpsc_shared_regs.sdma_intr_base = NULL;
+
+       mpsc_shared_regs.mpsc_routing_base_p = 0;
+       mpsc_shared_regs.sdma_intr_base_p = 0;
+}
+
+static int mpsc_shared_drv_probe(struct platform_device *dev)
+{
+       struct mpsc_shared_pdata        *pdata;
+       int                              rc = -ENODEV;
+
+       if (dev->id == 0) {
+               if (!(rc = mpsc_shared_map_regs(dev))) {
+                       pdata = (struct mpsc_shared_pdata *)
+                               dev->dev.platform_data;
+
+                       mpsc_shared_regs.MPSC_MRR_m = pdata->mrr_val;
+                       mpsc_shared_regs.MPSC_RCRR_m= pdata->rcrr_val;
+                       mpsc_shared_regs.MPSC_TCRR_m= pdata->tcrr_val;
+                       mpsc_shared_regs.SDMA_INTR_CAUSE_m =
+                               pdata->intr_cause_val;
+                       mpsc_shared_regs.SDMA_INTR_MASK_m =
+                               pdata->intr_mask_val;
+
+                       rc = 0;
+               }
+       }
+
+       return rc;
+}
+
+static int mpsc_shared_drv_remove(struct platform_device *dev)
+{
+       int     rc = -ENODEV;
+
+       if (dev->id == 0) {
+               mpsc_shared_unmap_regs();
+               mpsc_shared_regs.MPSC_MRR_m = 0;
+               mpsc_shared_regs.MPSC_RCRR_m = 0;
+               mpsc_shared_regs.MPSC_TCRR_m = 0;
+               mpsc_shared_regs.SDMA_INTR_CAUSE_m = 0;
+               mpsc_shared_regs.SDMA_INTR_MASK_m = 0;
+               rc = 0;
+       }
+
+       return rc;
+}
+
+static struct platform_driver mpsc_shared_driver = {
+       .probe  = mpsc_shared_drv_probe,
+       .remove = mpsc_shared_drv_remove,
+       .driver = {
+               .name   = MPSC_SHARED_NAME,
+       },
+};
+
+/*
+ ******************************************************************************
+ *
+ * Driver Interface Routines
+ *
+ ******************************************************************************
+ */
+static struct uart_driver mpsc_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = MPSC_DRIVER_NAME,
+       .dev_name       = MPSC_DEV_NAME,
+       .major          = MPSC_MAJOR,
+       .minor          = MPSC_MINOR_START,
+       .nr             = MPSC_NUM_CTLRS,
+       .cons           = MPSC_CONSOLE,
+};
+
+static int mpsc_drv_map_regs(struct mpsc_port_info *pi,
+               struct platform_device *pd)
+{
+       struct resource *r;
+
+       if ((r = platform_get_resource(pd, IORESOURCE_MEM, MPSC_BASE_ORDER))
+                       && request_mem_region(r->start, MPSC_REG_BLOCK_SIZE,
+                       "mpsc_regs")) {
+               pi->mpsc_base = ioremap(r->start, MPSC_REG_BLOCK_SIZE);
+               pi->mpsc_base_p = r->start;
+       } else {
+               mpsc_resource_err("MPSC base");
+               goto err;
+       }
+
+       if ((r = platform_get_resource(pd, IORESOURCE_MEM,
+                                       MPSC_SDMA_BASE_ORDER))
+                       && request_mem_region(r->start,
+                               MPSC_SDMA_REG_BLOCK_SIZE, "sdma_regs")) {
+               pi->sdma_base = ioremap(r->start,MPSC_SDMA_REG_BLOCK_SIZE);
+               pi->sdma_base_p = r->start;
+       } else {
+               mpsc_resource_err("SDMA base");
+               if (pi->mpsc_base) {
+                       iounmap(pi->mpsc_base);
+                       pi->mpsc_base = NULL;
+               }
+               goto err;
+       }
+
+       if ((r = platform_get_resource(pd,IORESOURCE_MEM,MPSC_BRG_BASE_ORDER))
+                       && request_mem_region(r->start,
+                               MPSC_BRG_REG_BLOCK_SIZE, "brg_regs")) {
+               pi->brg_base = ioremap(r->start, MPSC_BRG_REG_BLOCK_SIZE);
+               pi->brg_base_p = r->start;
+       } else {
+               mpsc_resource_err("BRG base");
+               if (pi->mpsc_base) {
+                       iounmap(pi->mpsc_base);
+                       pi->mpsc_base = NULL;
+               }
+               if (pi->sdma_base) {
+                       iounmap(pi->sdma_base);
+                       pi->sdma_base = NULL;
+               }
+               goto err;
+       }
+       return 0;
+
+err:
+       return -ENOMEM;
+}
+
+static void mpsc_drv_unmap_regs(struct mpsc_port_info *pi)
+{
+       if (!pi->mpsc_base) {
+               iounmap(pi->mpsc_base);
+               release_mem_region(pi->mpsc_base_p, MPSC_REG_BLOCK_SIZE);
+       }
+       if (!pi->sdma_base) {
+               iounmap(pi->sdma_base);
+               release_mem_region(pi->sdma_base_p, MPSC_SDMA_REG_BLOCK_SIZE);
+       }
+       if (!pi->brg_base) {
+               iounmap(pi->brg_base);
+               release_mem_region(pi->brg_base_p, MPSC_BRG_REG_BLOCK_SIZE);
+       }
+
+       pi->mpsc_base = NULL;
+       pi->sdma_base = NULL;
+       pi->brg_base = NULL;
+
+       pi->mpsc_base_p = 0;
+       pi->sdma_base_p = 0;
+       pi->brg_base_p = 0;
+}
+
+static void mpsc_drv_get_platform_data(struct mpsc_port_info *pi,
+               struct platform_device *pd, int num)
+{
+       struct mpsc_pdata       *pdata;
+
+       pdata = (struct mpsc_pdata *)pd->dev.platform_data;
+
+       pi->port.uartclk = pdata->brg_clk_freq;
+       pi->port.iotype = UPIO_MEM;
+       pi->port.line = num;
+       pi->port.type = PORT_MPSC;
+       pi->port.fifosize = MPSC_TXBE_SIZE;
+       pi->port.membase = pi->mpsc_base;
+       pi->port.mapbase = (ulong)pi->mpsc_base;
+       pi->port.ops = &mpsc_pops;
+
+       pi->mirror_regs = pdata->mirror_regs;
+       pi->cache_mgmt = pdata->cache_mgmt;
+       pi->brg_can_tune = pdata->brg_can_tune;
+       pi->brg_clk_src = pdata->brg_clk_src;
+       pi->mpsc_max_idle = pdata->max_idle;
+       pi->default_baud = pdata->default_baud;
+       pi->default_bits = pdata->default_bits;
+       pi->default_parity = pdata->default_parity;
+       pi->default_flow = pdata->default_flow;
+
+       /* Initial values of mirrored regs */
+       pi->MPSC_CHR_1_m = pdata->chr_1_val;
+       pi->MPSC_CHR_2_m = pdata->chr_2_val;
+       pi->MPSC_CHR_10_m = pdata->chr_10_val;
+       pi->MPSC_MPCR_m = pdata->mpcr_val;
+       pi->BRG_BCR_m = pdata->bcr_val;
+
+       pi->shared_regs = &mpsc_shared_regs;
+
+       pi->port.irq = platform_get_irq(pd, 0);
+}
+
+static int mpsc_drv_probe(struct platform_device *dev)
+{
+       struct mpsc_port_info   *pi;
+       int                     rc = -ENODEV;
+
+       pr_debug("mpsc_drv_probe: Adding MPSC %d\n", dev->id);
+
+       if (dev->id < MPSC_NUM_CTLRS) {
+               pi = &mpsc_ports[dev->id];
+
+               if (!(rc = mpsc_drv_map_regs(pi, dev))) {
+                       mpsc_drv_get_platform_data(pi, dev, dev->id);
+                       pi->port.dev = &dev->dev;
+
+                       if (!(rc = mpsc_make_ready(pi))) {
+                               spin_lock_init(&pi->tx_lock);
+                               if (!(rc = uart_add_one_port(&mpsc_reg,
+                                                               &pi->port))) {
+                                       rc = 0;
+                               } else {
+                                       mpsc_release_port((struct uart_port *)
+                                                       pi);
+                                       mpsc_drv_unmap_regs(pi);
+                               }
+                       } else {
+                               mpsc_drv_unmap_regs(pi);
+                       }
+               }
+       }
+
+       return rc;
+}
+
+static int mpsc_drv_remove(struct platform_device *dev)
+{
+       pr_debug("mpsc_drv_exit: Removing MPSC %d\n", dev->id);
+
+       if (dev->id < MPSC_NUM_CTLRS) {
+               uart_remove_one_port(&mpsc_reg, &mpsc_ports[dev->id].port);
+               mpsc_release_port((struct uart_port *)
+                               &mpsc_ports[dev->id].port);
+               mpsc_drv_unmap_regs(&mpsc_ports[dev->id]);
+               return 0;
+       } else {
+               return -ENODEV;
+       }
+}
+
+static struct platform_driver mpsc_driver = {
+       .probe  = mpsc_drv_probe,
+       .remove = mpsc_drv_remove,
+       .driver = {
+               .name   = MPSC_CTLR_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init mpsc_drv_init(void)
+{
+       int     rc;
+
+       printk(KERN_INFO "Serial: MPSC driver\n");
+
+       memset(mpsc_ports, 0, sizeof(mpsc_ports));
+       memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));
+
+       if (!(rc = uart_register_driver(&mpsc_reg))) {
+               if (!(rc = platform_driver_register(&mpsc_shared_driver))) {
+                       if ((rc = platform_driver_register(&mpsc_driver))) {
+                               platform_driver_unregister(&mpsc_shared_driver);
+                               uart_unregister_driver(&mpsc_reg);
+                       }
+               } else {
+                       uart_unregister_driver(&mpsc_reg);
+               }
+       }
+
+       return rc;
+}
+
+static void __exit mpsc_drv_exit(void)
+{
+       platform_driver_unregister(&mpsc_driver);
+       platform_driver_unregister(&mpsc_shared_driver);
+       uart_unregister_driver(&mpsc_reg);
+       memset(mpsc_ports, 0, sizeof(mpsc_ports));
+       memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));
+}
+
+module_init(mpsc_drv_init);
+module_exit(mpsc_drv_exit);
+
+MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>");
+MODULE_DESCRIPTION("Generic Marvell MPSC serial/UART driver");
+MODULE_VERSION(MPSC_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(MPSC_MAJOR);
+MODULE_ALIAS("platform:" MPSC_CTLR_NAME);
diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c
new file mode 100644 (file)
index 0000000..b62857b
--- /dev/null
@@ -0,0 +1,919 @@
+/*
+ *  mrst_max3110.c - spi uart protocol driver for Maxim 3110
+ *
+ * Copyright (c) 2008-2010, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * Note:
+ * 1. From Max3110 spec, the Rx FIFO has 8 words, while the Tx FIFO only has
+ *    1 word. If SPI master controller doesn't support sclk frequency change,
+ *    then the char need be sent out one by one with some delay
+ *
+ * 2. Currently only RX availabe interrrupt is used, no need for waiting TXE
+ *    interrupt for a low speed UART device
+ */
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+
+#include <linux/kthread.h>
+#include <linux/spi/spi.h>
+
+#include "mrst_max3110.h"
+
+#define PR_FMT "mrst_max3110: "
+
+#define UART_TX_NEEDED 1
+#define CON_TX_NEEDED  2
+#define BIT_IRQ_PENDING    3
+
+struct uart_max3110 {
+       struct uart_port port;
+       struct spi_device *spi;
+       char name[24];
+
+       wait_queue_head_t wq;
+       struct task_struct *main_thread;
+       struct task_struct *read_thread;
+       struct mutex thread_mutex;;
+
+       u32 baud;
+       u16 cur_conf;
+       u8 clock;
+       u8 parity, word_7bits;
+       u16 irq;
+
+       unsigned long uart_flags;
+
+       /* console related */
+       struct circ_buf con_xmit;
+};
+
+/* global data structure, may need be removed */
+static struct uart_max3110 *pmax;
+
+static void receive_chars(struct uart_max3110 *max,
+                               unsigned char *str, int len);
+static int max3110_read_multi(struct uart_max3110 *max, u8 *buf);
+static void max3110_con_receive(struct uart_max3110 *max);
+
+static int max3110_write_then_read(struct uart_max3110 *max,
+               const void *txbuf, void *rxbuf, unsigned len, int always_fast)
+{
+       struct spi_device *spi = max->spi;
+       struct spi_message      message;
+       struct spi_transfer     x;
+       int ret;
+
+       spi_message_init(&message);
+       memset(&x, 0, sizeof x);
+       x.len = len;
+       x.tx_buf = txbuf;
+       x.rx_buf = rxbuf;
+       spi_message_add_tail(&x, &message);
+
+       if (always_fast)
+               x.speed_hz = spi->max_speed_hz;
+       else if (max->baud)
+               x.speed_hz = max->baud;
+
+       /* Do the i/o */
+       ret = spi_sync(spi, &message);
+       return ret;
+}
+
+/* Write a 16b word to the device */
+static int max3110_out(struct uart_max3110 *max, const u16 out)
+{
+       void *buf;
+       u16 *obuf, *ibuf;
+       u8  ch;
+       int ret;
+
+       buf = kzalloc(8, GFP_KERNEL | GFP_DMA);
+       if (!buf)
+               return -ENOMEM;
+
+       obuf = buf;
+       ibuf = buf + 4;
+       *obuf = out;
+       ret = max3110_write_then_read(max, obuf, ibuf, 2, 1);
+       if (ret) {
+               pr_warning(PR_FMT "%s(): get err msg %d when sending 0x%x\n",
+                               __func__, ret, out);
+               goto exit;
+       }
+
+       /* If some valid data is read back */
+       if (*ibuf & MAX3110_READ_DATA_AVAILABLE) {
+               ch = *ibuf & 0xff;
+               receive_chars(max, &ch, 1);
+       }
+
+exit:
+       kfree(buf);
+       return ret;
+}
+
+/*
+ * This is usually used to read data from SPIC RX FIFO, which doesn't
+ * need any delay like flushing character out.
+ *
+ * Return how many valide bytes are read back
+ */
+static int max3110_read_multi(struct uart_max3110 *max, u8 *rxbuf)
+{
+       void *buf;
+       u16 *obuf, *ibuf;
+       u8 *pbuf, valid_str[M3110_RX_FIFO_DEPTH];
+       int i, j, blen;
+
+       blen = M3110_RX_FIFO_DEPTH * sizeof(u16);
+       buf = kzalloc(blen * 2, GFP_KERNEL | GFP_DMA);
+       if (!buf) {
+               pr_warning(PR_FMT "%s(): fail to alloc dma buffer\n", __func__);
+               return 0;
+       }
+
+       /* tx/rx always have the same length */
+       obuf = buf;
+       ibuf = buf + blen;
+
+       if (max3110_write_then_read(max, obuf, ibuf, blen, 1)) {
+               kfree(buf);
+               return 0;
+       }
+
+       /* If caller doesn't provide a buffer, then handle received char */
+       pbuf = rxbuf ? rxbuf : valid_str;
+
+       for (i = 0, j = 0; i < M3110_RX_FIFO_DEPTH; i++) {
+               if (ibuf[i] & MAX3110_READ_DATA_AVAILABLE)
+                       pbuf[j++] = ibuf[i] & 0xff;
+       }
+
+       if (j && (pbuf == valid_str))
+               receive_chars(max, valid_str, j);
+
+       kfree(buf);
+       return j;
+}
+
+static void serial_m3110_con_putchar(struct uart_port *port, int ch)
+{
+       struct uart_max3110 *max =
+               container_of(port, struct uart_max3110, port);
+       struct circ_buf *xmit = &max->con_xmit;
+
+       if (uart_circ_chars_free(xmit)) {
+               xmit->buf[xmit->head] = (char)ch;
+               xmit->head = (xmit->head + 1) & (PAGE_SIZE - 1);
+       }
+}
+
+/*
+ * 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.
+ */
+static void serial_m3110_con_write(struct console *co,
+                               const char *s, unsigned int count)
+{
+       if (!pmax)
+               return;
+
+       uart_console_write(&pmax->port, s, count, serial_m3110_con_putchar);
+
+       if (!test_and_set_bit(CON_TX_NEEDED, &pmax->uart_flags))
+               wake_up_process(pmax->main_thread);
+}
+
+static int __init
+serial_m3110_con_setup(struct console *co, char *options)
+{
+       struct uart_max3110 *max = pmax;
+       int baud = 115200;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       pr_info(PR_FMT "setting up console\n");
+
+       if (co->index == -1)
+               co->index = 0;
+
+       if (!max) {
+               pr_err(PR_FMT "pmax is NULL, return");
+               return -ENODEV;
+       }
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(&max->port, co, baud, parity, bits, flow);
+}
+
+static struct tty_driver *serial_m3110_con_device(struct console *co,
+                                                       int *index)
+{
+       struct uart_driver *p = co->data;
+       *index = co->index;
+       return p->tty_driver;
+}
+
+static struct uart_driver serial_m3110_reg;
+static struct console serial_m3110_console = {
+       .name           = "ttyS",
+       .write          = serial_m3110_con_write,
+       .device         = serial_m3110_con_device,
+       .setup          = serial_m3110_con_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &serial_m3110_reg,
+};
+
+static unsigned int serial_m3110_tx_empty(struct uart_port *port)
+{
+       return 1;
+}
+
+static void serial_m3110_stop_tx(struct uart_port *port)
+{
+       return;
+}
+
+/* stop_rx will be called in spin_lock env */
+static void serial_m3110_stop_rx(struct uart_port *port)
+{
+       return;
+}
+
+#define WORDS_PER_XFER 128
+static void send_circ_buf(struct uart_max3110 *max,
+                               struct circ_buf *xmit)
+{
+       void *buf;
+       u16 *obuf, *ibuf;
+       u8 valid_str[WORDS_PER_XFER];
+       int i, j, len, blen, dma_size, left, ret = 0;
+
+
+       dma_size = WORDS_PER_XFER * sizeof(u16) * 2;
+       buf = kzalloc(dma_size, GFP_KERNEL | GFP_DMA);
+       if (!buf)
+               return;
+       obuf = buf;
+       ibuf = buf + dma_size/2;
+
+       while (!uart_circ_empty(xmit)) {
+               left = uart_circ_chars_pending(xmit);
+               while (left) {
+                       len = min(left, WORDS_PER_XFER);
+                       blen = len * sizeof(u16);
+                       memset(ibuf, 0, blen);
+
+                       for (i = 0; i < len; i++) {
+                               obuf[i] = (u8)xmit->buf[xmit->tail] | WD_TAG;
+                               xmit->tail = (xmit->tail + 1) &
+                                               (UART_XMIT_SIZE - 1);
+                       }
+
+                       /* Fail to send msg to console is not very critical */
+                       ret = max3110_write_then_read(max, obuf, ibuf, blen, 0);
+                       if (ret)
+                               pr_warning(PR_FMT "%s(): get err msg %d\n",
+                                               __func__, ret);
+
+                       for (i = 0, j = 0; i < len; i++) {
+                               if (ibuf[i] & MAX3110_READ_DATA_AVAILABLE)
+                                       valid_str[j++] = ibuf[i] & 0xff;
+                       }
+
+                       if (j)
+                               receive_chars(max, valid_str, j);
+
+                       max->port.icount.tx += len;
+                       left -= len;
+               }
+       }
+
+       kfree(buf);
+}
+
+static void transmit_char(struct uart_max3110 *max)
+{
+       struct uart_port *port = &max->port;
+       struct circ_buf *xmit = &port->state->xmit;
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+               return;
+
+       send_circ_buf(max, xmit);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit))
+               serial_m3110_stop_tx(port);
+}
+
+/*
+ * This will be called by uart_write() and tty_write, can't
+ * go to sleep
+ */
+static void serial_m3110_start_tx(struct uart_port *port)
+{
+       struct uart_max3110 *max =
+               container_of(port, struct uart_max3110, port);
+
+       if (!test_and_set_bit(UART_TX_NEEDED, &max->uart_flags))
+               wake_up_process(max->main_thread);
+}
+
+static void receive_chars(struct uart_max3110 *max, unsigned char *str, int len)
+{
+       struct uart_port *port = &max->port;
+       struct tty_struct *tty;
+       int usable;
+
+       /* If uart is not opened, just return */
+       if (!port->state)
+               return;
+
+       tty = port->state->port.tty;
+       if (!tty)
+               return;
+
+       while (len) {
+               usable = tty_buffer_request_room(tty, len);
+               if (usable) {
+                       tty_insert_flip_string(tty, str, usable);
+                       str += usable;
+                       port->icount.rx += usable;
+               }
+               len -= usable;
+       }
+       tty_flip_buffer_push(tty);
+}
+
+/*
+ * This routine will be used in read_thread or RX IRQ handling,
+ * it will first do one round buffer read(8 words), if there is some
+ * valid RX data, will try to read 5 more rounds till all data
+ * is read out.
+ *
+ * Use stack space as data buffer to save some system load, and chose
+ * 504 Btyes as a threadhold to do a bulk push to upper tty layer when
+ * receiving bulk data, a much bigger buffer may cause stack overflow
+ */
+static void max3110_con_receive(struct uart_max3110 *max)
+{
+       int loop = 1, num, total = 0;
+       u8 recv_buf[512], *pbuf;
+
+       pbuf = recv_buf;
+       do {
+               num = max3110_read_multi(max, pbuf);
+
+               if (num) {
+                       loop = 5;
+                       pbuf += num;
+                       total += num;
+
+                       if (total >= 504) {
+                               receive_chars(max, recv_buf, total);
+                               pbuf = recv_buf;
+                               total = 0;
+                       }
+               }
+       } while (--loop);
+
+       if (total)
+               receive_chars(max, recv_buf, total);
+}
+
+static int max3110_main_thread(void *_max)
+{
+       struct uart_max3110 *max = _max;
+       wait_queue_head_t *wq = &max->wq;
+       int ret = 0;
+       struct circ_buf *xmit = &max->con_xmit;
+
+       init_waitqueue_head(wq);
+       pr_info(PR_FMT "start main thread\n");
+
+       do {
+               wait_event_interruptible(*wq, max->uart_flags || kthread_should_stop());
+
+               mutex_lock(&max->thread_mutex);
+
+               if (test_and_clear_bit(BIT_IRQ_PENDING, &max->uart_flags))
+                       max3110_con_receive(max);
+
+               /* first handle console output */
+               if (test_and_clear_bit(CON_TX_NEEDED, &max->uart_flags))
+                       send_circ_buf(max, xmit);
+
+               /* handle uart output */
+               if (test_and_clear_bit(UART_TX_NEEDED, &max->uart_flags))
+                       transmit_char(max);
+
+               mutex_unlock(&max->thread_mutex);
+
+       } while (!kthread_should_stop());
+
+       return ret;
+}
+
+static irqreturn_t serial_m3110_irq(int irq, void *dev_id)
+{
+       struct uart_max3110 *max = dev_id;
+
+       /* max3110's irq is a falling edge, not level triggered,
+        * so no need to disable the irq */
+       if (!test_and_set_bit(BIT_IRQ_PENDING, &max->uart_flags))
+               wake_up_process(max->main_thread);
+
+       return IRQ_HANDLED;
+}
+
+/* if don't use RX IRQ, then need a thread to polling read */
+static int max3110_read_thread(void *_max)
+{
+       struct uart_max3110 *max = _max;
+
+       pr_info(PR_FMT "start read thread\n");
+       do {
+               /*
+                * If can't acquire the mutex, it means the main thread
+                * is running which will also perform the rx job
+                */
+               if (mutex_trylock(&max->thread_mutex)) {
+                       max3110_con_receive(max);
+                       mutex_unlock(&max->thread_mutex);
+               }
+
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(HZ / 20);
+       } while (!kthread_should_stop());
+
+       return 0;
+}
+
+static int serial_m3110_startup(struct uart_port *port)
+{
+       struct uart_max3110 *max =
+               container_of(port, struct uart_max3110, port);
+       u16 config = 0;
+       int ret = 0;
+
+       if (port->line != 0) {
+               pr_err(PR_FMT "uart port startup failed\n");
+               return -1;
+       }
+
+       /* Disable all IRQ and config it to 115200, 8n1 */
+       config = WC_TAG | WC_FIFO_ENABLE
+                       | WC_1_STOPBITS
+                       | WC_8BIT_WORD
+                       | WC_BAUD_DR2;
+
+       /* as we use thread to handle tx/rx, need set low latency */
+       port->state->port.tty->low_latency = 1;
+
+       if (max->irq) {
+               max->read_thread = NULL;
+               ret = request_irq(max->irq, serial_m3110_irq,
+                               IRQ_TYPE_EDGE_FALLING, "max3110", max);
+               if (ret) {
+                       max->irq = 0;
+                       pr_err(PR_FMT "unable to allocate IRQ, polling\n");
+               }  else {
+                       /* Enable RX IRQ only */
+                       config |= WC_RXA_IRQ_ENABLE;
+               }
+       }
+
+       if (max->irq == 0) {
+               /* If IRQ is disabled, start a read thread for input data */
+               max->read_thread =
+                       kthread_run(max3110_read_thread, max, "max3110_read");
+               if (IS_ERR(max->read_thread)) {
+                       ret = PTR_ERR(max->read_thread);
+                       max->read_thread = NULL;
+                       pr_err(PR_FMT "Can't create read thread!\n");
+                       return ret;
+               }
+       }
+
+       ret = max3110_out(max, config);
+       if (ret) {
+               if (max->irq)
+                       free_irq(max->irq, max);
+               if (max->read_thread)
+                       kthread_stop(max->read_thread);
+               max->read_thread = NULL;
+               return ret;
+       }
+
+       max->cur_conf = config;
+       return 0;
+}
+
+static void serial_m3110_shutdown(struct uart_port *port)
+{
+       struct uart_max3110 *max =
+               container_of(port, struct uart_max3110, port);
+       u16 config;
+
+       if (max->read_thread) {
+               kthread_stop(max->read_thread);
+               max->read_thread = NULL;
+       }
+
+       if (max->irq)
+               free_irq(max->irq, max);
+
+       /* Disable interrupts from this port */
+       config = WC_TAG | WC_SW_SHDI;
+       max3110_out(max, config);
+}
+
+static void serial_m3110_release_port(struct uart_port *port)
+{
+}
+
+static int serial_m3110_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static void serial_m3110_config_port(struct uart_port *port, int flags)
+{
+       port->type = PORT_MAX3100;
+}
+
+static int
+serial_m3110_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       /* we don't want the core code to modify any port params */
+       return -EINVAL;
+}
+
+
+static const char *serial_m3110_type(struct uart_port *port)
+{
+       struct uart_max3110 *max =
+               container_of(port, struct uart_max3110, port);
+       return max->name;
+}
+
+static void
+serial_m3110_set_termios(struct uart_port *port, struct ktermios *termios,
+                      struct ktermios *old)
+{
+       struct uart_max3110 *max =
+               container_of(port, struct uart_max3110, port);
+       unsigned char cval;
+       unsigned int baud, parity = 0;
+       int clk_div = -1;
+       u16 new_conf = max->cur_conf;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS7:
+               cval = UART_LCR_WLEN7;
+               new_conf |= WC_7BIT_WORD;
+               break;
+       default:
+               /* We only support CS7 & CS8 */
+               termios->c_cflag &= ~CSIZE;
+               termios->c_cflag |= CS8;
+       case CS8:
+               cval = UART_LCR_WLEN8;
+               new_conf |= WC_8BIT_WORD;
+               break;
+       }
+
+       baud = uart_get_baud_rate(port, termios, old, 0, 230400);
+
+       /* First calc the div for 1.8MHZ clock case */
+       switch (baud) {
+       case 300:
+               clk_div = WC_BAUD_DR384;
+               break;
+       case 600:
+               clk_div = WC_BAUD_DR192;
+               break;
+       case 1200:
+               clk_div = WC_BAUD_DR96;
+               break;
+       case 2400:
+               clk_div = WC_BAUD_DR48;
+               break;
+       case 4800:
+               clk_div = WC_BAUD_DR24;
+               break;
+       case 9600:
+               clk_div = WC_BAUD_DR12;
+               break;
+       case 19200:
+               clk_div = WC_BAUD_DR6;
+               break;
+       case 38400:
+               clk_div = WC_BAUD_DR3;
+               break;
+       case 57600:
+               clk_div = WC_BAUD_DR2;
+               break;
+       case 115200:
+               clk_div = WC_BAUD_DR1;
+               break;
+       case 230400:
+               if (max->clock & MAX3110_HIGH_CLK)
+                       break;
+       default:
+               /* Pick the previous baud rate */
+               baud = max->baud;
+               clk_div = max->cur_conf & WC_BAUD_DIV_MASK;
+               tty_termios_encode_baud_rate(termios, baud, baud);
+       }
+
+       if (max->clock & MAX3110_HIGH_CLK) {
+               clk_div += 1;
+               /* High clk version max3110 doesn't support B300 */
+               if (baud == 300) {
+                       baud = 600;
+                       clk_div = WC_BAUD_DR384;
+               }
+               if (baud == 230400)
+                       clk_div = WC_BAUD_DR1;
+               tty_termios_encode_baud_rate(termios, baud, baud);
+       }
+
+       new_conf = (new_conf & ~WC_BAUD_DIV_MASK) | clk_div;
+
+       if (unlikely(termios->c_cflag & CMSPAR))
+               termios->c_cflag &= ~CMSPAR;
+
+       if (termios->c_cflag & CSTOPB)
+               new_conf |= WC_2_STOPBITS;
+       else
+               new_conf &= ~WC_2_STOPBITS;
+
+       if (termios->c_cflag & PARENB) {
+               new_conf |= WC_PARITY_ENABLE;
+               parity |= UART_LCR_PARITY;
+       } else
+               new_conf &= ~WC_PARITY_ENABLE;
+
+       if (!(termios->c_cflag & PARODD))
+               parity |= UART_LCR_EPAR;
+       max->parity = parity;
+
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       new_conf |= WC_TAG;
+       if (new_conf != max->cur_conf) {
+               if (!max3110_out(max, new_conf)) {
+                       max->cur_conf = new_conf;
+                       max->baud = baud;
+               }
+       }
+}
+
+/* Don't handle hw handshaking */
+static unsigned int serial_m3110_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_DSR | TIOCM_CAR | TIOCM_DSR;
+}
+
+static void serial_m3110_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static void serial_m3110_break_ctl(struct uart_port *port, int break_state)
+{
+}
+
+static void serial_m3110_pm(struct uart_port *port, unsigned int state,
+                       unsigned int oldstate)
+{
+}
+
+static void serial_m3110_enable_ms(struct uart_port *port)
+{
+}
+
+struct uart_ops serial_m3110_ops = {
+       .tx_empty       = serial_m3110_tx_empty,
+       .set_mctrl      = serial_m3110_set_mctrl,
+       .get_mctrl      = serial_m3110_get_mctrl,
+       .stop_tx        = serial_m3110_stop_tx,
+       .start_tx       = serial_m3110_start_tx,
+       .stop_rx        = serial_m3110_stop_rx,
+       .enable_ms      = serial_m3110_enable_ms,
+       .break_ctl      = serial_m3110_break_ctl,
+       .startup        = serial_m3110_startup,
+       .shutdown       = serial_m3110_shutdown,
+       .set_termios    = serial_m3110_set_termios,
+       .pm             = serial_m3110_pm,
+       .type           = serial_m3110_type,
+       .release_port   = serial_m3110_release_port,
+       .request_port   = serial_m3110_request_port,
+       .config_port    = serial_m3110_config_port,
+       .verify_port    = serial_m3110_verify_port,
+};
+
+static struct uart_driver serial_m3110_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "MRST serial",
+       .dev_name       = "ttyS",
+       .major          = TTY_MAJOR,
+       .minor          = 64,
+       .nr             = 1,
+       .cons           = &serial_m3110_console,
+};
+
+#ifdef CONFIG_PM
+static int serial_m3110_suspend(struct spi_device *spi, pm_message_t state)
+{
+       struct uart_max3110 *max = spi_get_drvdata(spi);
+
+       disable_irq(max->irq);
+       uart_suspend_port(&serial_m3110_reg, &max->port);
+       max3110_out(max, max->cur_conf | WC_SW_SHDI);
+       return 0;
+}
+
+static int serial_m3110_resume(struct spi_device *spi)
+{
+       struct uart_max3110 *max = spi_get_drvdata(spi);
+
+       max3110_out(max, max->cur_conf);
+       uart_resume_port(&serial_m3110_reg, &max->port);
+       enable_irq(max->irq);
+       return 0;
+}
+#else
+#define serial_m3110_suspend   NULL
+#define serial_m3110_resume    NULL
+#endif
+
+static int __devinit serial_m3110_probe(struct spi_device *spi)
+{
+       struct uart_max3110 *max;
+       void *buffer;
+       u16 res;
+       int ret = 0;
+
+       max = kzalloc(sizeof(*max), GFP_KERNEL);
+       if (!max)
+               return -ENOMEM;
+
+       /* Set spi info */
+       spi->bits_per_word = 16;
+       max->clock = MAX3110_HIGH_CLK;
+
+       spi_setup(spi);
+
+       max->port.type = PORT_MAX3100;
+       max->port.fifosize = 2;         /* Only have 16b buffer */
+       max->port.ops = &serial_m3110_ops;
+       max->port.line = 0;
+       max->port.dev = &spi->dev;
+       max->port.uartclk = 115200;
+
+       max->spi = spi;
+       strcpy(max->name, spi->modalias);
+       max->irq = (u16)spi->irq;
+
+       mutex_init(&max->thread_mutex);
+
+       max->word_7bits = 0;
+       max->parity = 0;
+       max->baud = 0;
+
+       max->cur_conf = 0;
+       max->uart_flags = 0;
+
+       /* Check if reading configuration register returns something sane */
+
+       res = RC_TAG;
+       ret = max3110_write_then_read(max, (u8 *)&res, (u8 *)&res, 2, 0);
+       if (ret < 0 || res == 0 || res == 0xffff) {
+               printk(KERN_ERR "MAX3111 deemed not present (conf reg %04x)",
+                                                                       res);
+               ret = -ENODEV;
+               goto err_get_page;
+       }
+
+       buffer = (void *)__get_free_page(GFP_KERNEL);
+       if (!buffer) {
+               ret = -ENOMEM;
+               goto err_get_page;
+       }
+       max->con_xmit.buf = buffer;
+       max->con_xmit.head = 0;
+       max->con_xmit.tail = 0;
+
+       max->main_thread = kthread_run(max3110_main_thread,
+                                       max, "max3110_main");
+       if (IS_ERR(max->main_thread)) {
+               ret = PTR_ERR(max->main_thread);
+               goto err_kthread;
+       }
+
+       spi_set_drvdata(spi, max);
+       pmax = max;
+
+       /* Give membase a psudo value to pass serial_core's check */
+       max->port.membase = (void *)0xff110000;
+       uart_add_one_port(&serial_m3110_reg, &max->port);
+
+       return 0;
+
+err_kthread:
+       free_page((unsigned long)buffer);
+err_get_page:
+       kfree(max);
+       return ret;
+}
+
+static int __devexit serial_m3110_remove(struct spi_device *dev)
+{
+       struct uart_max3110 *max = spi_get_drvdata(dev);
+
+       if (!max)
+               return 0;
+
+       uart_remove_one_port(&serial_m3110_reg, &max->port);
+
+       free_page((unsigned long)max->con_xmit.buf);
+
+       if (max->main_thread)
+               kthread_stop(max->main_thread);
+
+       kfree(max);
+       return 0;
+}
+
+static struct spi_driver uart_max3110_driver = {
+       .driver = {
+                       .name   = "spi_max3111",
+                       .bus    = &spi_bus_type,
+                       .owner  = THIS_MODULE,
+       },
+       .probe          = serial_m3110_probe,
+       .remove         = __devexit_p(serial_m3110_remove),
+       .suspend        = serial_m3110_suspend,
+       .resume         = serial_m3110_resume,
+};
+
+static int __init serial_m3110_init(void)
+{
+       int ret = 0;
+
+       ret = uart_register_driver(&serial_m3110_reg);
+       if (ret)
+               return ret;
+
+       ret = spi_register_driver(&uart_max3110_driver);
+       if (ret)
+               uart_unregister_driver(&serial_m3110_reg);
+
+       return ret;
+}
+
+static void __exit serial_m3110_exit(void)
+{
+       spi_unregister_driver(&uart_max3110_driver);
+       uart_unregister_driver(&serial_m3110_reg);
+}
+
+module_init(serial_m3110_init);
+module_exit(serial_m3110_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("max3110-uart");
diff --git a/drivers/tty/serial/mrst_max3110.h b/drivers/tty/serial/mrst_max3110.h
new file mode 100644 (file)
index 0000000..d1ef43a
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef _MRST_MAX3110_H
+#define _MRST_MAX3110_H
+
+#define MAX3110_HIGH_CLK       0x1     /* 3.6864 MHZ */
+#define MAX3110_LOW_CLK                0x0     /* 1.8432 MHZ */
+
+/* status bits for all 4 MAX3110 operate modes */
+#define MAX3110_READ_DATA_AVAILABLE    (1 << 15)
+#define MAX3110_WRITE_BUF_EMPTY                (1 << 14)
+
+#define WC_TAG                 (3 << 14)
+#define RC_TAG                 (1 << 14)
+#define WD_TAG                 (2 << 14)
+#define RD_TAG                 (0 << 14)
+
+/* bits def for write configuration */
+#define WC_FIFO_ENABLE_MASK    (1 << 13)
+#define WC_FIFO_ENABLE         (0 << 13)
+
+#define WC_SW_SHDI             (1 << 12)
+
+#define WC_IRQ_MASK            (0xF << 8)
+#define WC_TXE_IRQ_ENABLE      (1 << 11)       /* TX empty irq */
+#define WC_RXA_IRQ_ENABLE      (1 << 10)       /* RX availabe irq */
+#define WC_PAR_HIGH_IRQ_ENABLE (1 << 9)
+#define WC_REC_ACT_IRQ_ENABLE  (1 << 8)
+
+#define WC_IRDA_ENABLE         (1 << 7)
+
+#define WC_STOPBITS_MASK       (1 << 6)
+#define WC_2_STOPBITS          (1 << 6)
+#define WC_1_STOPBITS          (0 << 6)
+
+#define WC_PARITY_ENABLE_MASK  (1 << 5)
+#define WC_PARITY_ENABLE       (1 << 5)
+
+#define WC_WORDLEN_MASK                (1 << 4)
+#define WC_7BIT_WORD           (1 << 4)
+#define WC_8BIT_WORD           (0 << 4)
+
+#define WC_BAUD_DIV_MASK       (0xF)
+#define WC_BAUD_DR1            (0x0)
+#define WC_BAUD_DR2            (0x1)
+#define WC_BAUD_DR4            (0x2)
+#define WC_BAUD_DR8            (0x3)
+#define WC_BAUD_DR16           (0x4)
+#define WC_BAUD_DR32           (0x5)
+#define WC_BAUD_DR64           (0x6)
+#define WC_BAUD_DR128          (0x7)
+#define WC_BAUD_DR3            (0x8)
+#define WC_BAUD_DR6            (0x9)
+#define WC_BAUD_DR12           (0xA)
+#define WC_BAUD_DR24           (0xB)
+#define WC_BAUD_DR48           (0xC)
+#define WC_BAUD_DR96           (0xD)
+#define WC_BAUD_DR192          (0xE)
+#define WC_BAUD_DR384          (0xF)
+
+#define M3110_RX_FIFO_DEPTH    8
+#endif
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
new file mode 100644 (file)
index 0000000..8e43a7b
--- /dev/null
@@ -0,0 +1,758 @@
+/*
+ * drivers/serial/msm_serial.c - driver for msm7k serial device and console
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Robert Love <rlove@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#if defined(CONFIG_SERIAL_MSM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+# define SUPPORT_SYSRQ
+#endif
+
+#include <linux/hrtimer.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include "msm_serial.h"
+
+struct msm_port {
+       struct uart_port        uart;
+       char                    name[16];
+       struct clk              *clk;
+       unsigned int            imr;
+};
+
+static void msm_stop_tx(struct uart_port *port)
+{
+       struct msm_port *msm_port = UART_TO_MSM(port);
+
+       msm_port->imr &= ~UART_IMR_TXLEV;
+       msm_write(port, msm_port->imr, UART_IMR);
+}
+
+static void msm_start_tx(struct uart_port *port)
+{
+       struct msm_port *msm_port = UART_TO_MSM(port);
+
+       msm_port->imr |= UART_IMR_TXLEV;
+       msm_write(port, msm_port->imr, UART_IMR);
+}
+
+static void msm_stop_rx(struct uart_port *port)
+{
+       struct msm_port *msm_port = UART_TO_MSM(port);
+
+       msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE);
+       msm_write(port, msm_port->imr, UART_IMR);
+}
+
+static void msm_enable_ms(struct uart_port *port)
+{
+       struct msm_port *msm_port = UART_TO_MSM(port);
+
+       msm_port->imr |= UART_IMR_DELTA_CTS;
+       msm_write(port, msm_port->imr, UART_IMR);
+}
+
+static void handle_rx(struct uart_port *port)
+{
+       struct tty_struct *tty = port->state->port.tty;
+       unsigned int sr;
+
+       /*
+        * Handle overrun. My understanding of the hardware is that overrun
+        * is not tied to the RX buffer, so we handle the case out of band.
+        */
+       if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) {
+               port->icount.overrun++;
+               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+               msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
+       }
+
+       /* and now the main RX loop */
+       while ((sr = msm_read(port, UART_SR)) & UART_SR_RX_READY) {
+               unsigned int c;
+               char flag = TTY_NORMAL;
+
+               c = msm_read(port, UART_RF);
+
+               if (sr & UART_SR_RX_BREAK) {
+                       port->icount.brk++;
+                       if (uart_handle_break(port))
+                               continue;
+               } else if (sr & UART_SR_PAR_FRAME_ERR) {
+                       port->icount.frame++;
+               } else {
+                       port->icount.rx++;
+               }
+
+               /* Mask conditions we're ignorning. */
+               sr &= port->read_status_mask;
+
+               if (sr & UART_SR_RX_BREAK) {
+                       flag = TTY_BREAK;
+               } else if (sr & UART_SR_PAR_FRAME_ERR) {
+                       flag = TTY_FRAME;
+               }
+
+               if (!uart_handle_sysrq_char(port, c))
+                       tty_insert_flip_char(tty, c, flag);
+       }
+
+       tty_flip_buffer_push(tty);
+}
+
+static void handle_tx(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->state->xmit;
+       struct msm_port *msm_port = UART_TO_MSM(port);
+       int sent_tx;
+
+       if (port->x_char) {
+               msm_write(port, port->x_char, UART_TF);
+               port->icount.tx++;
+               port->x_char = 0;
+       }
+
+       while (msm_read(port, UART_SR) & UART_SR_TX_READY) {
+               if (uart_circ_empty(xmit)) {
+                       /* disable tx interrupts */
+                       msm_port->imr &= ~UART_IMR_TXLEV;
+                       msm_write(port, msm_port->imr, UART_IMR);
+                       break;
+               }
+
+               msm_write(port, xmit->buf[xmit->tail], UART_TF);
+
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               sent_tx = 1;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+}
+
+static void handle_delta_cts(struct uart_port *port)
+{
+       msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
+       port->icount.cts++;
+       wake_up_interruptible(&port->state->port.delta_msr_wait);
+}
+
+static irqreturn_t msm_irq(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       struct msm_port *msm_port = UART_TO_MSM(port);
+       unsigned int misr;
+
+       spin_lock(&port->lock);
+       misr = msm_read(port, UART_MISR);
+       msm_write(port, 0, UART_IMR); /* disable interrupt */
+
+       if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE))
+               handle_rx(port);
+       if (misr & UART_IMR_TXLEV)
+               handle_tx(port);
+       if (misr & UART_IMR_DELTA_CTS)
+               handle_delta_cts(port);
+
+       msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */
+       spin_unlock(&port->lock);
+
+       return IRQ_HANDLED;
+}
+
+static unsigned int msm_tx_empty(struct uart_port *port)
+{
+       return (msm_read(port, UART_SR) & UART_SR_TX_EMPTY) ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int msm_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR | TIOCM_RTS;
+}
+
+static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       unsigned int mr;
+
+       mr = msm_read(port, UART_MR1);
+
+       if (!(mctrl & TIOCM_RTS)) {
+               mr &= ~UART_MR1_RX_RDY_CTL;
+               msm_write(port, mr, UART_MR1);
+               msm_write(port, UART_CR_CMD_RESET_RFR, UART_CR);
+       } else {
+               mr |= UART_MR1_RX_RDY_CTL;
+               msm_write(port, mr, UART_MR1);
+       }
+}
+
+static void msm_break_ctl(struct uart_port *port, int break_ctl)
+{
+       if (break_ctl)
+               msm_write(port, UART_CR_CMD_START_BREAK, UART_CR);
+       else
+               msm_write(port, UART_CR_CMD_STOP_BREAK, UART_CR);
+}
+
+static int msm_set_baud_rate(struct uart_port *port, unsigned int baud)
+{
+       unsigned int baud_code, rxstale, watermark;
+
+       switch (baud) {
+       case 300:
+               baud_code = UART_CSR_300;
+               rxstale = 1;
+               break;
+       case 600:
+               baud_code = UART_CSR_600;
+               rxstale = 1;
+               break;
+       case 1200:
+               baud_code = UART_CSR_1200;
+               rxstale = 1;
+               break;
+       case 2400:
+               baud_code = UART_CSR_2400;
+               rxstale = 1;
+               break;
+       case 4800:
+               baud_code = UART_CSR_4800;
+               rxstale = 1;
+               break;
+       case 9600:
+               baud_code = UART_CSR_9600;
+               rxstale = 2;
+               break;
+       case 14400:
+               baud_code = UART_CSR_14400;
+               rxstale = 3;
+               break;
+       case 19200:
+               baud_code = UART_CSR_19200;
+               rxstale = 4;
+               break;
+       case 28800:
+               baud_code = UART_CSR_28800;
+               rxstale = 6;
+               break;
+       case 38400:
+               baud_code = UART_CSR_38400;
+               rxstale = 8;
+               break;
+       case 57600:
+               baud_code = UART_CSR_57600;
+               rxstale = 16;
+               break;
+       case 115200:
+       default:
+               baud_code = UART_CSR_115200;
+               baud = 115200;
+               rxstale = 31;
+               break;
+       }
+
+       msm_write(port, baud_code, UART_CSR);
+
+       /* RX stale watermark */
+       watermark = UART_IPR_STALE_LSB & rxstale;
+       watermark |= UART_IPR_RXSTALE_LAST;
+       watermark |= UART_IPR_STALE_TIMEOUT_MSB & (rxstale << 2);
+       msm_write(port, watermark, UART_IPR);
+
+       /* set RX watermark */
+       watermark = (port->fifosize * 3) / 4;
+       msm_write(port, watermark, UART_RFWR);
+
+       /* set TX watermark */
+       msm_write(port, 10, UART_TFWR);
+
+       return baud;
+}
+
+static void msm_reset(struct uart_port *port)
+{
+       /* reset everything */
+       msm_write(port, UART_CR_CMD_RESET_RX, UART_CR);
+       msm_write(port, UART_CR_CMD_RESET_TX, UART_CR);
+       msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
+       msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR);
+       msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
+       msm_write(port, UART_CR_CMD_SET_RFR, UART_CR);
+}
+
+static void msm_init_clock(struct uart_port *port)
+{
+       struct msm_port *msm_port = UART_TO_MSM(port);
+
+       clk_enable(msm_port->clk);
+       msm_serial_set_mnd_regs(port);
+}
+
+static int msm_startup(struct uart_port *port)
+{
+       struct msm_port *msm_port = UART_TO_MSM(port);
+       unsigned int data, rfr_level;
+       int ret;
+
+       snprintf(msm_port->name, sizeof(msm_port->name),
+                "msm_serial%d", port->line);
+
+       ret = request_irq(port->irq, msm_irq, IRQF_TRIGGER_HIGH,
+                         msm_port->name, port);
+       if (unlikely(ret))
+               return ret;
+
+       msm_init_clock(port);
+
+       if (likely(port->fifosize > 12))
+               rfr_level = port->fifosize - 12;
+       else
+               rfr_level = port->fifosize;
+
+       /* set automatic RFR level */
+       data = msm_read(port, UART_MR1);
+       data &= ~UART_MR1_AUTO_RFR_LEVEL1;
+       data &= ~UART_MR1_AUTO_RFR_LEVEL0;
+       data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2);
+       data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level;
+       msm_write(port, data, UART_MR1);
+
+       /* make sure that RXSTALE count is non-zero */
+       data = msm_read(port, UART_IPR);
+       if (unlikely(!data)) {
+               data |= UART_IPR_RXSTALE_LAST;
+               data |= UART_IPR_STALE_LSB;
+               msm_write(port, data, UART_IPR);
+       }
+
+       msm_reset(port);
+
+       msm_write(port, 0x05, UART_CR); /* enable TX & RX */
+
+       /* turn on RX and CTS interrupts */
+       msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE |
+                       UART_IMR_CURRENT_CTS;
+       msm_write(port, msm_port->imr, UART_IMR);
+
+       return 0;
+}
+
+static void msm_shutdown(struct uart_port *port)
+{
+       struct msm_port *msm_port = UART_TO_MSM(port);
+
+       msm_port->imr = 0;
+       msm_write(port, 0, UART_IMR); /* disable interrupts */
+
+       clk_disable(msm_port->clk);
+
+       free_irq(port->irq, port);
+}
+
+static void msm_set_termios(struct uart_port *port, struct ktermios *termios,
+                           struct ktermios *old)
+{
+       unsigned long flags;
+       unsigned int baud, mr;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* calculate and set baud rate */
+       baud = uart_get_baud_rate(port, termios, old, 300, 115200);
+       baud = msm_set_baud_rate(port, baud);
+       if (tty_termios_baud_rate(termios))
+               tty_termios_encode_baud_rate(termios, baud, baud);
+       
+       /* calculate parity */
+       mr = msm_read(port, UART_MR2);
+       mr &= ~UART_MR2_PARITY_MODE;
+       if (termios->c_cflag & PARENB) {
+               if (termios->c_cflag & PARODD)
+                       mr |= UART_MR2_PARITY_MODE_ODD;
+               else if (termios->c_cflag & CMSPAR)
+                       mr |= UART_MR2_PARITY_MODE_SPACE;
+               else
+                       mr |= UART_MR2_PARITY_MODE_EVEN;
+       }
+
+       /* calculate bits per char */
+       mr &= ~UART_MR2_BITS_PER_CHAR;
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               mr |= UART_MR2_BITS_PER_CHAR_5;
+               break;
+       case CS6:
+               mr |= UART_MR2_BITS_PER_CHAR_6;
+               break;
+       case CS7:
+               mr |= UART_MR2_BITS_PER_CHAR_7;
+               break;
+       case CS8:
+       default:
+               mr |= UART_MR2_BITS_PER_CHAR_8;
+               break;
+       }
+
+       /* calculate stop bits */
+       mr &= ~(UART_MR2_STOP_BIT_LEN_ONE | UART_MR2_STOP_BIT_LEN_TWO);
+       if (termios->c_cflag & CSTOPB)
+               mr |= UART_MR2_STOP_BIT_LEN_TWO;
+       else
+               mr |= UART_MR2_STOP_BIT_LEN_ONE;
+
+       /* set parity, bits per char, and stop bit */
+       msm_write(port, mr, UART_MR2);
+
+       /* calculate and set hardware flow control */
+       mr = msm_read(port, UART_MR1);
+       mr &= ~(UART_MR1_CTS_CTL | UART_MR1_RX_RDY_CTL);
+       if (termios->c_cflag & CRTSCTS) {
+               mr |= UART_MR1_CTS_CTL;
+               mr |= UART_MR1_RX_RDY_CTL;
+       }
+       msm_write(port, mr, UART_MR1);
+
+       /* Configure status bits to ignore based on termio flags. */
+       port->read_status_mask = 0;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= UART_SR_PAR_FRAME_ERR;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               port->read_status_mask |= UART_SR_RX_BREAK;
+
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *msm_type(struct uart_port *port)
+{
+       return "MSM";
+}
+
+static void msm_release_port(struct uart_port *port)
+{
+       struct platform_device *pdev = to_platform_device(port->dev);
+       struct resource *resource;
+       resource_size_t size;
+
+       resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (unlikely(!resource))
+               return;
+       size = resource->end - resource->start + 1;
+
+       release_mem_region(port->mapbase, size);
+       iounmap(port->membase);
+       port->membase = NULL;
+}
+
+static int msm_request_port(struct uart_port *port)
+{
+       struct platform_device *pdev = to_platform_device(port->dev);
+       struct resource *resource;
+       resource_size_t size;
+
+       resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (unlikely(!resource))
+               return -ENXIO;
+       size = resource->end - resource->start + 1;
+
+       if (unlikely(!request_mem_region(port->mapbase, size, "msm_serial")))
+               return -EBUSY;
+
+       port->membase = ioremap(port->mapbase, size);
+       if (!port->membase) {
+               release_mem_region(port->mapbase, size);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static void msm_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = PORT_MSM;
+               msm_request_port(port);
+       }
+}
+
+static int msm_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       if (unlikely(ser->type != PORT_UNKNOWN && ser->type != PORT_MSM))
+               return -EINVAL;
+       if (unlikely(port->irq != ser->irq))
+               return -EINVAL;
+       return 0;
+}
+
+static void msm_power(struct uart_port *port, unsigned int state,
+                     unsigned int oldstate)
+{
+       struct msm_port *msm_port = UART_TO_MSM(port);
+
+       switch (state) {
+       case 0:
+               clk_enable(msm_port->clk);
+               break;
+       case 3:
+               clk_disable(msm_port->clk);
+               break;
+       default:
+               printk(KERN_ERR "msm_serial: Unknown PM state %d\n", state);
+       }
+}
+
+static struct uart_ops msm_uart_pops = {
+       .tx_empty = msm_tx_empty,
+       .set_mctrl = msm_set_mctrl,
+       .get_mctrl = msm_get_mctrl,
+       .stop_tx = msm_stop_tx,
+       .start_tx = msm_start_tx,
+       .stop_rx = msm_stop_rx,
+       .enable_ms = msm_enable_ms,
+       .break_ctl = msm_break_ctl,
+       .startup = msm_startup,
+       .shutdown = msm_shutdown,
+       .set_termios = msm_set_termios,
+       .type = msm_type,
+       .release_port = msm_release_port,
+       .request_port = msm_request_port,
+       .config_port = msm_config_port,
+       .verify_port = msm_verify_port,
+       .pm = msm_power,
+};
+
+static struct msm_port msm_uart_ports[] = {
+       {
+               .uart = {
+                       .iotype = UPIO_MEM,
+                       .ops = &msm_uart_pops,
+                       .flags = UPF_BOOT_AUTOCONF,
+                       .fifosize = 512,
+                       .line = 0,
+               },
+       },
+       {
+               .uart = {
+                       .iotype = UPIO_MEM,
+                       .ops = &msm_uart_pops,
+                       .flags = UPF_BOOT_AUTOCONF,
+                       .fifosize = 512,
+                       .line = 1,
+               },
+       },
+       {
+               .uart = {
+                       .iotype = UPIO_MEM,
+                       .ops = &msm_uart_pops,
+                       .flags = UPF_BOOT_AUTOCONF,
+                       .fifosize = 64,
+                       .line = 2,
+               },
+       },
+};
+
+#define UART_NR        ARRAY_SIZE(msm_uart_ports)
+
+static inline struct uart_port *get_port_from_line(unsigned int line)
+{
+       return &msm_uart_ports[line].uart;
+}
+
+#ifdef CONFIG_SERIAL_MSM_CONSOLE
+
+static void msm_console_putchar(struct uart_port *port, int c)
+{
+       while (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
+               ;
+       msm_write(port, c, UART_TF);
+}
+
+static void msm_console_write(struct console *co, const char *s,
+                             unsigned int count)
+{
+       struct uart_port *port;
+       struct msm_port *msm_port;
+
+       BUG_ON(co->index < 0 || co->index >= UART_NR);
+
+       port = get_port_from_line(co->index);
+       msm_port = UART_TO_MSM(port);
+
+       spin_lock(&port->lock);
+       uart_console_write(port, s, count, msm_console_putchar);
+       spin_unlock(&port->lock);
+}
+
+static int __init msm_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       int baud, flow, bits, parity;
+
+       if (unlikely(co->index >= UART_NR || co->index < 0))
+               return -ENXIO;
+
+       port = get_port_from_line(co->index);
+
+       if (unlikely(!port->membase))
+               return -ENXIO;
+
+       port->cons = co;
+
+       msm_init_clock(port);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       bits = 8;
+       parity = 'n';
+       flow = 'n';
+       msm_write(port, UART_MR2_BITS_PER_CHAR_8 | UART_MR2_STOP_BIT_LEN_ONE,
+                 UART_MR2);    /* 8N1 */
+
+       if (baud < 300 || baud > 115200)
+               baud = 115200;
+       msm_set_baud_rate(port, baud);
+
+       msm_reset(port);
+
+       printk(KERN_INFO "msm_serial: console setup on port #%d\n", port->line);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver msm_uart_driver;
+
+static struct console msm_console = {
+       .name = "ttyMSM",
+       .write = msm_console_write,
+       .device = uart_console_device,
+       .setup = msm_console_setup,
+       .flags = CON_PRINTBUFFER,
+       .index = -1,
+       .data = &msm_uart_driver,
+};
+
+#define MSM_CONSOLE    (&msm_console)
+
+#else
+#define MSM_CONSOLE    NULL
+#endif
+
+static struct uart_driver msm_uart_driver = {
+       .owner = THIS_MODULE,
+       .driver_name = "msm_serial",
+       .dev_name = "ttyMSM",
+       .nr = UART_NR,
+       .cons = MSM_CONSOLE,
+};
+
+static int __init msm_serial_probe(struct platform_device *pdev)
+{
+       struct msm_port *msm_port;
+       struct resource *resource;
+       struct uart_port *port;
+       int irq;
+
+       if (unlikely(pdev->id < 0 || pdev->id >= UART_NR))
+               return -ENXIO;
+
+       printk(KERN_INFO "msm_serial: detected port #%d\n", pdev->id);
+
+       port = get_port_from_line(pdev->id);
+       port->dev = &pdev->dev;
+       msm_port = UART_TO_MSM(port);
+
+       msm_port->clk = clk_get(&pdev->dev, "uart_clk");
+       if (IS_ERR(msm_port->clk))
+               return PTR_ERR(msm_port->clk);
+       port->uartclk = clk_get_rate(msm_port->clk);
+       printk(KERN_INFO "uartclk = %d\n", port->uartclk);
+
+
+       resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (unlikely(!resource))
+               return -ENXIO;
+       port->mapbase = resource->start;
+
+       irq = platform_get_irq(pdev, 0);
+       if (unlikely(irq < 0))
+               return -ENXIO;
+       port->irq = irq;
+
+       platform_set_drvdata(pdev, port);
+
+       return uart_add_one_port(&msm_uart_driver, port);
+}
+
+static int __devexit msm_serial_remove(struct platform_device *pdev)
+{
+       struct msm_port *msm_port = platform_get_drvdata(pdev);
+
+       clk_put(msm_port->clk);
+
+       return 0;
+}
+
+static struct platform_driver msm_platform_driver = {
+       .remove = msm_serial_remove,
+       .driver = {
+               .name = "msm_serial",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init msm_serial_init(void)
+{
+       int ret;
+
+       ret = uart_register_driver(&msm_uart_driver);
+       if (unlikely(ret))
+               return ret;
+
+       ret = platform_driver_probe(&msm_platform_driver, msm_serial_probe);
+       if (unlikely(ret))
+               uart_unregister_driver(&msm_uart_driver);
+
+       printk(KERN_INFO "msm_serial: driver initialized\n");
+
+       return ret;
+}
+
+static void __exit msm_serial_exit(void)
+{
+#ifdef CONFIG_SERIAL_MSM_CONSOLE
+       unregister_console(&msm_console);
+#endif
+       platform_driver_unregister(&msm_platform_driver);
+       uart_unregister_driver(&msm_uart_driver);
+}
+
+module_init(msm_serial_init);
+module_exit(msm_serial_exit);
+
+MODULE_AUTHOR("Robert Love <rlove@google.com>");
+MODULE_DESCRIPTION("Driver for msm7x serial device");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/msm_serial.h b/drivers/tty/serial/msm_serial.h
new file mode 100644 (file)
index 0000000..f6ca9ca
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * drivers/serial/msm_serial.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Robert Love <rlove@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#ifndef __DRIVERS_SERIAL_MSM_SERIAL_H
+#define __DRIVERS_SERIAL_MSM_SERIAL_H
+
+#define UART_MR1                       0x0000
+
+#define UART_MR1_AUTO_RFR_LEVEL0       0x3F
+#define UART_MR1_AUTO_RFR_LEVEL1       0x3FF00
+#define UART_MR1_RX_RDY_CTL                    (1 << 7)
+#define UART_MR1_CTS_CTL                       (1 << 6)
+
+#define UART_MR2                       0x0004
+#define UART_MR2_ERROR_MODE            (1 << 6)
+#define UART_MR2_BITS_PER_CHAR         0x30
+#define UART_MR2_BITS_PER_CHAR_5       (0x0 << 4)
+#define UART_MR2_BITS_PER_CHAR_6       (0x1 << 4)
+#define UART_MR2_BITS_PER_CHAR_7       (0x2 << 4)
+#define UART_MR2_BITS_PER_CHAR_8       (0x3 << 4)
+#define UART_MR2_STOP_BIT_LEN_ONE      (0x1 << 2)
+#define UART_MR2_STOP_BIT_LEN_TWO      (0x3 << 2)
+#define UART_MR2_PARITY_MODE_NONE      0x0
+#define UART_MR2_PARITY_MODE_ODD       0x1
+#define UART_MR2_PARITY_MODE_EVEN      0x2
+#define UART_MR2_PARITY_MODE_SPACE     0x3
+#define UART_MR2_PARITY_MODE           0x3
+
+#define UART_CSR       0x0008
+#define UART_CSR_115200        0xFF
+#define UART_CSR_57600 0xEE
+#define UART_CSR_38400 0xDD
+#define UART_CSR_28800 0xCC
+#define UART_CSR_19200 0xBB
+#define UART_CSR_14400 0xAA
+#define UART_CSR_9600  0x99
+#define UART_CSR_4800  0x77
+#define UART_CSR_2400  0x55
+#define UART_CSR_1200  0x44
+#define UART_CSR_600   0x33
+#define UART_CSR_300   0x22
+
+#define UART_TF                0x000C
+
+#define UART_CR                                0x0010
+#define UART_CR_CMD_NULL               (0 << 4)
+#define UART_CR_CMD_RESET_RX           (1 << 4)
+#define UART_CR_CMD_RESET_TX           (2 << 4)
+#define UART_CR_CMD_RESET_ERR          (3 << 4)
+#define UART_CR_CMD_RESET_BREAK_INT    (4 << 4)
+#define UART_CR_CMD_START_BREAK                (5 << 4)
+#define UART_CR_CMD_STOP_BREAK         (6 << 4)
+#define UART_CR_CMD_RESET_CTS          (7 << 4)
+#define UART_CR_CMD_PACKET_MODE                (9 << 4)
+#define UART_CR_CMD_MODE_RESET         (12 << 4)
+#define UART_CR_CMD_SET_RFR            (13 << 4)
+#define UART_CR_CMD_RESET_RFR          (14 << 4)
+#define UART_CR_TX_DISABLE             (1 << 3)
+#define UART_CR_TX_ENABLE              (1 << 3)
+#define UART_CR_RX_DISABLE             (1 << 3)
+#define UART_CR_RX_ENABLE              (1 << 3)
+
+#define UART_IMR               0x0014
+#define UART_IMR_TXLEV         (1 << 0)
+#define UART_IMR_RXSTALE       (1 << 3)
+#define UART_IMR_RXLEV         (1 << 4)
+#define UART_IMR_DELTA_CTS     (1 << 5)
+#define UART_IMR_CURRENT_CTS   (1 << 6)
+
+#define UART_IPR_RXSTALE_LAST          0x20
+#define UART_IPR_STALE_LSB             0x1F
+#define UART_IPR_STALE_TIMEOUT_MSB     0x3FF80
+
+#define UART_IPR       0x0018
+#define UART_TFWR      0x001C
+#define UART_RFWR      0x0020
+#define UART_HCR       0x0024
+
+#define UART_MREG              0x0028
+#define UART_NREG              0x002C
+#define UART_DREG              0x0030
+#define UART_MNDREG            0x0034
+#define UART_IRDA              0x0038
+#define UART_MISR_MODE         0x0040
+#define UART_MISR_RESET                0x0044
+#define UART_MISR_EXPORT       0x0048
+#define UART_MISR_VAL          0x004C
+#define UART_TEST_CTRL         0x0050
+
+#define UART_SR                        0x0008
+#define UART_SR_HUNT_CHAR      (1 << 7)
+#define UART_SR_RX_BREAK       (1 << 6)
+#define UART_SR_PAR_FRAME_ERR  (1 << 5)
+#define UART_SR_OVERRUN                (1 << 4)
+#define UART_SR_TX_EMPTY       (1 << 3)
+#define UART_SR_TX_READY       (1 << 2)
+#define UART_SR_RX_FULL                (1 << 1)
+#define UART_SR_RX_READY       (1 << 0)
+
+#define UART_RF                0x000C
+#define UART_MISR      0x0010
+#define UART_ISR       0x0014
+
+#define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port)
+
+static inline
+void msm_write(struct uart_port *port, unsigned int val, unsigned int off)
+{
+       __raw_writel(val, port->membase + off);
+}
+
+static inline
+unsigned int msm_read(struct uart_port *port, unsigned int off)
+{
+       return __raw_readl(port->membase + off);
+}
+
+/*
+ * Setup the MND registers to use the TCXO clock.
+ */
+static inline void msm_serial_set_mnd_regs_tcxo(struct uart_port *port)
+{
+       msm_write(port, 0x06, UART_MREG);
+       msm_write(port, 0xF1, UART_NREG);
+       msm_write(port, 0x0F, UART_DREG);
+       msm_write(port, 0x1A, UART_MNDREG);
+}
+
+/*
+ * Setup the MND registers to use the TCXO clock divided by 4.
+ */
+static inline void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port)
+{
+       msm_write(port, 0x18, UART_MREG);
+       msm_write(port, 0xF6, UART_NREG);
+       msm_write(port, 0x0F, UART_DREG);
+       msm_write(port, 0x0A, UART_MNDREG);
+}
+
+static inline
+void msm_serial_set_mnd_regs_from_uartclk(struct uart_port *port)
+{
+       if (port->uartclk == 19200000)
+               msm_serial_set_mnd_regs_tcxo(port);
+       else
+               msm_serial_set_mnd_regs_tcxoby4(port);
+}
+
+/*
+ * TROUT has a specific defect that makes it report it's uartclk
+ * as 19.2Mhz (TCXO) when it's actually 4.8Mhz (TCXO/4). This special
+ * cases TROUT to use the right clock.
+ */
+#ifdef CONFIG_MACH_TROUT
+#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_tcxoby4
+#else
+#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_from_uartclk
+#endif
+
+#endif /* __DRIVERS_SERIAL_MSM_SERIAL_H */
diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c
new file mode 100644 (file)
index 0000000..9711e06
--- /dev/null
@@ -0,0 +1,633 @@
+/*
+** mux.c:
+**     serial driver for the Mux console found in some PA-RISC servers.
+**
+**     (c) Copyright 2002 Ryan Bradetich
+**     (c) Copyright 2002 Hewlett-Packard Company
+**
+** 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 Driver currently only supports the console (port 0) on the MUX.
+** Additional work will be needed on this driver to enable the full
+** functionality of the MUX.
+**
+*/
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/delay.h> /* for udelay */
+#include <linux/device.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/parisc-device.h>
+
+#ifdef CONFIG_MAGIC_SYSRQ
+#include <linux/sysrq.h>
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#define MUX_OFFSET 0x800
+#define MUX_LINE_OFFSET 0x80
+
+#define MUX_FIFO_SIZE 255
+#define MUX_POLL_DELAY (30 * HZ / 1000)
+
+#define IO_DATA_REG_OFFSET 0x3c
+#define IO_DCOUNT_REG_OFFSET 0x40
+
+#define MUX_EOFIFO(status) ((status & 0xF000) == 0xF000)
+#define MUX_STATUS(status) ((status & 0xF000) == 0x8000)
+#define MUX_BREAK(status) ((status & 0xF000) == 0x2000)
+
+#define MUX_NR 256
+static unsigned int port_cnt __read_mostly;
+struct mux_port {
+       struct uart_port port;
+       int enabled;
+};
+static struct mux_port mux_ports[MUX_NR];
+
+static struct uart_driver mux_driver = {
+       .owner = THIS_MODULE,
+       .driver_name = "ttyB",
+       .dev_name = "ttyB",
+       .major = MUX_MAJOR,
+       .minor = 0,
+       .nr = MUX_NR,
+};
+
+static struct timer_list mux_timer;
+
+#define UART_PUT_CHAR(p, c) __raw_writel((c), (p)->membase + IO_DATA_REG_OFFSET)
+#define UART_GET_FIFO_CNT(p) __raw_readl((p)->membase + IO_DCOUNT_REG_OFFSET)
+
+/**
+ * get_mux_port_count - Get the number of available ports on the Mux.
+ * @dev: The parisc device.
+ *
+ * This function is used to determine the number of ports the Mux
+ * supports.  The IODC data reports the number of ports the Mux
+ * can support, but there are cases where not all the Mux ports
+ * are connected.  This function can override the IODC and
+ * return the true port count.
+ */
+static int __init get_mux_port_count(struct parisc_device *dev)
+{
+       int status;
+       u8 iodc_data[32];
+       unsigned long bytecnt;
+
+       /* If this is the built-in Mux for the K-Class (Eole CAP/MUX),
+        * we only need to allocate resources for 1 port since the
+        * other 7 ports are not connected.
+        */
+       if(dev->id.hversion == 0x15)
+               return 1;
+
+       status = pdc_iodc_read(&bytecnt, dev->hpa.start, 0, iodc_data, 32);
+       BUG_ON(status != PDC_OK);
+
+       /* Return the number of ports specified in the iodc data. */
+       return ((((iodc_data)[4] & 0xf0) >> 4) * 8) + 8;
+}
+
+/**
+ * mux_tx_empty - Check if the transmitter fifo is empty.
+ * @port: Ptr to the uart_port.
+ *
+ * This function test if the transmitter fifo for the port
+ * described by 'port' is empty.  If it is empty, this function
+ * should return TIOCSER_TEMT, otherwise return 0.
+ */
+static unsigned int mux_tx_empty(struct uart_port *port)
+{
+       return UART_GET_FIFO_CNT(port) ? 0 : TIOCSER_TEMT;
+} 
+
+/**
+ * mux_set_mctrl - Set the current state of the modem control inputs.
+ * @ports: Ptr to the uart_port.
+ * @mctrl: Modem control bits.
+ *
+ * The Serial MUX does not support CTS, DCD or DSR so this function
+ * is ignored.
+ */
+static void mux_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+/**
+ * mux_get_mctrl - Returns the current state of modem control inputs.
+ * @port: Ptr to the uart_port.
+ *
+ * The Serial MUX does not support CTS, DCD or DSR so these lines are
+ * treated as permanently active.
+ */
+static unsigned int mux_get_mctrl(struct uart_port *port)
+{ 
+       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+/**
+ * mux_stop_tx - Stop transmitting characters.
+ * @port: Ptr to the uart_port.
+ *
+ * The Serial MUX does not support this function.
+ */
+static void mux_stop_tx(struct uart_port *port)
+{
+}
+
+/**
+ * mux_start_tx - Start transmitting characters.
+ * @port: Ptr to the uart_port.
+ *
+ * The Serial Mux does not support this function.
+ */
+static void mux_start_tx(struct uart_port *port)
+{
+}
+
+/**
+ * mux_stop_rx - Stop receiving characters.
+ * @port: Ptr to the uart_port.
+ *
+ * The Serial Mux does not support this function.
+ */
+static void mux_stop_rx(struct uart_port *port)
+{
+}
+
+/**
+ * mux_enable_ms - Enable modum status interrupts.
+ * @port: Ptr to the uart_port.
+ *
+ * The Serial Mux does not support this function.
+ */
+static void mux_enable_ms(struct uart_port *port)
+{
+}
+
+/**
+ * mux_break_ctl - Control the transmitssion of a break signal.
+ * @port: Ptr to the uart_port.
+ * @break_state: Raise/Lower the break signal.
+ *
+ * The Serial Mux does not support this function.
+ */
+static void mux_break_ctl(struct uart_port *port, int break_state)
+{
+}
+
+/**
+ * mux_write - Write chars to the mux fifo.
+ * @port: Ptr to the uart_port.
+ *
+ * This function writes all the data from the uart buffer to
+ * the mux fifo.
+ */
+static void mux_write(struct uart_port *port)
+{
+       int count;
+       struct circ_buf *xmit = &port->state->xmit;
+
+       if(port->x_char) {
+               UART_PUT_CHAR(port, port->x_char);
+               port->icount.tx++;
+               port->x_char = 0;
+               return;
+       }
+
+       if(uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               mux_stop_tx(port);
+               return;
+       }
+
+       count = (port->fifosize) - UART_GET_FIFO_CNT(port);
+       do {
+               UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               if(uart_circ_empty(xmit))
+                       break;
+
+       } while(--count > 0);
+
+       while(UART_GET_FIFO_CNT(port)) 
+               udelay(1);
+
+       if(uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit))
+               mux_stop_tx(port);
+}
+
+/**
+ * mux_read - Read chars from the mux fifo.
+ * @port: Ptr to the uart_port.
+ *
+ * This reads all available data from the mux's fifo and pushes
+ * the data to the tty layer.
+ */
+static void mux_read(struct uart_port *port)
+{
+       int data;
+       struct tty_struct *tty = port->state->port.tty;
+       __u32 start_count = port->icount.rx;
+
+       while(1) {
+               data = __raw_readl(port->membase + IO_DATA_REG_OFFSET);
+
+               if (MUX_STATUS(data))
+                       continue;
+
+               if (MUX_EOFIFO(data))
+                       break;
+
+               port->icount.rx++;
+
+               if (MUX_BREAK(data)) {
+                       port->icount.brk++;
+                       if(uart_handle_break(port))
+                               continue;
+               }
+
+               if (uart_handle_sysrq_char(port, data & 0xffu))
+                       continue;
+
+               tty_insert_flip_char(tty, data & 0xFF, TTY_NORMAL);
+       }
+       
+       if (start_count != port->icount.rx) {
+               tty_flip_buffer_push(tty);
+       }
+}
+
+/**
+ * mux_startup - Initialize the port.
+ * @port: Ptr to the uart_port.
+ *
+ * Grab any resources needed for this port and start the
+ * mux timer.
+ */
+static int mux_startup(struct uart_port *port)
+{
+       mux_ports[port->line].enabled = 1;
+       return 0;
+}
+
+/**
+ * mux_shutdown - Disable the port.
+ * @port: Ptr to the uart_port.
+ *
+ * Release any resources needed for the port.
+ */
+static void mux_shutdown(struct uart_port *port)
+{
+       mux_ports[port->line].enabled = 0;
+}
+
+/**
+ * mux_set_termios - Chane port parameters.
+ * @port: Ptr to the uart_port.
+ * @termios: new termios settings.
+ * @old: old termios settings.
+ *
+ * The Serial Mux does not support this function.
+ */
+static void
+mux_set_termios(struct uart_port *port, struct ktermios *termios,
+               struct ktermios *old)
+{
+}
+
+/**
+ * mux_type - Describe the port.
+ * @port: Ptr to the uart_port.
+ *
+ * Return a pointer to a string constant describing the
+ * specified port.
+ */
+static const char *mux_type(struct uart_port *port)
+{
+       return "Mux";
+}
+
+/**
+ * mux_release_port - Release memory and IO regions.
+ * @port: Ptr to the uart_port.
+ * 
+ * Release any memory and IO region resources currently in use by
+ * the port.
+ */
+static void mux_release_port(struct uart_port *port)
+{
+}
+
+/**
+ * mux_request_port - Request memory and IO regions.
+ * @port: Ptr to the uart_port.
+ *
+ * Request any memory and IO region resources required by the port.
+ * If any fail, no resources should be registered when this function
+ * returns, and it should return -EBUSY on failure.
+ */
+static int mux_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+/**
+ * mux_config_port - Perform port autoconfiguration.
+ * @port: Ptr to the uart_port.
+ * @type: Bitmask of required configurations.
+ *
+ * Perform any autoconfiguration steps for the port.  This function is
+ * called if the UPF_BOOT_AUTOCONF flag is specified for the port.
+ * [Note: This is required for now because of a bug in the Serial core.
+ *  rmk has already submitted a patch to linus, should be available for
+ *  2.5.47.]
+ */
+static void mux_config_port(struct uart_port *port, int type)
+{
+       port->type = PORT_MUX;
+}
+
+/**
+ * mux_verify_port - Verify the port information.
+ * @port: Ptr to the uart_port.
+ * @ser: Ptr to the serial information.
+ *
+ * Verify the new serial port information contained within serinfo is
+ * suitable for this port type.
+ */
+static int mux_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       if(port->membase == NULL)
+               return -EINVAL;
+
+       return 0;
+}
+
+/**
+ * mux_drv_poll - Mux poll function.
+ * @unused: Unused variable
+ *
+ * This function periodically polls the Serial MUX to check for new data.
+ */
+static void mux_poll(unsigned long unused)
+{  
+       int i;
+
+       for(i = 0; i < port_cnt; ++i) {
+               if(!mux_ports[i].enabled)
+                       continue;
+
+               mux_read(&mux_ports[i].port);
+               mux_write(&mux_ports[i].port);
+       }
+
+       mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY);
+}
+
+
+#ifdef CONFIG_SERIAL_MUX_CONSOLE
+static void mux_console_write(struct console *co, const char *s, unsigned count)
+{
+       /* Wait until the FIFO drains. */
+       while(UART_GET_FIFO_CNT(&mux_ports[0].port))
+               udelay(1);
+
+       while(count--) {
+               if(*s == '\n') {
+                       UART_PUT_CHAR(&mux_ports[0].port, '\r');
+               }
+               UART_PUT_CHAR(&mux_ports[0].port, *s++);
+       }
+
+}
+
+static int mux_console_setup(struct console *co, char *options)
+{
+        return 0;
+}
+
+struct tty_driver *mux_console_device(struct console *co, int *index)
+{
+        *index = co->index;
+       return mux_driver.tty_driver;
+}
+
+static struct console mux_console = {
+       .name =         "ttyB",
+       .write =        mux_console_write,
+       .device =       mux_console_device,
+       .setup =        mux_console_setup,
+       .flags =        CON_ENABLED | CON_PRINTBUFFER,
+       .index =        0,
+};
+
+#define MUX_CONSOLE    &mux_console
+#else
+#define MUX_CONSOLE    NULL
+#endif
+
+static struct uart_ops mux_pops = {
+       .tx_empty =             mux_tx_empty,
+       .set_mctrl =            mux_set_mctrl,
+       .get_mctrl =            mux_get_mctrl,
+       .stop_tx =              mux_stop_tx,
+       .start_tx =             mux_start_tx,
+       .stop_rx =              mux_stop_rx,
+       .enable_ms =            mux_enable_ms,
+       .break_ctl =            mux_break_ctl,
+       .startup =              mux_startup,
+       .shutdown =             mux_shutdown,
+       .set_termios =          mux_set_termios,
+       .type =                 mux_type,
+       .release_port =         mux_release_port,
+       .request_port =         mux_request_port,
+       .config_port =          mux_config_port,
+       .verify_port =          mux_verify_port,
+};
+
+/**
+ * mux_probe - Determine if the Serial Mux should claim this device.
+ * @dev: The parisc device.
+ *
+ * Deterimine if the Serial Mux should claim this chip (return 0)
+ * or not (return 1).
+ */
+static int __init mux_probe(struct parisc_device *dev)
+{
+       int i, status;
+
+       int port_count = get_mux_port_count(dev);
+       printk(KERN_INFO "Serial mux driver (%d ports) Revision: 0.6\n", port_count);
+
+       dev_set_drvdata(&dev->dev, (void *)(long)port_count);
+       request_mem_region(dev->hpa.start + MUX_OFFSET,
+                           port_count * MUX_LINE_OFFSET, "Mux");
+
+       if(!port_cnt) {
+               mux_driver.cons = MUX_CONSOLE;
+
+               status = uart_register_driver(&mux_driver);
+               if(status) {
+                       printk(KERN_ERR "Serial mux: Unable to register driver.\n");
+                       return 1;
+               }
+       }
+
+       for(i = 0; i < port_count; ++i, ++port_cnt) {
+               struct uart_port *port = &mux_ports[port_cnt].port;
+               port->iobase    = 0;
+               port->mapbase   = dev->hpa.start + MUX_OFFSET +
+                                               (i * MUX_LINE_OFFSET);
+               port->membase   = ioremap_nocache(port->mapbase, MUX_LINE_OFFSET);
+               port->iotype    = UPIO_MEM;
+               port->type      = PORT_MUX;
+               port->irq       = NO_IRQ;
+               port->uartclk   = 0;
+               port->fifosize  = MUX_FIFO_SIZE;
+               port->ops       = &mux_pops;
+               port->flags     = UPF_BOOT_AUTOCONF;
+               port->line      = port_cnt;
+
+               /* The port->timeout needs to match what is present in
+                * uart_wait_until_sent in serial_core.c.  Otherwise
+                * the time spent in msleep_interruptable will be very
+                * long, causing the appearance of a console hang.
+                */
+               port->timeout   = HZ / 50;
+               spin_lock_init(&port->lock);
+
+               status = uart_add_one_port(&mux_driver, port);
+               BUG_ON(status);
+       }
+
+       return 0;
+}
+
+static int __devexit mux_remove(struct parisc_device *dev)
+{
+       int i, j;
+       int port_count = (long)dev_get_drvdata(&dev->dev);
+
+       /* Find Port 0 for this card in the mux_ports list. */
+       for(i = 0; i < port_cnt; ++i) {
+               if(mux_ports[i].port.mapbase == dev->hpa.start + MUX_OFFSET)
+                       break;
+       }
+       BUG_ON(i + port_count > port_cnt);
+
+       /* Release the resources associated with each port on the device. */
+       for(j = 0; j < port_count; ++j, ++i) {
+               struct uart_port *port = &mux_ports[i].port;
+
+               uart_remove_one_port(&mux_driver, port);
+               if(port->membase)
+                       iounmap(port->membase);
+       }
+
+       release_mem_region(dev->hpa.start + MUX_OFFSET, port_count * MUX_LINE_OFFSET);
+       return 0;
+}
+
+/* Hack.  This idea was taken from the 8250_gsc.c on how to properly order
+ * the serial port detection in the proper order.   The idea is we always
+ * want the builtin mux to be detected before addin mux cards, so we
+ * specifically probe for the builtin mux cards first.
+ *
+ * This table only contains the parisc_device_id of known builtin mux
+ * devices.  All other mux cards will be detected by the generic mux_tbl.
+ */
+static struct parisc_device_id builtin_mux_tbl[] = {
+       { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, 0x15, 0x0000D }, /* All K-class */
+       { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, 0x44, 0x0000D }, /* E35, E45, and E55 */
+       { 0, }
+};
+
+static struct parisc_device_id mux_tbl[] = {
+       { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0000D },
+       { 0, }
+};
+
+MODULE_DEVICE_TABLE(parisc, builtin_mux_tbl);
+MODULE_DEVICE_TABLE(parisc, mux_tbl);
+
+static struct parisc_driver builtin_serial_mux_driver = {
+       .name =         "builtin_serial_mux",
+       .id_table =     builtin_mux_tbl,
+       .probe =        mux_probe,
+       .remove =       __devexit_p(mux_remove),
+};
+
+static struct parisc_driver serial_mux_driver = {
+       .name =         "serial_mux",
+       .id_table =     mux_tbl,
+       .probe =        mux_probe,
+       .remove =       __devexit_p(mux_remove),
+};
+
+/**
+ * mux_init - Serial MUX initialization procedure.
+ *
+ * Register the Serial MUX driver.
+ */
+static int __init mux_init(void)
+{
+       register_parisc_driver(&builtin_serial_mux_driver);
+       register_parisc_driver(&serial_mux_driver);
+
+       if(port_cnt > 0) {
+               /* Start the Mux timer */
+               init_timer(&mux_timer);
+               mux_timer.function = mux_poll;
+               mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY);
+
+#ifdef CONFIG_SERIAL_MUX_CONSOLE
+               register_console(&mux_console);
+#endif
+       }
+
+       return 0;
+}
+
+/**
+ * mux_exit - Serial MUX cleanup procedure.
+ *
+ * Unregister the Serial MUX driver from the tty layer.
+ */
+static void __exit mux_exit(void)
+{
+       /* Delete the Mux timer. */
+       if(port_cnt > 0) {
+               del_timer(&mux_timer);
+#ifdef CONFIG_SERIAL_MUX_CONSOLE
+               unregister_console(&mux_console);
+#endif
+       }
+
+       unregister_parisc_driver(&builtin_serial_mux_driver);
+       unregister_parisc_driver(&serial_mux_driver);
+       uart_unregister_driver(&mux_driver);
+}
+
+module_init(mux_init);
+module_exit(mux_exit);
+
+MODULE_AUTHOR("Ryan Bradetich");
+MODULE_DESCRIPTION("Serial MUX driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(MUX_MAJOR);
diff --git a/drivers/tty/serial/netx-serial.c b/drivers/tty/serial/netx-serial.c
new file mode 100644 (file)
index 0000000..7735c9f
--- /dev/null
@@ -0,0 +1,750 @@
+/*
+ * drivers/serial/netx-serial.c
+ *
+ * Copyright (c) 2005 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * 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
+ */
+
+#if defined(CONFIG_SERIAL_NETX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <mach/hardware.h>
+#include <mach/netx-regs.h>
+
+/* We've been assigned a range on the "Low-density serial ports" major */
+#define SERIAL_NX_MAJOR        204
+#define MINOR_START    170
+
+enum uart_regs {
+       UART_DR              = 0x00,
+       UART_SR              = 0x04,
+       UART_LINE_CR         = 0x08,
+       UART_BAUDDIV_MSB     = 0x0c,
+       UART_BAUDDIV_LSB     = 0x10,
+       UART_CR              = 0x14,
+       UART_FR              = 0x18,
+       UART_IIR             = 0x1c,
+       UART_ILPR            = 0x20,
+       UART_RTS_CR          = 0x24,
+       UART_RTS_LEAD        = 0x28,
+       UART_RTS_TRAIL       = 0x2c,
+       UART_DRV_ENABLE      = 0x30,
+       UART_BRM_CR          = 0x34,
+       UART_RXFIFO_IRQLEVEL = 0x38,
+       UART_TXFIFO_IRQLEVEL = 0x3c,
+};
+
+#define SR_FE (1<<0)
+#define SR_PE (1<<1)
+#define SR_BE (1<<2)
+#define SR_OE (1<<3)
+
+#define LINE_CR_BRK       (1<<0)
+#define LINE_CR_PEN       (1<<1)
+#define LINE_CR_EPS       (1<<2)
+#define LINE_CR_STP2      (1<<3)
+#define LINE_CR_FEN       (1<<4)
+#define LINE_CR_5BIT      (0<<5)
+#define LINE_CR_6BIT      (1<<5)
+#define LINE_CR_7BIT      (2<<5)
+#define LINE_CR_8BIT      (3<<5)
+#define LINE_CR_BITS_MASK (3<<5)
+
+#define CR_UART_EN (1<<0)
+#define CR_SIREN   (1<<1)
+#define CR_SIRLP   (1<<2)
+#define CR_MSIE    (1<<3)
+#define CR_RIE     (1<<4)
+#define CR_TIE     (1<<5)
+#define CR_RTIE    (1<<6)
+#define CR_LBE     (1<<7)
+
+#define FR_CTS  (1<<0)
+#define FR_DSR  (1<<1)
+#define FR_DCD  (1<<2)
+#define FR_BUSY (1<<3)
+#define FR_RXFE (1<<4)
+#define FR_TXFF (1<<5)
+#define FR_RXFF (1<<6)
+#define FR_TXFE (1<<7)
+
+#define IIR_MIS (1<<0)
+#define IIR_RIS (1<<1)
+#define IIR_TIS (1<<2)
+#define IIR_RTIS (1<<3)
+#define IIR_MASK 0xf
+
+#define RTS_CR_AUTO (1<<0)
+#define RTS_CR_RTS  (1<<1)
+#define RTS_CR_COUNT (1<<2)
+#define RTS_CR_MOD2  (1<<3)
+#define RTS_CR_RTS_POL (1<<4)
+#define RTS_CR_CTS_CTR (1<<5)
+#define RTS_CR_CTS_POL (1<<6)
+#define RTS_CR_STICK   (1<<7)
+
+#define UART_PORT_SIZE 0x40
+#define DRIVER_NAME "netx-uart"
+
+struct netx_port {
+       struct uart_port        port;
+};
+
+static void netx_stop_tx(struct uart_port *port)
+{
+       unsigned int val;
+       val = readl(port->membase + UART_CR);
+       writel(val & ~CR_TIE,  port->membase + UART_CR);
+}
+
+static void netx_stop_rx(struct uart_port *port)
+{
+       unsigned int val;
+       val = readl(port->membase + UART_CR);
+       writel(val & ~CR_RIE,  port->membase + UART_CR);
+}
+
+static void netx_enable_ms(struct uart_port *port)
+{
+       unsigned int val;
+       val = readl(port->membase + UART_CR);
+       writel(val | CR_MSIE, port->membase + UART_CR);
+}
+
+static inline void netx_transmit_buffer(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->state->xmit;
+
+       if (port->x_char) {
+               writel(port->x_char, port->membase + UART_DR);
+               port->icount.tx++;
+               port->x_char = 0;
+               return;
+       }
+
+       if (uart_tx_stopped(port) || uart_circ_empty(xmit)) {
+               netx_stop_tx(port);
+               return;
+       }
+
+       do {
+               /* send xmit->buf[xmit->tail]
+                * out the port here */
+               writel(xmit->buf[xmit->tail], port->membase + UART_DR);
+               xmit->tail = (xmit->tail + 1) &
+                        (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (!(readl(port->membase + UART_FR) & FR_TXFF));
+
+       if (uart_circ_empty(xmit))
+               netx_stop_tx(port);
+}
+
+static void netx_start_tx(struct uart_port *port)
+{
+       writel(
+           readl(port->membase + UART_CR) | CR_TIE, port->membase + UART_CR);
+
+       if (!(readl(port->membase + UART_FR) & FR_TXFF))
+               netx_transmit_buffer(port);
+}
+
+static unsigned int netx_tx_empty(struct uart_port *port)
+{
+       return readl(port->membase + UART_FR) & FR_BUSY ? 0 : TIOCSER_TEMT;
+}
+
+static void netx_txint(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->state->xmit;
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               netx_stop_tx(port);
+               return;
+       }
+
+       netx_transmit_buffer(port);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+}
+
+static void netx_rxint(struct uart_port *port)
+{
+       unsigned char rx, flg, status;
+       struct tty_struct *tty = port->state->port.tty;
+
+       while (!(readl(port->membase + UART_FR) & FR_RXFE)) {
+               rx = readl(port->membase + UART_DR);
+               flg = TTY_NORMAL;
+               port->icount.rx++;
+               status = readl(port->membase + UART_SR);
+               if (status & SR_BE) {
+                       writel(0, port->membase + UART_SR);
+                       if (uart_handle_break(port))
+                               continue;
+               }
+
+               if (unlikely(status & (SR_FE | SR_PE | SR_OE))) {
+
+                       if (status & SR_PE)
+                               port->icount.parity++;
+                       else if (status & SR_FE)
+                               port->icount.frame++;
+                       if (status & SR_OE)
+                               port->icount.overrun++;
+
+                       status &= port->read_status_mask;
+
+                       if (status & SR_BE)
+                               flg = TTY_BREAK;
+                       else if (status & SR_PE)
+                               flg = TTY_PARITY;
+                       else if (status & SR_FE)
+                               flg = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(port, rx))
+                       continue;
+
+               uart_insert_char(port, status, SR_OE, rx, flg);
+       }
+
+       tty_flip_buffer_push(tty);
+       return;
+}
+
+static irqreturn_t netx_int(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       unsigned long flags;
+       unsigned char status;
+
+       spin_lock_irqsave(&port->lock,flags);
+
+       status = readl(port->membase + UART_IIR) & IIR_MASK;
+       while (status) {
+               if (status & IIR_RIS)
+                       netx_rxint(port);
+               if (status & IIR_TIS)
+                       netx_txint(port);
+               if (status & IIR_MIS) {
+                       if (readl(port->membase + UART_FR) & FR_CTS)
+                               uart_handle_cts_change(port, 1);
+                       else
+                               uart_handle_cts_change(port, 0);
+               }
+               writel(0, port->membase + UART_IIR);
+               status = readl(port->membase + UART_IIR) & IIR_MASK;
+       }
+
+       spin_unlock_irqrestore(&port->lock,flags);
+       return IRQ_HANDLED;
+}
+
+static unsigned int netx_get_mctrl(struct uart_port *port)
+{
+       unsigned int ret = TIOCM_DSR | TIOCM_CAR;
+
+       if (readl(port->membase + UART_FR) & FR_CTS)
+               ret |= TIOCM_CTS;
+
+       return ret;
+}
+
+static void netx_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       unsigned int val;
+
+       /* FIXME: Locking needed ? */
+       if (mctrl & TIOCM_RTS) {
+               val = readl(port->membase + UART_RTS_CR);
+               writel(val | RTS_CR_RTS, port->membase + UART_RTS_CR);
+       }
+}
+
+static void netx_break_ctl(struct uart_port *port, int break_state)
+{
+       unsigned int line_cr;
+       spin_lock_irq(&port->lock);
+
+       line_cr = readl(port->membase + UART_LINE_CR);
+       if (break_state != 0)
+               line_cr |= LINE_CR_BRK;
+       else
+               line_cr &= ~LINE_CR_BRK;
+       writel(line_cr, port->membase + UART_LINE_CR);
+
+       spin_unlock_irq(&port->lock);
+}
+
+static int netx_startup(struct uart_port *port)
+{
+       int ret;
+
+       ret = request_irq(port->irq, netx_int, 0,
+                            DRIVER_NAME, port);
+       if (ret) {
+               dev_err(port->dev, "unable to grab irq%d\n",port->irq);
+               goto exit;
+       }
+
+       writel(readl(port->membase + UART_LINE_CR) | LINE_CR_FEN,
+               port->membase + UART_LINE_CR);
+
+       writel(CR_MSIE | CR_RIE | CR_TIE | CR_RTIE | CR_UART_EN,
+               port->membase + UART_CR);
+
+exit:
+       return ret;
+}
+
+static void netx_shutdown(struct uart_port *port)
+{
+       writel(0, port->membase + UART_CR) ;
+
+       free_irq(port->irq, port);
+}
+
+static void
+netx_set_termios(struct uart_port *port, struct ktermios *termios,
+                  struct ktermios *old)
+{
+       unsigned int baud, quot;
+       unsigned char old_cr;
+       unsigned char line_cr = LINE_CR_FEN;
+       unsigned char rts_cr = 0;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               line_cr |= LINE_CR_5BIT;
+               break;
+       case CS6:
+               line_cr |= LINE_CR_6BIT;
+               break;
+       case CS7:
+               line_cr |= LINE_CR_7BIT;
+               break;
+       case CS8:
+               line_cr |= LINE_CR_8BIT;
+               break;
+       }
+
+       if (termios->c_cflag & CSTOPB)
+               line_cr |= LINE_CR_STP2;
+
+       if (termios->c_cflag & PARENB) {
+               line_cr |= LINE_CR_PEN;
+               if (!(termios->c_cflag & PARODD))
+                       line_cr |= LINE_CR_EPS;
+       }
+
+       if (termios->c_cflag & CRTSCTS)
+               rts_cr = RTS_CR_AUTO | RTS_CR_CTS_CTR | RTS_CR_RTS_POL;
+
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+       quot = baud * 4096;
+       quot /= 1000;
+       quot *= 256;
+       quot /= 100000;
+
+       spin_lock_irq(&port->lock);
+
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       old_cr = readl(port->membase + UART_CR);
+
+       /* disable interrupts */
+       writel(old_cr & ~(CR_MSIE | CR_RIE | CR_TIE | CR_RTIE),
+               port->membase + UART_CR);
+
+       /* drain transmitter */
+       while (readl(port->membase + UART_FR) & FR_BUSY);
+
+       /* disable UART */
+       writel(old_cr & ~CR_UART_EN, port->membase + UART_CR);
+
+       /* modem status interrupts */
+       old_cr &= ~CR_MSIE;
+       if (UART_ENABLE_MS(port, termios->c_cflag))
+               old_cr |= CR_MSIE;
+
+       writel((quot>>8) & 0xff, port->membase + UART_BAUDDIV_MSB);
+       writel(quot & 0xff, port->membase + UART_BAUDDIV_LSB);
+       writel(line_cr, port->membase + UART_LINE_CR);
+
+       writel(rts_cr, port->membase + UART_RTS_CR);
+
+       /*
+        * Characters to ignore
+        */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= SR_PE;
+       if (termios->c_iflag & IGNBRK) {
+               port->ignore_status_mask |= SR_BE;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       port->ignore_status_mask |= SR_PE;
+       }
+
+       port->read_status_mask = 0;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               port->read_status_mask |= SR_BE;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= SR_PE | SR_FE;
+
+       writel(old_cr, port->membase + UART_CR);
+
+       spin_unlock_irq(&port->lock);
+}
+
+static const char *netx_type(struct uart_port *port)
+{
+       return port->type == PORT_NETX ? "NETX" : NULL;
+}
+
+static void netx_release_port(struct uart_port *port)
+{
+       release_mem_region(port->mapbase, UART_PORT_SIZE);
+}
+
+static int netx_request_port(struct uart_port *port)
+{
+       return request_mem_region(port->mapbase, UART_PORT_SIZE,
+                       DRIVER_NAME) != NULL ? 0 : -EBUSY;
+}
+
+static void netx_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE && netx_request_port(port) == 0)
+               port->type = PORT_NETX;
+}
+
+static int
+netx_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       int ret = 0;
+
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_NETX)
+               ret = -EINVAL;
+
+       return ret;
+}
+
+static struct uart_ops netx_pops = {
+       .tx_empty       = netx_tx_empty,
+       .set_mctrl      = netx_set_mctrl,
+       .get_mctrl      = netx_get_mctrl,
+       .stop_tx        = netx_stop_tx,
+       .start_tx       = netx_start_tx,
+       .stop_rx        = netx_stop_rx,
+       .enable_ms      = netx_enable_ms,
+       .break_ctl      = netx_break_ctl,
+       .startup        = netx_startup,
+       .shutdown       = netx_shutdown,
+       .set_termios    = netx_set_termios,
+       .type           = netx_type,
+       .release_port   = netx_release_port,
+       .request_port   = netx_request_port,
+       .config_port    = netx_config_port,
+       .verify_port    = netx_verify_port,
+};
+
+static struct netx_port netx_ports[] = {
+       {
+       .port = {
+               .type = PORT_NETX,
+               .iotype = UPIO_MEM,
+               .membase = (char __iomem *)io_p2v(NETX_PA_UART0),
+               .mapbase = NETX_PA_UART0,
+               .irq = NETX_IRQ_UART0,
+               .uartclk = 100000000,
+               .fifosize = 16,
+               .flags = UPF_BOOT_AUTOCONF,
+               .ops = &netx_pops,
+               .line = 0,
+       },
+       }, {
+       .port = {
+               .type = PORT_NETX,
+               .iotype = UPIO_MEM,
+               .membase = (char __iomem *)io_p2v(NETX_PA_UART1),
+               .mapbase = NETX_PA_UART1,
+               .irq = NETX_IRQ_UART1,
+               .uartclk = 100000000,
+               .fifosize = 16,
+               .flags = UPF_BOOT_AUTOCONF,
+               .ops = &netx_pops,
+               .line = 1,
+       },
+       }, {
+       .port = {
+               .type = PORT_NETX,
+               .iotype = UPIO_MEM,
+               .membase = (char __iomem *)io_p2v(NETX_PA_UART2),
+               .mapbase = NETX_PA_UART2,
+               .irq = NETX_IRQ_UART2,
+               .uartclk = 100000000,
+               .fifosize = 16,
+               .flags = UPF_BOOT_AUTOCONF,
+               .ops = &netx_pops,
+               .line = 2,
+       },
+       }
+};
+
+#ifdef CONFIG_SERIAL_NETX_CONSOLE
+
+static void netx_console_putchar(struct uart_port *port, int ch)
+{
+       while (readl(port->membase + UART_FR) & FR_BUSY);
+       writel(ch, port->membase + UART_DR);
+}
+
+static void
+netx_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct uart_port *port = &netx_ports[co->index].port;
+       unsigned char cr_save;
+
+       cr_save = readl(port->membase + UART_CR);
+       writel(cr_save | CR_UART_EN, port->membase + UART_CR);
+
+       uart_console_write(port, s, count, netx_console_putchar);
+
+       while (readl(port->membase + UART_FR) & FR_BUSY);
+       writel(cr_save, port->membase + UART_CR);
+}
+
+static void __init
+netx_console_get_options(struct uart_port *port, int *baud,
+                       int *parity, int *bits, int *flow)
+{
+       unsigned char line_cr;
+
+       *baud = (readl(port->membase + UART_BAUDDIV_MSB) << 8) |
+               readl(port->membase + UART_BAUDDIV_LSB);
+       *baud *= 1000;
+       *baud /= 4096;
+       *baud *= 1000;
+       *baud /= 256;
+       *baud *= 100;
+
+       line_cr = readl(port->membase + UART_LINE_CR);
+       *parity = 'n';
+       if (line_cr & LINE_CR_PEN) {
+               if (line_cr & LINE_CR_EPS)
+                       *parity = 'e';
+               else
+                       *parity = 'o';
+       }
+
+       switch (line_cr & LINE_CR_BITS_MASK) {
+       case LINE_CR_8BIT:
+               *bits = 8;
+               break;
+       case LINE_CR_7BIT:
+               *bits = 7;
+               break;
+       case LINE_CR_6BIT:
+               *bits = 6;
+               break;
+       case LINE_CR_5BIT:
+               *bits = 5;
+               break;
+       }
+
+       if (readl(port->membase + UART_RTS_CR) & RTS_CR_AUTO)
+               *flow = 'r';
+}
+
+static int __init
+netx_console_setup(struct console *co, char *options)
+{
+       struct netx_port *sport;
+       int baud = 9600;
+       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.
+        */
+       if (co->index == -1 || co->index >= ARRAY_SIZE(netx_ports))
+               co->index = 0;
+       sport = &netx_ports[co->index];
+
+       if (options) {
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       } else {
+               /* if the UART is enabled, assume it has been correctly setup
+                * by the bootloader and get the options
+                */
+               if (readl(sport->port.membase + UART_CR) & CR_UART_EN) {
+                       netx_console_get_options(&sport->port, &baud,
+                       &parity, &bits, &flow);
+               }
+
+       }
+
+       return uart_set_options(&sport->port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver netx_reg;
+static struct console netx_console = {
+       .name           = "ttyNX",
+       .write          = netx_console_write,
+       .device         = uart_console_device,
+       .setup          = netx_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &netx_reg,
+};
+
+static int __init netx_console_init(void)
+{
+       register_console(&netx_console);
+       return 0;
+}
+console_initcall(netx_console_init);
+
+#define NETX_CONSOLE   &netx_console
+#else
+#define NETX_CONSOLE   NULL
+#endif
+
+static struct uart_driver netx_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = DRIVER_NAME,
+       .dev_name       = "ttyNX",
+       .major          = SERIAL_NX_MAJOR,
+       .minor          = MINOR_START,
+       .nr             = ARRAY_SIZE(netx_ports),
+       .cons           = NETX_CONSOLE,
+};
+
+static int serial_netx_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct netx_port *sport = platform_get_drvdata(pdev);
+
+       if (sport)
+               uart_suspend_port(&netx_reg, &sport->port);
+
+       return 0;
+}
+
+static int serial_netx_resume(struct platform_device *pdev)
+{
+       struct netx_port *sport = platform_get_drvdata(pdev);
+
+       if (sport)
+               uart_resume_port(&netx_reg, &sport->port);
+
+       return 0;
+}
+
+static int serial_netx_probe(struct platform_device *pdev)
+{
+       struct uart_port *port = &netx_ports[pdev->id].port;
+
+       dev_info(&pdev->dev, "initialising\n");
+
+       port->dev = &pdev->dev;
+
+       writel(1, port->membase + UART_RXFIFO_IRQLEVEL);
+       uart_add_one_port(&netx_reg, &netx_ports[pdev->id].port);
+       platform_set_drvdata(pdev, &netx_ports[pdev->id]);
+
+       return 0;
+}
+
+static int serial_netx_remove(struct platform_device *pdev)
+{
+       struct netx_port *sport = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+
+       if (sport)
+               uart_remove_one_port(&netx_reg, &sport->port);
+
+       return 0;
+}
+
+static struct platform_driver serial_netx_driver = {
+       .probe          = serial_netx_probe,
+       .remove         = serial_netx_remove,
+
+       .suspend        = serial_netx_suspend,
+       .resume         = serial_netx_resume,
+
+       .driver         = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init netx_serial_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "Serial: NetX driver\n");
+
+       ret = uart_register_driver(&netx_reg);
+       if (ret)
+               return ret;
+
+       ret = platform_driver_register(&serial_netx_driver);
+       if (ret != 0)
+               uart_unregister_driver(&netx_reg);
+
+       return 0;
+}
+
+static void __exit netx_serial_exit(void)
+{
+       platform_driver_unregister(&serial_netx_driver);
+       uart_unregister_driver(&netx_reg);
+}
+
+module_init(netx_serial_init);
+module_exit(netx_serial_exit);
+
+MODULE_AUTHOR("Sascha Hauer");
+MODULE_DESCRIPTION("NetX serial port driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/tty/serial/nwpserial.c b/drivers/tty/serial/nwpserial.c
new file mode 100644 (file)
index 0000000..de17367
--- /dev/null
@@ -0,0 +1,477 @@
+/*
+ *  Serial Port driver for a NWP uart device
+ *
+ *    Copyright (C) 2008 IBM Corp., Benjamin Krill <ben@codiert.org>
+ *
+ *  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.
+ *
+ */
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/serial_core.h>
+#include <linux/tty.h>
+#include <linux/irqreturn.h>
+#include <linux/mutex.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
+#include <linux/nwpserial.h>
+#include <asm/prom.h>
+#include <asm/dcr.h>
+
+#define NWPSERIAL_NR               2
+
+#define NWPSERIAL_STATUS_RXVALID 0x1
+#define NWPSERIAL_STATUS_TXFULL  0x2
+
+struct nwpserial_port {
+       struct uart_port port;
+       dcr_host_t dcr_host;
+       unsigned int ier;
+       unsigned int mcr;
+};
+
+static DEFINE_MUTEX(nwpserial_mutex);
+static struct nwpserial_port nwpserial_ports[NWPSERIAL_NR];
+
+static void wait_for_bits(struct nwpserial_port *up, int bits)
+{
+       unsigned int status, tmout = 10000;
+
+       /* Wait up to 10ms for the character(s) to be sent. */
+       do {
+               status = dcr_read(up->dcr_host, UART_LSR);
+
+               if (--tmout == 0)
+                       break;
+               udelay(1);
+       } while ((status & bits) != bits);
+}
+
+#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE
+static void nwpserial_console_putchar(struct uart_port *port, int c)
+{
+       struct nwpserial_port *up;
+       up = container_of(port, struct nwpserial_port, port);
+       /* check if tx buffer is full */
+       wait_for_bits(up, UART_LSR_THRE);
+       dcr_write(up->dcr_host, UART_TX, c);
+       up->port.icount.tx++;
+}
+
+static void
+nwpserial_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct nwpserial_port *up = &nwpserial_ports[co->index];
+       unsigned long flags;
+       int locked = 1;
+
+       if (oops_in_progress)
+               locked = spin_trylock_irqsave(&up->port.lock, flags);
+       else
+               spin_lock_irqsave(&up->port.lock, flags);
+
+       /* save and disable interrupt */
+       up->ier = dcr_read(up->dcr_host, UART_IER);
+       dcr_write(up->dcr_host, UART_IER, up->ier & ~UART_IER_RDI);
+
+       uart_console_write(&up->port, s, count, nwpserial_console_putchar);
+
+       /* wait for transmitter to become empty */
+       while ((dcr_read(up->dcr_host, UART_LSR) & UART_LSR_THRE) == 0)
+               cpu_relax();
+
+       /* restore interrupt state */
+       dcr_write(up->dcr_host, UART_IER, up->ier);
+
+       if (locked)
+               spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static struct uart_driver nwpserial_reg;
+static struct console nwpserial_console = {
+       .name           = "ttySQ",
+       .write          = nwpserial_console_write,
+       .device         = uart_console_device,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &nwpserial_reg,
+};
+#define NWPSERIAL_CONSOLE      (&nwpserial_console)
+#else
+#define NWPSERIAL_CONSOLE      NULL
+#endif /* CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE */
+
+/**************************************************************************/
+
+static int nwpserial_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static void nwpserial_release_port(struct uart_port *port)
+{
+       /* N/A */
+}
+
+static void nwpserial_config_port(struct uart_port *port, int flags)
+{
+       port->type = PORT_NWPSERIAL;
+}
+
+static irqreturn_t nwpserial_interrupt(int irq, void *dev_id)
+{
+       struct nwpserial_port *up = dev_id;
+       struct tty_struct *tty = up->port.state->port.tty;
+       irqreturn_t ret;
+       unsigned int iir;
+       unsigned char ch;
+
+       spin_lock(&up->port.lock);
+
+       /* check if the uart was the interrupt source. */
+       iir = dcr_read(up->dcr_host, UART_IIR);
+       if (!iir) {
+               ret = IRQ_NONE;
+               goto out;
+       }
+
+       do {
+               up->port.icount.rx++;
+               ch = dcr_read(up->dcr_host, UART_RX);
+               if (up->port.ignore_status_mask != NWPSERIAL_STATUS_RXVALID)
+                       tty_insert_flip_char(tty, ch, TTY_NORMAL);
+       } while (dcr_read(up->dcr_host, UART_LSR) & UART_LSR_DR);
+
+       tty_flip_buffer_push(tty);
+       ret = IRQ_HANDLED;
+
+       /* clear interrupt */
+       dcr_write(up->dcr_host, UART_IIR, 1);
+out:
+       spin_unlock(&up->port.lock);
+       return ret;
+}
+
+static int nwpserial_startup(struct uart_port *port)
+{
+       struct nwpserial_port *up;
+       int err;
+
+       up = container_of(port, struct nwpserial_port, port);
+
+       /* disable flow control by default */
+       up->mcr = dcr_read(up->dcr_host, UART_MCR) & ~UART_MCR_AFE;
+       dcr_write(up->dcr_host, UART_MCR, up->mcr);
+
+       /* register interrupt handler */
+       err = request_irq(up->port.irq, nwpserial_interrupt,
+                       IRQF_SHARED, "nwpserial", up);
+       if (err)
+               return err;
+
+       /* enable interrupts */
+       up->ier = UART_IER_RDI;
+       dcr_write(up->dcr_host, UART_IER, up->ier);
+
+       /* enable receiving */
+       up->port.ignore_status_mask &= ~NWPSERIAL_STATUS_RXVALID;
+
+       return 0;
+}
+
+static void nwpserial_shutdown(struct uart_port *port)
+{
+       struct nwpserial_port *up;
+       up = container_of(port, struct nwpserial_port, port);
+
+       /* disable receiving */
+       up->port.ignore_status_mask |= NWPSERIAL_STATUS_RXVALID;
+
+       /* disable interrupts from this port */
+       up->ier = 0;
+       dcr_write(up->dcr_host, UART_IER, up->ier);
+
+       /* free irq */
+       free_irq(up->port.irq, port);
+}
+
+static int nwpserial_verify_port(struct uart_port *port,
+                       struct serial_struct *ser)
+{
+       return -EINVAL;
+}
+
+static const char *nwpserial_type(struct uart_port *port)
+{
+       return port->type == PORT_NWPSERIAL ? "nwpserial" : NULL;
+}
+
+static void nwpserial_set_termios(struct uart_port *port,
+                       struct ktermios *termios, struct ktermios *old)
+{
+       struct nwpserial_port *up;
+       up = container_of(port, struct nwpserial_port, port);
+
+       up->port.read_status_mask = NWPSERIAL_STATUS_RXVALID
+                               | NWPSERIAL_STATUS_TXFULL;
+
+       up->port.ignore_status_mask = 0;
+       /* ignore all characters if CREAD is not set */
+       if ((termios->c_cflag & CREAD) == 0)
+               up->port.ignore_status_mask |= NWPSERIAL_STATUS_RXVALID;
+
+       /* Copy back the old hardware settings */
+       if (old)
+               tty_termios_copy_hw(termios, old);
+}
+
+static void nwpserial_break_ctl(struct uart_port *port, int ctl)
+{
+       /* N/A */
+}
+
+static void nwpserial_enable_ms(struct uart_port *port)
+{
+       /* N/A */
+}
+
+static void nwpserial_stop_rx(struct uart_port *port)
+{
+       struct nwpserial_port *up;
+       up = container_of(port, struct nwpserial_port, port);
+       /* don't forward any more data (like !CREAD) */
+       up->port.ignore_status_mask = NWPSERIAL_STATUS_RXVALID;
+}
+
+static void nwpserial_putchar(struct nwpserial_port *up, unsigned char c)
+{
+       /* check if tx buffer is full */
+       wait_for_bits(up, UART_LSR_THRE);
+       dcr_write(up->dcr_host, UART_TX, c);
+       up->port.icount.tx++;
+}
+
+static void nwpserial_start_tx(struct uart_port *port)
+{
+       struct nwpserial_port *up;
+       struct circ_buf *xmit;
+       up = container_of(port, struct nwpserial_port, port);
+       xmit  = &up->port.state->xmit;
+
+       if (port->x_char) {
+               nwpserial_putchar(up, up->port.x_char);
+               port->x_char = 0;
+       }
+
+       while (!(uart_circ_empty(xmit) || uart_tx_stopped(&up->port))) {
+               nwpserial_putchar(up, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
+       }
+}
+
+static unsigned int nwpserial_get_mctrl(struct uart_port *port)
+{
+       return 0;
+}
+
+static void nwpserial_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       /* N/A */
+}
+
+static void nwpserial_stop_tx(struct uart_port *port)
+{
+       /* N/A */
+}
+
+static unsigned int nwpserial_tx_empty(struct uart_port *port)
+{
+       struct nwpserial_port *up;
+       unsigned long flags;
+       int ret;
+       up = container_of(port, struct nwpserial_port, port);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       ret = dcr_read(up->dcr_host, UART_LSR);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       return ret & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+}
+
+static struct uart_ops nwpserial_pops = {
+       .tx_empty     = nwpserial_tx_empty,
+       .set_mctrl    = nwpserial_set_mctrl,
+       .get_mctrl    = nwpserial_get_mctrl,
+       .stop_tx      = nwpserial_stop_tx,
+       .start_tx     = nwpserial_start_tx,
+       .stop_rx      = nwpserial_stop_rx,
+       .enable_ms    = nwpserial_enable_ms,
+       .break_ctl    = nwpserial_break_ctl,
+       .startup      = nwpserial_startup,
+       .shutdown     = nwpserial_shutdown,
+       .set_termios  = nwpserial_set_termios,
+       .type         = nwpserial_type,
+       .release_port = nwpserial_release_port,
+       .request_port = nwpserial_request_port,
+       .config_port  = nwpserial_config_port,
+       .verify_port  = nwpserial_verify_port,
+};
+
+static struct uart_driver nwpserial_reg = {
+       .owner       = THIS_MODULE,
+       .driver_name = "nwpserial",
+       .dev_name    = "ttySQ",
+       .major       = TTY_MAJOR,
+       .minor       = 68,
+       .nr          = NWPSERIAL_NR,
+       .cons        = NWPSERIAL_CONSOLE,
+};
+
+int nwpserial_register_port(struct uart_port *port)
+{
+       struct nwpserial_port *up = NULL;
+       int ret = -1;
+       int i;
+       static int first = 1;
+       int dcr_len;
+       int dcr_base;
+       struct device_node *dn;
+
+       mutex_lock(&nwpserial_mutex);
+
+       dn = port->dev->of_node;
+       if (dn == NULL)
+               goto out;
+
+       /* get dcr base. */
+       dcr_base = dcr_resource_start(dn, 0);
+
+       /* find matching entry */
+       for (i = 0; i < NWPSERIAL_NR; i++)
+               if (nwpserial_ports[i].port.iobase == dcr_base) {
+                       up = &nwpserial_ports[i];
+                       break;
+               }
+
+       /* we didn't find a mtching entry, search for a free port */
+       if (up == NULL)
+               for (i = 0; i < NWPSERIAL_NR; i++)
+                       if (nwpserial_ports[i].port.type == PORT_UNKNOWN &&
+                               nwpserial_ports[i].port.iobase == 0) {
+                               up = &nwpserial_ports[i];
+                               break;
+                       }
+
+       if (up == NULL) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       if (first)
+               uart_register_driver(&nwpserial_reg);
+       first = 0;
+
+       up->port.membase      = port->membase;
+       up->port.irq          = port->irq;
+       up->port.uartclk      = port->uartclk;
+       up->port.fifosize     = port->fifosize;
+       up->port.regshift     = port->regshift;
+       up->port.iotype       = port->iotype;
+       up->port.flags        = port->flags;
+       up->port.mapbase      = port->mapbase;
+       up->port.private_data = port->private_data;
+
+       if (port->dev)
+               up->port.dev = port->dev;
+
+       if (up->port.iobase != dcr_base) {
+               up->port.ops          = &nwpserial_pops;
+               up->port.fifosize     = 16;
+
+               spin_lock_init(&up->port.lock);
+
+               up->port.iobase = dcr_base;
+               dcr_len = dcr_resource_len(dn, 0);
+
+               up->dcr_host = dcr_map(dn, dcr_base, dcr_len);
+               if (!DCR_MAP_OK(up->dcr_host)) {
+                       printk(KERN_ERR "Cannot map DCR resources for NWPSERIAL");
+                       goto out;
+               }
+       }
+
+       ret = uart_add_one_port(&nwpserial_reg, &up->port);
+       if (ret == 0)
+               ret = up->port.line;
+
+out:
+       mutex_unlock(&nwpserial_mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL(nwpserial_register_port);
+
+void nwpserial_unregister_port(int line)
+{
+       struct nwpserial_port *up = &nwpserial_ports[line];
+       mutex_lock(&nwpserial_mutex);
+       uart_remove_one_port(&nwpserial_reg, &up->port);
+
+       up->port.type = PORT_UNKNOWN;
+
+       mutex_unlock(&nwpserial_mutex);
+}
+EXPORT_SYMBOL(nwpserial_unregister_port);
+
+#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE
+static int __init nwpserial_console_init(void)
+{
+       struct nwpserial_port *up = NULL;
+       struct device_node *dn;
+       const char *name;
+       int dcr_base;
+       int dcr_len;
+       int i;
+
+       /* search for a free port */
+       for (i = 0; i < NWPSERIAL_NR; i++)
+               if (nwpserial_ports[i].port.type == PORT_UNKNOWN) {
+                       up = &nwpserial_ports[i];
+                       break;
+               }
+
+       if (up == NULL)
+               return -1;
+
+       name = of_get_property(of_chosen, "linux,stdout-path", NULL);
+       if (name == NULL)
+               return -1;
+
+       dn = of_find_node_by_path(name);
+       if (!dn)
+               return -1;
+
+       spin_lock_init(&up->port.lock);
+       up->port.ops = &nwpserial_pops;
+       up->port.type = PORT_NWPSERIAL;
+       up->port.fifosize = 16;
+
+       dcr_base = dcr_resource_start(dn, 0);
+       dcr_len = dcr_resource_len(dn, 0);
+       up->port.iobase = dcr_base;
+
+       up->dcr_host = dcr_map(dn, dcr_base, dcr_len);
+       if (!DCR_MAP_OK(up->dcr_host)) {
+               printk("Cannot map DCR resources for SERIAL");
+               return -1;
+       }
+       register_console(&nwpserial_console);
+       return 0;
+}
+console_initcall(nwpserial_console_init);
+#endif /* CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE */
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
new file mode 100644 (file)
index 0000000..5c7abe4
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ *  Serial Port driver for Open Firmware platform devices
+ *
+ *    Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>, IBM Corp.
+ *
+ *  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.
+ *
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/nwpserial.h>
+
+struct of_serial_info {
+       int type;
+       int line;
+};
+
+/*
+ * Fill a struct uart_port for a given device node
+ */
+static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
+                                       int type, struct uart_port *port)
+{
+       struct resource resource;
+       struct device_node *np = ofdev->dev.of_node;
+       const __be32 *clk, *spd;
+       const __be32 *prop;
+       int ret, prop_size;
+
+       memset(port, 0, sizeof *port);
+       spd = of_get_property(np, "current-speed", NULL);
+       clk = of_get_property(np, "clock-frequency", NULL);
+       if (!clk) {
+               dev_warn(&ofdev->dev, "no clock-frequency property set\n");
+               return -ENODEV;
+       }
+
+       ret = of_address_to_resource(np, 0, &resource);
+       if (ret) {
+               dev_warn(&ofdev->dev, "invalid address\n");
+               return ret;
+       }
+
+       spin_lock_init(&port->lock);
+       port->mapbase = resource.start;
+
+       /* Check for shifted address mapping */
+       prop = of_get_property(np, "reg-offset", &prop_size);
+       if (prop && (prop_size == sizeof(u32)))
+               port->mapbase += be32_to_cpup(prop);
+
+       /* Check for registers offset within the devices address range */
+       prop = of_get_property(np, "reg-shift", &prop_size);
+       if (prop && (prop_size == sizeof(u32)))
+               port->regshift = be32_to_cpup(prop);
+
+       port->irq = irq_of_parse_and_map(np, 0);
+       port->iotype = UPIO_MEM;
+       port->type = type;
+       port->uartclk = be32_to_cpup(clk);
+       port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
+               | UPF_FIXED_PORT | UPF_FIXED_TYPE;
+       port->dev = &ofdev->dev;
+       /* If current-speed was set, then try not to change it. */
+       if (spd)
+               port->custom_divisor = be32_to_cpup(clk) / (16 * (be32_to_cpup(spd)));
+
+       return 0;
+}
+
+/*
+ * Try to register a serial port
+ */
+static int __devinit of_platform_serial_probe(struct platform_device *ofdev,
+                                               const struct of_device_id *id)
+{
+       struct of_serial_info *info;
+       struct uart_port port;
+       int port_type;
+       int ret;
+
+       if (of_find_property(ofdev->dev.of_node, "used-by-rtas", NULL))
+               return -EBUSY;
+
+       info = kmalloc(sizeof(*info), GFP_KERNEL);
+       if (info == NULL)
+               return -ENOMEM;
+
+       port_type = (unsigned long)id->data;
+       ret = of_platform_serial_setup(ofdev, port_type, &port);
+       if (ret)
+               goto out;
+
+       switch (port_type) {
+#ifdef CONFIG_SERIAL_8250
+       case PORT_8250 ... PORT_MAX_8250:
+               ret = serial8250_register_port(&port);
+               break;
+#endif
+#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
+       case PORT_NWPSERIAL:
+               ret = nwpserial_register_port(&port);
+               break;
+#endif
+       default:
+               /* need to add code for these */
+       case PORT_UNKNOWN:
+               dev_info(&ofdev->dev, "Unknown serial port found, ignored\n");
+               ret = -ENODEV;
+               break;
+       }
+       if (ret < 0)
+               goto out;
+
+       info->type = port_type;
+       info->line = ret;
+       dev_set_drvdata(&ofdev->dev, info);
+       return 0;
+out:
+       kfree(info);
+       irq_dispose_mapping(port.irq);
+       return ret;
+}
+
+/*
+ * Release a line
+ */
+static int of_platform_serial_remove(struct platform_device *ofdev)
+{
+       struct of_serial_info *info = dev_get_drvdata(&ofdev->dev);
+       switch (info->type) {
+#ifdef CONFIG_SERIAL_8250
+       case PORT_8250 ... PORT_MAX_8250:
+               serial8250_unregister_port(info->line);
+               break;
+#endif
+#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
+       case PORT_NWPSERIAL:
+               nwpserial_unregister_port(info->line);
+               break;
+#endif
+       default:
+               /* need to add code for these */
+               break;
+       }
+       kfree(info);
+       return 0;
+}
+
+/*
+ * A few common types, add more as needed.
+ */
+static struct of_device_id __devinitdata of_platform_serial_table[] = {
+       { .type = "serial", .compatible = "ns8250",   .data = (void *)PORT_8250, },
+       { .type = "serial", .compatible = "ns16450",  .data = (void *)PORT_16450, },
+       { .type = "serial", .compatible = "ns16550a", .data = (void *)PORT_16550A, },
+       { .type = "serial", .compatible = "ns16550",  .data = (void *)PORT_16550, },
+       { .type = "serial", .compatible = "ns16750",  .data = (void *)PORT_16750, },
+       { .type = "serial", .compatible = "ns16850",  .data = (void *)PORT_16850, },
+#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
+       { .type = "serial", .compatible = "ibm,qpace-nwp-serial",
+                                       .data = (void *)PORT_NWPSERIAL, },
+#endif
+       { .type = "serial",                           .data = (void *)PORT_UNKNOWN, },
+       { /* end of list */ },
+};
+
+static struct of_platform_driver of_platform_serial_driver = {
+       .driver = {
+               .name = "of_serial",
+               .owner = THIS_MODULE,
+               .of_match_table = of_platform_serial_table,
+       },
+       .probe = of_platform_serial_probe,
+       .remove = of_platform_serial_remove,
+};
+
+static int __init of_platform_serial_init(void)
+{
+       return of_register_platform_driver(&of_platform_serial_driver);
+}
+module_init(of_platform_serial_init);
+
+static void __exit of_platform_serial_exit(void)
+{
+       return of_unregister_platform_driver(&of_platform_serial_driver);
+};
+module_exit(of_platform_serial_exit);
+
+MODULE_AUTHOR("Arnd Bergmann <arnd@arndb.de>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Serial Port driver for Open Firmware platform devices");
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
new file mode 100644 (file)
index 0000000..7f2f010
--- /dev/null
@@ -0,0 +1,1359 @@
+/*
+ * Driver for OMAP-UART controller.
+ * Based on drivers/serial/8250.c
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * Authors:
+ *     Govindraj R     <govindraj.raja@ti.com>
+ *     Thara Gopinath  <thara@ti.com>
+ *
+ * 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.
+ *
+ * Note: This driver is made seperate from 8250 driver as we cannot
+ * over load 8250 driver with omap platform specific configuration for
+ * features like DMA, it makes easier to implement features like DMA and
+ * hardware flow control and software flow control configuration with
+ * this driver as required for the omap-platform.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/serial_reg.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/serial_core.h>
+#include <linux/irq.h>
+
+#include <plat/dma.h>
+#include <plat/dmtimer.h>
+#include <plat/omap-serial.h>
+
+static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
+
+/* Forward declaration of functions */
+static void uart_tx_dma_callback(int lch, u16 ch_status, void *data);
+static void serial_omap_rx_timeout(unsigned long uart_no);
+static int serial_omap_start_rxdma(struct uart_omap_port *up);
+
+static inline unsigned int serial_in(struct uart_omap_port *up, int offset)
+{
+       offset <<= up->port.regshift;
+       return readw(up->port.membase + offset);
+}
+
+static inline void serial_out(struct uart_omap_port *up, int offset, int value)
+{
+       offset <<= up->port.regshift;
+       writew(value, up->port.membase + offset);
+}
+
+static inline void serial_omap_clear_fifos(struct uart_omap_port *up)
+{
+       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+                      UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+       serial_out(up, UART_FCR, 0);
+}
+
+/*
+ * serial_omap_get_divisor - calculate divisor value
+ * @port: uart port info
+ * @baud: baudrate for which divisor needs to be calculated.
+ *
+ * We have written our own function to get the divisor so as to support
+ * 13x mode. 3Mbps Baudrate as an different divisor.
+ * Reference OMAP TRM Chapter 17:
+ * Table 17-1. UART Mode Baud Rates, Divisor Values, and Error Rates
+ * referring to oversampling - divisor value
+ * baudrate 460,800 to 3,686,400 all have divisor 13
+ * except 3,000,000 which has divisor value 16
+ */
+static unsigned int
+serial_omap_get_divisor(struct uart_port *port, unsigned int baud)
+{
+       unsigned int divisor;
+
+       if (baud > OMAP_MODE13X_SPEED && baud != 3000000)
+               divisor = 13;
+       else
+               divisor = 16;
+       return port->uartclk/(baud * divisor);
+}
+
+static void serial_omap_stop_rxdma(struct uart_omap_port *up)
+{
+       if (up->uart_dma.rx_dma_used) {
+               del_timer(&up->uart_dma.rx_timer);
+               omap_stop_dma(up->uart_dma.rx_dma_channel);
+               omap_free_dma(up->uart_dma.rx_dma_channel);
+               up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
+               up->uart_dma.rx_dma_used = false;
+       }
+}
+
+static void serial_omap_enable_ms(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+       dev_dbg(up->port.dev, "serial_omap_enable_ms+%d\n", up->pdev->id);
+       up->ier |= UART_IER_MSI;
+       serial_out(up, UART_IER, up->ier);
+}
+
+static void serial_omap_stop_tx(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+       if (up->use_dma &&
+               up->uart_dma.tx_dma_channel != OMAP_UART_DMA_CH_FREE) {
+               /*
+                * Check if dma is still active. If yes do nothing,
+                * return. Else stop dma
+                */
+               if (omap_get_dma_active_status(up->uart_dma.tx_dma_channel))
+                       return;
+               omap_stop_dma(up->uart_dma.tx_dma_channel);
+               omap_free_dma(up->uart_dma.tx_dma_channel);
+               up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE;
+       }
+
+       if (up->ier & UART_IER_THRI) {
+               up->ier &= ~UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+       }
+}
+
+static void serial_omap_stop_rx(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+       if (up->use_dma)
+               serial_omap_stop_rxdma(up);
+       up->ier &= ~UART_IER_RLSI;
+       up->port.read_status_mask &= ~UART_LSR_DR;
+       serial_out(up, UART_IER, up->ier);
+}
+
+static inline void receive_chars(struct uart_omap_port *up, int *status)
+{
+       struct tty_struct *tty = up->port.state->port.tty;
+       unsigned int flag;
+       unsigned char ch, lsr = *status;
+       int max_count = 256;
+
+       do {
+               if (likely(lsr & UART_LSR_DR))
+                       ch = serial_in(up, UART_RX);
+               flag = TTY_NORMAL;
+               up->port.icount.rx++;
+
+               if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
+                       /*
+                        * For statistics only
+                        */
+                       if (lsr & UART_LSR_BI) {
+                               lsr &= ~(UART_LSR_FE | UART_LSR_PE);
+                               up->port.icount.brk++;
+                               /*
+                                * We do the SysRQ and SAK checking
+                                * here because otherwise the break
+                                * may get masked by ignore_status_mask
+                                * or read_status_mask.
+                                */
+                               if (uart_handle_break(&up->port))
+                                       goto ignore_char;
+                       } else if (lsr & UART_LSR_PE) {
+                               up->port.icount.parity++;
+                       } else if (lsr & UART_LSR_FE) {
+                               up->port.icount.frame++;
+                       }
+
+                       if (lsr & UART_LSR_OE)
+                               up->port.icount.overrun++;
+
+                       /*
+                        * Mask off conditions which should be ignored.
+                        */
+                       lsr &= up->port.read_status_mask;
+
+#ifdef CONFIG_SERIAL_OMAP_CONSOLE
+                       if (up->port.line == up->port.cons->index) {
+                               /* Recover the break flag from console xmit */
+                               lsr |= up->lsr_break_flag;
+                               up->lsr_break_flag = 0;
+                       }
+#endif
+                       if (lsr & UART_LSR_BI)
+                               flag = TTY_BREAK;
+                       else if (lsr & UART_LSR_PE)
+                               flag = TTY_PARITY;
+                       else if (lsr & UART_LSR_FE)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(&up->port, ch))
+                       goto ignore_char;
+               uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);
+ignore_char:
+               lsr = serial_in(up, UART_LSR);
+       } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0));
+       spin_unlock(&up->port.lock);
+       tty_flip_buffer_push(tty);
+       spin_lock(&up->port.lock);
+}
+
+static void transmit_chars(struct uart_omap_port *up)
+{
+       struct circ_buf *xmit = &up->port.state->xmit;
+       int count;
+
+       if (up->port.x_char) {
+               serial_out(up, UART_TX, up->port.x_char);
+               up->port.icount.tx++;
+               up->port.x_char = 0;
+               return;
+       }
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+               serial_omap_stop_tx(&up->port);
+               return;
+       }
+       count = up->port.fifosize / 4;
+       do {
+               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               up->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (--count > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+       if (uart_circ_empty(xmit))
+               serial_omap_stop_tx(&up->port);
+}
+
+static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up)
+{
+       if (!(up->ier & UART_IER_THRI)) {
+               up->ier |= UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+       }
+}
+
+static void serial_omap_start_tx(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       struct circ_buf *xmit;
+       unsigned int start;
+       int ret = 0;
+
+       if (!up->use_dma) {
+               serial_omap_enable_ier_thri(up);
+               return;
+       }
+
+       if (up->uart_dma.tx_dma_used)
+               return;
+
+       xmit = &up->port.state->xmit;
+
+       if (up->uart_dma.tx_dma_channel == OMAP_UART_DMA_CH_FREE) {
+               ret = omap_request_dma(up->uart_dma.uart_dma_tx,
+                               "UART Tx DMA",
+                               (void *)uart_tx_dma_callback, up,
+                               &(up->uart_dma.tx_dma_channel));
+
+               if (ret < 0) {
+                       serial_omap_enable_ier_thri(up);
+                       return;
+               }
+       }
+       spin_lock(&(up->uart_dma.tx_lock));
+       up->uart_dma.tx_dma_used = true;
+       spin_unlock(&(up->uart_dma.tx_lock));
+
+       start = up->uart_dma.tx_buf_dma_phys +
+                               (xmit->tail & (UART_XMIT_SIZE - 1));
+
+       up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit);
+       /*
+        * It is a circular buffer. See if the buffer has wounded back.
+        * If yes it will have to be transferred in two separate dma
+        * transfers
+        */
+       if (start + up->uart_dma.tx_buf_size >=
+                       up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE)
+               up->uart_dma.tx_buf_size =
+                       (up->uart_dma.tx_buf_dma_phys +
+                       UART_XMIT_SIZE) - start;
+
+       omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0,
+                               OMAP_DMA_AMODE_CONSTANT,
+                               up->uart_dma.uart_base, 0, 0);
+       omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0,
+                               OMAP_DMA_AMODE_POST_INC, start, 0, 0);
+       omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel,
+                               OMAP_DMA_DATA_TYPE_S8,
+                               up->uart_dma.tx_buf_size, 1,
+                               OMAP_DMA_SYNC_ELEMENT,
+                               up->uart_dma.uart_dma_tx, 0);
+       /* FIXME: Cache maintenance needed here? */
+       omap_start_dma(up->uart_dma.tx_dma_channel);
+}
+
+static unsigned int check_modem_status(struct uart_omap_port *up)
+{
+       unsigned int status;
+
+       status = serial_in(up, UART_MSR);
+       status |= up->msr_saved_flags;
+       up->msr_saved_flags = 0;
+       if ((status & UART_MSR_ANY_DELTA) == 0)
+               return status;
+
+       if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&
+           up->port.state != NULL) {
+               if (status & UART_MSR_TERI)
+                       up->port.icount.rng++;
+               if (status & UART_MSR_DDSR)
+                       up->port.icount.dsr++;
+               if (status & UART_MSR_DDCD)
+                       uart_handle_dcd_change
+                               (&up->port, status & UART_MSR_DCD);
+               if (status & UART_MSR_DCTS)
+                       uart_handle_cts_change
+                               (&up->port, status & UART_MSR_CTS);
+               wake_up_interruptible(&up->port.state->port.delta_msr_wait);
+       }
+
+       return status;
+}
+
+/**
+ * serial_omap_irq() - This handles the interrupt from one port
+ * @irq: uart port irq number
+ * @dev_id: uart port info
+ */
+static inline irqreturn_t serial_omap_irq(int irq, void *dev_id)
+{
+       struct uart_omap_port *up = dev_id;
+       unsigned int iir, lsr;
+       unsigned long flags;
+
+       iir = serial_in(up, UART_IIR);
+       if (iir & UART_IIR_NO_INT)
+               return IRQ_NONE;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       lsr = serial_in(up, UART_LSR);
+       if (iir & UART_IIR_RLSI) {
+               if (!up->use_dma) {
+                       if (lsr & UART_LSR_DR)
+                               receive_chars(up, &lsr);
+               } else {
+                       up->ier &= ~(UART_IER_RDI | UART_IER_RLSI);
+                       serial_out(up, UART_IER, up->ier);
+                       if ((serial_omap_start_rxdma(up) != 0) &&
+                                       (lsr & UART_LSR_DR))
+                               receive_chars(up, &lsr);
+               }
+       }
+
+       check_modem_status(up);
+       if ((lsr & UART_LSR_THRE) && (iir & UART_IIR_THRI))
+               transmit_chars(up);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+       up->port_activity = jiffies;
+       return IRQ_HANDLED;
+}
+
+static unsigned int serial_omap_tx_empty(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       unsigned long flags = 0;
+       unsigned int ret = 0;
+
+       dev_dbg(up->port.dev, "serial_omap_tx_empty+%d\n", up->pdev->id);
+       spin_lock_irqsave(&up->port.lock, flags);
+       ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       return ret;
+}
+
+static unsigned int serial_omap_get_mctrl(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       unsigned char status;
+       unsigned int ret = 0;
+
+       status = check_modem_status(up);
+       dev_dbg(up->port.dev, "serial_omap_get_mctrl+%d\n", up->pdev->id);
+
+       if (status & UART_MSR_DCD)
+               ret |= TIOCM_CAR;
+       if (status & UART_MSR_RI)
+               ret |= TIOCM_RNG;
+       if (status & UART_MSR_DSR)
+               ret |= TIOCM_DSR;
+       if (status & UART_MSR_CTS)
+               ret |= TIOCM_CTS;
+       return ret;
+}
+
+static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       unsigned char mcr = 0;
+
+       dev_dbg(up->port.dev, "serial_omap_set_mctrl+%d\n", up->pdev->id);
+       if (mctrl & TIOCM_RTS)
+               mcr |= UART_MCR_RTS;
+       if (mctrl & TIOCM_DTR)
+               mcr |= UART_MCR_DTR;
+       if (mctrl & TIOCM_OUT1)
+               mcr |= UART_MCR_OUT1;
+       if (mctrl & TIOCM_OUT2)
+               mcr |= UART_MCR_OUT2;
+       if (mctrl & TIOCM_LOOP)
+               mcr |= UART_MCR_LOOP;
+
+       mcr |= up->mcr;
+       serial_out(up, UART_MCR, mcr);
+}
+
+static void serial_omap_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       unsigned long flags = 0;
+
+       dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->pdev->id);
+       spin_lock_irqsave(&up->port.lock, flags);
+       if (break_state == -1)
+               up->lcr |= UART_LCR_SBC;
+       else
+               up->lcr &= ~UART_LCR_SBC;
+       serial_out(up, UART_LCR, up->lcr);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static int serial_omap_startup(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       unsigned long flags = 0;
+       int retval;
+
+       /*
+        * Allocate the IRQ
+        */
+       retval = request_irq(up->port.irq, serial_omap_irq, up->port.irqflags,
+                               up->name, up);
+       if (retval)
+               return retval;
+
+       dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->pdev->id);
+
+       /*
+        * Clear the FIFO buffers and disable them.
+        * (they will be reenabled in set_termios())
+        */
+       serial_omap_clear_fifos(up);
+       /* For Hardware flow control */
+       serial_out(up, UART_MCR, UART_MCR_RTS);
+
+       /*
+        * Clear the interrupt registers.
+        */
+       (void) serial_in(up, UART_LSR);
+       if (serial_in(up, UART_LSR) & UART_LSR_DR)
+               (void) serial_in(up, UART_RX);
+       (void) serial_in(up, UART_IIR);
+       (void) serial_in(up, UART_MSR);
+
+       /*
+        * Now, initialize the UART
+        */
+       serial_out(up, UART_LCR, UART_LCR_WLEN8);
+       spin_lock_irqsave(&up->port.lock, flags);
+       /*
+        * Most PC uarts need OUT2 raised to enable interrupts.
+        */
+       up->port.mctrl |= TIOCM_OUT2;
+       serial_omap_set_mctrl(&up->port, up->port.mctrl);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       up->msr_saved_flags = 0;
+       if (up->use_dma) {
+               free_page((unsigned long)up->port.state->xmit.buf);
+               up->port.state->xmit.buf = dma_alloc_coherent(NULL,
+                       UART_XMIT_SIZE,
+                       (dma_addr_t *)&(up->uart_dma.tx_buf_dma_phys),
+                       0);
+               init_timer(&(up->uart_dma.rx_timer));
+               up->uart_dma.rx_timer.function = serial_omap_rx_timeout;
+               up->uart_dma.rx_timer.data = up->pdev->id;
+               /* Currently the buffer size is 4KB. Can increase it */
+               up->uart_dma.rx_buf = dma_alloc_coherent(NULL,
+                       up->uart_dma.rx_buf_size,
+                       (dma_addr_t *)&(up->uart_dma.rx_buf_dma_phys), 0);
+       }
+       /*
+        * Finally, enable interrupts. Note: Modem status interrupts
+        * are set via set_termios(), which will be occurring imminently
+        * anyway, so we don't enable them here.
+        */
+       up->ier = UART_IER_RLSI | UART_IER_RDI;
+       serial_out(up, UART_IER, up->ier);
+
+       up->port_activity = jiffies;
+       return 0;
+}
+
+static void serial_omap_shutdown(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       unsigned long flags = 0;
+
+       dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->pdev->id);
+       /*
+        * Disable interrupts from this port
+        */
+       up->ier = 0;
+       serial_out(up, UART_IER, 0);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       up->port.mctrl &= ~TIOCM_OUT2;
+       serial_omap_set_mctrl(&up->port, up->port.mctrl);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       /*
+        * Disable break condition and FIFOs
+        */
+       serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
+       serial_omap_clear_fifos(up);
+
+       /*
+        * Read data port to reset things, and then free the irq
+        */
+       if (serial_in(up, UART_LSR) & UART_LSR_DR)
+               (void) serial_in(up, UART_RX);
+       if (up->use_dma) {
+               dma_free_coherent(up->port.dev,
+                       UART_XMIT_SIZE, up->port.state->xmit.buf,
+                       up->uart_dma.tx_buf_dma_phys);
+               up->port.state->xmit.buf = NULL;
+               serial_omap_stop_rx(port);
+               dma_free_coherent(up->port.dev,
+                       up->uart_dma.rx_buf_size, up->uart_dma.rx_buf,
+                       up->uart_dma.rx_buf_dma_phys);
+               up->uart_dma.rx_buf = NULL;
+       }
+       free_irq(up->port.irq, up);
+}
+
+static inline void
+serial_omap_configure_xonxoff
+               (struct uart_omap_port *up, struct ktermios *termios)
+{
+       unsigned char efr = 0;
+
+       up->lcr = serial_in(up, UART_LCR);
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+       up->efr = serial_in(up, UART_EFR);
+       serial_out(up, UART_EFR, up->efr & ~UART_EFR_ECB);
+
+       serial_out(up, UART_XON1, termios->c_cc[VSTART]);
+       serial_out(up, UART_XOFF1, termios->c_cc[VSTOP]);
+
+       /* clear SW control mode bits */
+       efr = up->efr;
+       efr &= OMAP_UART_SW_CLR;
+
+       /*
+        * IXON Flag:
+        * Enable XON/XOFF flow control on output.
+        * Transmit XON1, XOFF1
+        */
+       if (termios->c_iflag & IXON)
+               efr |= OMAP_UART_SW_TX;
+
+       /*
+        * IXOFF Flag:
+        * Enable XON/XOFF flow control on input.
+        * Receiver compares XON1, XOFF1.
+        */
+       if (termios->c_iflag & IXOFF)
+               efr |= OMAP_UART_SW_RX;
+
+       serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
+
+       up->mcr = serial_in(up, UART_MCR);
+
+       /*
+        * IXANY Flag:
+        * Enable any character to restart output.
+        * Operation resumes after receiving any
+        * character after recognition of the XOFF character
+        */
+       if (termios->c_iflag & IXANY)
+               up->mcr |= UART_MCR_XONANY;
+
+       serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+       serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
+       /* Enable special char function UARTi.EFR_REG[5] and
+        * load the new software flow control mode IXON or IXOFF
+        * and restore the UARTi.EFR_REG[4] ENHANCED_EN value.
+        */
+       serial_out(up, UART_EFR, efr | UART_EFR_SCD);
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
+
+       serial_out(up, UART_MCR, up->mcr & ~UART_MCR_TCRTLR);
+       serial_out(up, UART_LCR, up->lcr);
+}
+
+static void
+serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
+                       struct ktermios *old)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       unsigned char cval = 0;
+       unsigned char efr = 0;
+       unsigned long flags = 0;
+       unsigned int baud, quot;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               cval = UART_LCR_WLEN5;
+               break;
+       case CS6:
+               cval = UART_LCR_WLEN6;
+               break;
+       case CS7:
+               cval = UART_LCR_WLEN7;
+               break;
+       default:
+       case CS8:
+               cval = UART_LCR_WLEN8;
+               break;
+       }
+
+       if (termios->c_cflag & CSTOPB)
+               cval |= UART_LCR_STOP;
+       if (termios->c_cflag & PARENB)
+               cval |= UART_LCR_PARITY;
+       if (!(termios->c_cflag & PARODD))
+               cval |= UART_LCR_EPAR;
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/13);
+       quot = serial_omap_get_divisor(port, baud);
+
+       up->fcr = UART_FCR_R_TRIG_01 | UART_FCR_T_TRIG_01 |
+                       UART_FCR_ENABLE_FIFO;
+       if (up->use_dma)
+               up->fcr |= UART_FCR_DMA_SELECT;
+
+       /*
+        * Ok, we're now changing the port state. Do it with
+        * interrupts disabled.
+        */
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+       if (termios->c_iflag & INPCK)
+               up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               up->port.read_status_mask |= UART_LSR_BI;
+
+       /*
+        * Characters to ignore
+        */
+       up->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+       if (termios->c_iflag & IGNBRK) {
+               up->port.ignore_status_mask |= UART_LSR_BI;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       up->port.ignore_status_mask |= UART_LSR_OE;
+       }
+
+       /*
+        * ignore all characters if CREAD is not set
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               up->port.ignore_status_mask |= UART_LSR_DR;
+
+       /*
+        * Modem status interrupts
+        */
+       up->ier &= ~UART_IER_MSI;
+       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
+               up->ier |= UART_IER_MSI;
+       serial_out(up, UART_IER, up->ier);
+       serial_out(up, UART_LCR, cval);         /* reset DLAB */
+
+       /* FIFOs and DMA Settings */
+
+       /* FCR can be changed only when the
+        * baud clock is not running
+        * DLL_REG and DLH_REG set to 0.
+        */
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
+       serial_out(up, UART_DLL, 0);
+       serial_out(up, UART_DLM, 0);
+       serial_out(up, UART_LCR, 0);
+
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+
+       up->efr = serial_in(up, UART_EFR);
+       serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
+       up->mcr = serial_in(up, UART_MCR);
+       serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
+       /* FIFO ENABLE, DMA MODE */
+       serial_out(up, UART_FCR, up->fcr);
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+
+       if (up->use_dma) {
+               serial_out(up, UART_TI752_TLR, 0);
+               serial_out(up, UART_OMAP_SCR,
+                       (UART_FCR_TRIGGER_4 | UART_FCR_TRIGGER_8));
+       }
+
+       serial_out(up, UART_EFR, up->efr);
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
+       serial_out(up, UART_MCR, up->mcr);
+
+       /* Protocol, Baud Rate, and Interrupt Settings */
+
+       serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE);
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+
+       up->efr = serial_in(up, UART_EFR);
+       serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+
+       serial_out(up, UART_LCR, 0);
+       serial_out(up, UART_IER, 0);
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+
+       serial_out(up, UART_DLL, quot & 0xff);          /* LS of divisor */
+       serial_out(up, UART_DLM, quot >> 8);            /* MS of divisor */
+
+       serial_out(up, UART_LCR, 0);
+       serial_out(up, UART_IER, up->ier);
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+
+       serial_out(up, UART_EFR, up->efr);
+       serial_out(up, UART_LCR, cval);
+
+       if (baud > 230400 && baud != 3000000)
+               serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_13X_MODE);
+       else
+               serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_16X_MODE);
+
+       /* Hardware Flow Control Configuration */
+
+       if (termios->c_cflag & CRTSCTS) {
+               efr |= (UART_EFR_CTS | UART_EFR_RTS);
+               serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
+
+               up->mcr = serial_in(up, UART_MCR);
+               serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
+
+               serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+               up->efr = serial_in(up, UART_EFR);
+               serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+
+               serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
+               serial_out(up, UART_EFR, efr); /* Enable AUTORTS and AUTOCTS */
+               serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
+               serial_out(up, UART_MCR, up->mcr | UART_MCR_RTS);
+               serial_out(up, UART_LCR, cval);
+       }
+
+       serial_omap_set_mctrl(&up->port, up->port.mctrl);
+       /* Software Flow Control Configuration */
+       if (termios->c_iflag & (IXON | IXOFF))
+               serial_omap_configure_xonxoff(up, termios);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+       dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->pdev->id);
+}
+
+static void
+serial_omap_pm(struct uart_port *port, unsigned int state,
+              unsigned int oldstate)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       unsigned char efr;
+
+       dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->pdev->id);
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+       efr = serial_in(up, UART_EFR);
+       serial_out(up, UART_EFR, efr | UART_EFR_ECB);
+       serial_out(up, UART_LCR, 0);
+
+       serial_out(up, UART_IER, (state != 0) ? UART_IERX_SLEEP : 0);
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+       serial_out(up, UART_EFR, efr);
+       serial_out(up, UART_LCR, 0);
+       /* Enable module level wake up */
+       serial_out(up, UART_OMAP_WER,
+               (state != 0) ? OMAP_UART_WER_MOD_WKUP : 0);
+}
+
+static void serial_omap_release_port(struct uart_port *port)
+{
+       dev_dbg(port->dev, "serial_omap_release_port+\n");
+}
+
+static int serial_omap_request_port(struct uart_port *port)
+{
+       dev_dbg(port->dev, "serial_omap_request_port+\n");
+       return 0;
+}
+
+static void serial_omap_config_port(struct uart_port *port, int flags)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+       dev_dbg(up->port.dev, "serial_omap_config_port+%d\n",
+                                                       up->pdev->id);
+       up->port.type = PORT_OMAP;
+}
+
+static int
+serial_omap_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       /* we don't want the core code to modify any port params */
+       dev_dbg(port->dev, "serial_omap_verify_port+\n");
+       return -EINVAL;
+}
+
+static const char *
+serial_omap_type(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+       dev_dbg(up->port.dev, "serial_omap_type+%d\n", up->pdev->id);
+       return up->name;
+}
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+static inline void wait_for_xmitr(struct uart_omap_port *up)
+{
+       unsigned int status, tmout = 10000;
+
+       /* Wait up to 10ms for the character(s) to be sent. */
+       do {
+               status = serial_in(up, UART_LSR);
+
+               if (status & UART_LSR_BI)
+                       up->lsr_break_flag = UART_LSR_BI;
+
+               if (--tmout == 0)
+                       break;
+               udelay(1);
+       } while ((status & BOTH_EMPTY) != BOTH_EMPTY);
+
+       /* Wait up to 1s for flow control if necessary */
+       if (up->port.flags & UPF_CONS_FLOW) {
+               tmout = 1000000;
+               for (tmout = 1000000; tmout; tmout--) {
+                       unsigned int msr = serial_in(up, UART_MSR);
+
+                       up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
+                       if (msr & UART_MSR_CTS)
+                               break;
+
+                       udelay(1);
+               }
+       }
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+
+static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       wait_for_xmitr(up);
+       serial_out(up, UART_TX, ch);
+}
+
+static int serial_omap_poll_get_char(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       unsigned int status = serial_in(up, UART_LSR);
+
+       if (!(status & UART_LSR_DR))
+               return NO_POLL_CHAR;
+
+       return serial_in(up, UART_RX);
+}
+
+#endif /* CONFIG_CONSOLE_POLL */
+
+#ifdef CONFIG_SERIAL_OMAP_CONSOLE
+
+static struct uart_omap_port *serial_omap_console_ports[4];
+
+static struct uart_driver serial_omap_reg;
+
+static void serial_omap_console_putchar(struct uart_port *port, int ch)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+       wait_for_xmitr(up);
+       serial_out(up, UART_TX, ch);
+}
+
+static void
+serial_omap_console_write(struct console *co, const char *s,
+               unsigned int count)
+{
+       struct uart_omap_port *up = serial_omap_console_ports[co->index];
+       unsigned long flags;
+       unsigned int ier;
+       int locked = 1;
+
+       local_irq_save(flags);
+       if (up->port.sysrq)
+               locked = 0;
+       else if (oops_in_progress)
+               locked = spin_trylock(&up->port.lock);
+       else
+               spin_lock(&up->port.lock);
+
+       /*
+        * First save the IER then disable the interrupts
+        */
+       ier = serial_in(up, UART_IER);
+       serial_out(up, UART_IER, 0);
+
+       uart_console_write(&up->port, s, count, serial_omap_console_putchar);
+
+       /*
+        * Finally, wait for transmitter to become empty
+        * and restore the IER
+        */
+       wait_for_xmitr(up);
+       serial_out(up, UART_IER, ier);
+       /*
+        * The receive handling will happen properly because the
+        * receive ready bit will still be set; it is not cleared
+        * on read.  However, modem control will not, we must
+        * call it if we have saved something in the saved flags
+        * while processing with interrupts off.
+        */
+       if (up->msr_saved_flags)
+               check_modem_status(up);
+
+       if (locked)
+               spin_unlock(&up->port.lock);
+       local_irq_restore(flags);
+}
+
+static int __init
+serial_omap_console_setup(struct console *co, char *options)
+{
+       struct uart_omap_port *up;
+       int baud = 115200;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (serial_omap_console_ports[co->index] == NULL)
+               return -ENODEV;
+       up = serial_omap_console_ports[co->index];
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(&up->port, co, baud, parity, bits, flow);
+}
+
+static struct console serial_omap_console = {
+       .name           = OMAP_SERIAL_NAME,
+       .write          = serial_omap_console_write,
+       .device         = uart_console_device,
+       .setup          = serial_omap_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &serial_omap_reg,
+};
+
+static void serial_omap_add_console_port(struct uart_omap_port *up)
+{
+       serial_omap_console_ports[up->pdev->id] = up;
+}
+
+#define OMAP_CONSOLE   (&serial_omap_console)
+
+#else
+
+#define OMAP_CONSOLE   NULL
+
+static inline void serial_omap_add_console_port(struct uart_omap_port *up)
+{}
+
+#endif
+
+static struct uart_ops serial_omap_pops = {
+       .tx_empty       = serial_omap_tx_empty,
+       .set_mctrl      = serial_omap_set_mctrl,
+       .get_mctrl      = serial_omap_get_mctrl,
+       .stop_tx        = serial_omap_stop_tx,
+       .start_tx       = serial_omap_start_tx,
+       .stop_rx        = serial_omap_stop_rx,
+       .enable_ms      = serial_omap_enable_ms,
+       .break_ctl      = serial_omap_break_ctl,
+       .startup        = serial_omap_startup,
+       .shutdown       = serial_omap_shutdown,
+       .set_termios    = serial_omap_set_termios,
+       .pm             = serial_omap_pm,
+       .type           = serial_omap_type,
+       .release_port   = serial_omap_release_port,
+       .request_port   = serial_omap_request_port,
+       .config_port    = serial_omap_config_port,
+       .verify_port    = serial_omap_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_put_char  = serial_omap_poll_put_char,
+       .poll_get_char  = serial_omap_poll_get_char,
+#endif
+};
+
+static struct uart_driver serial_omap_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "OMAP-SERIAL",
+       .dev_name       = OMAP_SERIAL_NAME,
+       .nr             = OMAP_MAX_HSUART_PORTS,
+       .cons           = OMAP_CONSOLE,
+};
+
+static int
+serial_omap_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct uart_omap_port *up = platform_get_drvdata(pdev);
+
+       if (up)
+               uart_suspend_port(&serial_omap_reg, &up->port);
+       return 0;
+}
+
+static int serial_omap_resume(struct platform_device *dev)
+{
+       struct uart_omap_port *up = platform_get_drvdata(dev);
+
+       if (up)
+               uart_resume_port(&serial_omap_reg, &up->port);
+       return 0;
+}
+
+static void serial_omap_rx_timeout(unsigned long uart_no)
+{
+       struct uart_omap_port *up = ui[uart_no];
+       unsigned int curr_dma_pos, curr_transmitted_size;
+       int ret = 0;
+
+       curr_dma_pos = omap_get_dma_dst_pos(up->uart_dma.rx_dma_channel);
+       if ((curr_dma_pos == up->uart_dma.prev_rx_dma_pos) ||
+                            (curr_dma_pos == 0)) {
+               if (jiffies_to_msecs(jiffies - up->port_activity) <
+                                                       RX_TIMEOUT) {
+                       mod_timer(&up->uart_dma.rx_timer, jiffies +
+                               usecs_to_jiffies(up->uart_dma.rx_timeout));
+               } else {
+                       serial_omap_stop_rxdma(up);
+                       up->ier |= (UART_IER_RDI | UART_IER_RLSI);
+                       serial_out(up, UART_IER, up->ier);
+               }
+               return;
+       }
+
+       curr_transmitted_size = curr_dma_pos -
+                                       up->uart_dma.prev_rx_dma_pos;
+       up->port.icount.rx += curr_transmitted_size;
+       tty_insert_flip_string(up->port.state->port.tty,
+                       up->uart_dma.rx_buf +
+                       (up->uart_dma.prev_rx_dma_pos -
+                       up->uart_dma.rx_buf_dma_phys),
+                       curr_transmitted_size);
+       tty_flip_buffer_push(up->port.state->port.tty);
+       up->uart_dma.prev_rx_dma_pos = curr_dma_pos;
+       if (up->uart_dma.rx_buf_size +
+                       up->uart_dma.rx_buf_dma_phys == curr_dma_pos) {
+               ret = serial_omap_start_rxdma(up);
+               if (ret < 0) {
+                       serial_omap_stop_rxdma(up);
+                       up->ier |= (UART_IER_RDI | UART_IER_RLSI);
+                       serial_out(up, UART_IER, up->ier);
+               }
+       } else  {
+               mod_timer(&up->uart_dma.rx_timer, jiffies +
+                       usecs_to_jiffies(up->uart_dma.rx_timeout));
+       }
+       up->port_activity = jiffies;
+}
+
+static void uart_rx_dma_callback(int lch, u16 ch_status, void *data)
+{
+       return;
+}
+
+static int serial_omap_start_rxdma(struct uart_omap_port *up)
+{
+       int ret = 0;
+
+       if (up->uart_dma.rx_dma_channel == -1) {
+               ret = omap_request_dma(up->uart_dma.uart_dma_rx,
+                               "UART Rx DMA",
+                               (void *)uart_rx_dma_callback, up,
+                               &(up->uart_dma.rx_dma_channel));
+               if (ret < 0)
+                       return ret;
+
+               omap_set_dma_src_params(up->uart_dma.rx_dma_channel, 0,
+                               OMAP_DMA_AMODE_CONSTANT,
+                               up->uart_dma.uart_base, 0, 0);
+               omap_set_dma_dest_params(up->uart_dma.rx_dma_channel, 0,
+                               OMAP_DMA_AMODE_POST_INC,
+                               up->uart_dma.rx_buf_dma_phys, 0, 0);
+               omap_set_dma_transfer_params(up->uart_dma.rx_dma_channel,
+                               OMAP_DMA_DATA_TYPE_S8,
+                               up->uart_dma.rx_buf_size, 1,
+                               OMAP_DMA_SYNC_ELEMENT,
+                               up->uart_dma.uart_dma_rx, 0);
+       }
+       up->uart_dma.prev_rx_dma_pos = up->uart_dma.rx_buf_dma_phys;
+       /* FIXME: Cache maintenance needed here? */
+       omap_start_dma(up->uart_dma.rx_dma_channel);
+       mod_timer(&up->uart_dma.rx_timer, jiffies +
+                               usecs_to_jiffies(up->uart_dma.rx_timeout));
+       up->uart_dma.rx_dma_used = true;
+       return ret;
+}
+
+static void serial_omap_continue_tx(struct uart_omap_port *up)
+{
+       struct circ_buf *xmit = &up->port.state->xmit;
+       unsigned int start = up->uart_dma.tx_buf_dma_phys
+                       + (xmit->tail & (UART_XMIT_SIZE - 1));
+
+       if (uart_circ_empty(xmit))
+               return;
+
+       up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit);
+       /*
+        * It is a circular buffer. See if the buffer has wounded back.
+        * If yes it will have to be transferred in two separate dma
+        * transfers
+        */
+       if (start + up->uart_dma.tx_buf_size >=
+                       up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE)
+               up->uart_dma.tx_buf_size =
+                       (up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE) - start;
+       omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0,
+                               OMAP_DMA_AMODE_CONSTANT,
+                               up->uart_dma.uart_base, 0, 0);
+       omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0,
+                               OMAP_DMA_AMODE_POST_INC, start, 0, 0);
+       omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel,
+                               OMAP_DMA_DATA_TYPE_S8,
+                               up->uart_dma.tx_buf_size, 1,
+                               OMAP_DMA_SYNC_ELEMENT,
+                               up->uart_dma.uart_dma_tx, 0);
+       /* FIXME: Cache maintenance needed here? */
+       omap_start_dma(up->uart_dma.tx_dma_channel);
+}
+
+static void uart_tx_dma_callback(int lch, u16 ch_status, void *data)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)data;
+       struct circ_buf *xmit = &up->port.state->xmit;
+
+       xmit->tail = (xmit->tail + up->uart_dma.tx_buf_size) & \
+                       (UART_XMIT_SIZE - 1);
+       up->port.icount.tx += up->uart_dma.tx_buf_size;
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+       if (uart_circ_empty(xmit)) {
+               spin_lock(&(up->uart_dma.tx_lock));
+               serial_omap_stop_tx(&up->port);
+               up->uart_dma.tx_dma_used = false;
+               spin_unlock(&(up->uart_dma.tx_lock));
+       } else {
+               omap_stop_dma(up->uart_dma.tx_dma_channel);
+               serial_omap_continue_tx(up);
+       }
+       up->port_activity = jiffies;
+       return;
+}
+
+static int serial_omap_probe(struct platform_device *pdev)
+{
+       struct uart_omap_port   *up;
+       struct resource         *mem, *irq, *dma_tx, *dma_rx;
+       struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data;
+       int ret = -ENOSPC;
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem) {
+               dev_err(&pdev->dev, "no mem resource?\n");
+               return -ENODEV;
+       }
+
+       irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!irq) {
+               dev_err(&pdev->dev, "no irq resource?\n");
+               return -ENODEV;
+       }
+
+       if (!request_mem_region(mem->start, (mem->end - mem->start) + 1,
+                                    pdev->dev.driver->name)) {
+               dev_err(&pdev->dev, "memory region already claimed\n");
+               return -EBUSY;
+       }
+
+       dma_rx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
+       if (!dma_rx) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       dma_tx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
+       if (!dma_tx) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       up = kzalloc(sizeof(*up), GFP_KERNEL);
+       if (up == NULL) {
+               ret = -ENOMEM;
+               goto do_release_region;
+       }
+       sprintf(up->name, "OMAP UART%d", pdev->id);
+       up->pdev = pdev;
+       up->port.dev = &pdev->dev;
+       up->port.type = PORT_OMAP;
+       up->port.iotype = UPIO_MEM;
+       up->port.irq = irq->start;
+
+       up->port.regshift = 2;
+       up->port.fifosize = 64;
+       up->port.ops = &serial_omap_pops;
+       up->port.line = pdev->id;
+
+       up->port.membase = omap_up_info->membase;
+       up->port.mapbase = omap_up_info->mapbase;
+       up->port.flags = omap_up_info->flags;
+       up->port.irqflags = omap_up_info->irqflags;
+       up->port.uartclk = omap_up_info->uartclk;
+       up->uart_dma.uart_base = mem->start;
+
+       if (omap_up_info->dma_enabled) {
+               up->uart_dma.uart_dma_tx = dma_tx->start;
+               up->uart_dma.uart_dma_rx = dma_rx->start;
+               up->use_dma = 1;
+               up->uart_dma.rx_buf_size = 4096;
+               up->uart_dma.rx_timeout = 2;
+               spin_lock_init(&(up->uart_dma.tx_lock));
+               spin_lock_init(&(up->uart_dma.rx_lock));
+               up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE;
+               up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
+       }
+
+       ui[pdev->id] = up;
+       serial_omap_add_console_port(up);
+
+       ret = uart_add_one_port(&serial_omap_reg, &up->port);
+       if (ret != 0)
+               goto do_release_region;
+
+       platform_set_drvdata(pdev, up);
+       return 0;
+err:
+       dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n",
+                               pdev->id, __func__, ret);
+do_release_region:
+       release_mem_region(mem->start, (mem->end - mem->start) + 1);
+       return ret;
+}
+
+static int serial_omap_remove(struct platform_device *dev)
+{
+       struct uart_omap_port *up = platform_get_drvdata(dev);
+
+       platform_set_drvdata(dev, NULL);
+       if (up) {
+               uart_remove_one_port(&serial_omap_reg, &up->port);
+               kfree(up);
+       }
+       return 0;
+}
+
+static struct platform_driver serial_omap_driver = {
+       .probe          = serial_omap_probe,
+       .remove         = serial_omap_remove,
+
+       .suspend        = serial_omap_suspend,
+       .resume         = serial_omap_resume,
+       .driver         = {
+               .name   = DRIVER_NAME,
+       },
+};
+
+static int __init serial_omap_init(void)
+{
+       int ret;
+
+       ret = uart_register_driver(&serial_omap_reg);
+       if (ret != 0)
+               return ret;
+       ret = platform_driver_register(&serial_omap_driver);
+       if (ret != 0)
+               uart_unregister_driver(&serial_omap_reg);
+       return ret;
+}
+
+static void __exit serial_omap_exit(void)
+{
+       platform_driver_unregister(&serial_omap_driver);
+       uart_unregister_driver(&serial_omap_reg);
+}
+
+module_init(serial_omap_init);
+module_exit(serial_omap_exit);
+
+MODULE_DESCRIPTION("OMAP High Speed UART driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Texas Instruments Inc");
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
new file mode 100644 (file)
index 0000000..70a6145
--- /dev/null
@@ -0,0 +1,1451 @@
+/*
+ *Copyright (C) 2010 OKI SEMICONDUCTOR CO., 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; version 2 of the License.
+ *
+ *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/serial_reg.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/serial_core.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include <linux/dmaengine.h>
+#include <linux/pch_dma.h>
+
+enum {
+       PCH_UART_HANDLED_RX_INT_SHIFT,
+       PCH_UART_HANDLED_TX_INT_SHIFT,
+       PCH_UART_HANDLED_RX_ERR_INT_SHIFT,
+       PCH_UART_HANDLED_RX_TRG_INT_SHIFT,
+       PCH_UART_HANDLED_MS_INT_SHIFT,
+};
+
+enum {
+       PCH_UART_8LINE,
+       PCH_UART_2LINE,
+};
+
+#define PCH_UART_DRIVER_DEVICE "ttyPCH"
+
+#define PCH_UART_NR_GE_256FIFO         1
+#define PCH_UART_NR_GE_64FIFO          3
+#define PCH_UART_NR_GE (PCH_UART_NR_GE_256FIFO+PCH_UART_NR_GE_64FIFO)
+#define PCH_UART_NR    PCH_UART_NR_GE
+
+#define PCH_UART_HANDLED_RX_INT        (1<<((PCH_UART_HANDLED_RX_INT_SHIFT)<<1))
+#define PCH_UART_HANDLED_TX_INT        (1<<((PCH_UART_HANDLED_TX_INT_SHIFT)<<1))
+#define PCH_UART_HANDLED_RX_ERR_INT    (1<<((\
+                                       PCH_UART_HANDLED_RX_ERR_INT_SHIFT)<<1))
+#define PCH_UART_HANDLED_RX_TRG_INT    (1<<((\
+                                       PCH_UART_HANDLED_RX_TRG_INT_SHIFT)<<1))
+#define PCH_UART_HANDLED_MS_INT        (1<<((PCH_UART_HANDLED_MS_INT_SHIFT)<<1))
+
+#define PCH_UART_RBR           0x00
+#define PCH_UART_THR           0x00
+
+#define PCH_UART_IER_MASK      (PCH_UART_IER_ERBFI|PCH_UART_IER_ETBEI|\
+                               PCH_UART_IER_ELSI|PCH_UART_IER_EDSSI)
+#define PCH_UART_IER_ERBFI     0x00000001
+#define PCH_UART_IER_ETBEI     0x00000002
+#define PCH_UART_IER_ELSI      0x00000004
+#define PCH_UART_IER_EDSSI     0x00000008
+
+#define PCH_UART_IIR_IP                        0x00000001
+#define PCH_UART_IIR_IID               0x00000006
+#define PCH_UART_IIR_MSI               0x00000000
+#define PCH_UART_IIR_TRI               0x00000002
+#define PCH_UART_IIR_RRI               0x00000004
+#define PCH_UART_IIR_REI               0x00000006
+#define PCH_UART_IIR_TOI               0x00000008
+#define PCH_UART_IIR_FIFO256           0x00000020
+#define PCH_UART_IIR_FIFO64            PCH_UART_IIR_FIFO256
+#define PCH_UART_IIR_FE                        0x000000C0
+
+#define PCH_UART_FCR_FIFOE             0x00000001
+#define PCH_UART_FCR_RFR               0x00000002
+#define PCH_UART_FCR_TFR               0x00000004
+#define PCH_UART_FCR_DMS               0x00000008
+#define PCH_UART_FCR_FIFO256           0x00000020
+#define PCH_UART_FCR_RFTL              0x000000C0
+
+#define PCH_UART_FCR_RFTL1             0x00000000
+#define PCH_UART_FCR_RFTL64            0x00000040
+#define PCH_UART_FCR_RFTL128           0x00000080
+#define PCH_UART_FCR_RFTL224           0x000000C0
+#define PCH_UART_FCR_RFTL16            PCH_UART_FCR_RFTL64
+#define PCH_UART_FCR_RFTL32            PCH_UART_FCR_RFTL128
+#define PCH_UART_FCR_RFTL56            PCH_UART_FCR_RFTL224
+#define PCH_UART_FCR_RFTL4             PCH_UART_FCR_RFTL64
+#define PCH_UART_FCR_RFTL8             PCH_UART_FCR_RFTL128
+#define PCH_UART_FCR_RFTL14            PCH_UART_FCR_RFTL224
+#define PCH_UART_FCR_RFTL_SHIFT                6
+
+#define PCH_UART_LCR_WLS       0x00000003
+#define PCH_UART_LCR_STB       0x00000004
+#define PCH_UART_LCR_PEN       0x00000008
+#define PCH_UART_LCR_EPS       0x00000010
+#define PCH_UART_LCR_SP                0x00000020
+#define PCH_UART_LCR_SB                0x00000040
+#define PCH_UART_LCR_DLAB      0x00000080
+#define PCH_UART_LCR_NP                0x00000000
+#define PCH_UART_LCR_OP                PCH_UART_LCR_PEN
+#define PCH_UART_LCR_EP                (PCH_UART_LCR_PEN | PCH_UART_LCR_EPS)
+#define PCH_UART_LCR_1P                (PCH_UART_LCR_PEN | PCH_UART_LCR_SP)
+#define PCH_UART_LCR_0P                (PCH_UART_LCR_PEN | PCH_UART_LCR_EPS |\
+                               PCH_UART_LCR_SP)
+
+#define PCH_UART_LCR_5BIT      0x00000000
+#define PCH_UART_LCR_6BIT      0x00000001
+#define PCH_UART_LCR_7BIT      0x00000002
+#define PCH_UART_LCR_8BIT      0x00000003
+
+#define PCH_UART_MCR_DTR       0x00000001
+#define PCH_UART_MCR_RTS       0x00000002
+#define PCH_UART_MCR_OUT       0x0000000C
+#define PCH_UART_MCR_LOOP      0x00000010
+#define PCH_UART_MCR_AFE       0x00000020
+
+#define PCH_UART_LSR_DR                0x00000001
+#define PCH_UART_LSR_ERR       (1<<7)
+
+#define PCH_UART_MSR_DCTS      0x00000001
+#define PCH_UART_MSR_DDSR      0x00000002
+#define PCH_UART_MSR_TERI      0x00000004
+#define PCH_UART_MSR_DDCD      0x00000008
+#define PCH_UART_MSR_CTS       0x00000010
+#define PCH_UART_MSR_DSR       0x00000020
+#define PCH_UART_MSR_RI                0x00000040
+#define PCH_UART_MSR_DCD       0x00000080
+#define PCH_UART_MSR_DELTA     (PCH_UART_MSR_DCTS | PCH_UART_MSR_DDSR |\
+                               PCH_UART_MSR_TERI | PCH_UART_MSR_DDCD)
+
+#define PCH_UART_DLL           0x00
+#define PCH_UART_DLM           0x01
+
+#define DIV_ROUND(a, b)        (((a) + ((b)/2)) / (b))
+
+#define PCH_UART_IID_RLS       (PCH_UART_IIR_REI)
+#define PCH_UART_IID_RDR       (PCH_UART_IIR_RRI)
+#define PCH_UART_IID_RDR_TO    (PCH_UART_IIR_RRI | PCH_UART_IIR_TOI)
+#define PCH_UART_IID_THRE      (PCH_UART_IIR_TRI)
+#define PCH_UART_IID_MS                (PCH_UART_IIR_MSI)
+
+#define PCH_UART_HAL_PARITY_NONE       (PCH_UART_LCR_NP)
+#define PCH_UART_HAL_PARITY_ODD                (PCH_UART_LCR_OP)
+#define PCH_UART_HAL_PARITY_EVEN       (PCH_UART_LCR_EP)
+#define PCH_UART_HAL_PARITY_FIX1       (PCH_UART_LCR_1P)
+#define PCH_UART_HAL_PARITY_FIX0       (PCH_UART_LCR_0P)
+#define PCH_UART_HAL_5BIT              (PCH_UART_LCR_5BIT)
+#define PCH_UART_HAL_6BIT              (PCH_UART_LCR_6BIT)
+#define PCH_UART_HAL_7BIT              (PCH_UART_LCR_7BIT)
+#define PCH_UART_HAL_8BIT              (PCH_UART_LCR_8BIT)
+#define PCH_UART_HAL_STB1              0
+#define PCH_UART_HAL_STB2              (PCH_UART_LCR_STB)
+
+#define PCH_UART_HAL_CLR_TX_FIFO       (PCH_UART_FCR_TFR)
+#define PCH_UART_HAL_CLR_RX_FIFO       (PCH_UART_FCR_RFR)
+#define PCH_UART_HAL_CLR_ALL_FIFO      (PCH_UART_HAL_CLR_TX_FIFO | \
+                                       PCH_UART_HAL_CLR_RX_FIFO)
+
+#define PCH_UART_HAL_DMA_MODE0         0
+#define PCH_UART_HAL_FIFO_DIS          0
+#define PCH_UART_HAL_FIFO16            (PCH_UART_FCR_FIFOE)
+#define PCH_UART_HAL_FIFO256           (PCH_UART_FCR_FIFOE | \
+                                       PCH_UART_FCR_FIFO256)
+#define PCH_UART_HAL_FIFO64            (PCH_UART_HAL_FIFO256)
+#define PCH_UART_HAL_TRIGGER1          (PCH_UART_FCR_RFTL1)
+#define PCH_UART_HAL_TRIGGER64         (PCH_UART_FCR_RFTL64)
+#define PCH_UART_HAL_TRIGGER128                (PCH_UART_FCR_RFTL128)
+#define PCH_UART_HAL_TRIGGER224                (PCH_UART_FCR_RFTL224)
+#define PCH_UART_HAL_TRIGGER16         (PCH_UART_FCR_RFTL16)
+#define PCH_UART_HAL_TRIGGER32         (PCH_UART_FCR_RFTL32)
+#define PCH_UART_HAL_TRIGGER56         (PCH_UART_FCR_RFTL56)
+#define PCH_UART_HAL_TRIGGER4          (PCH_UART_FCR_RFTL4)
+#define PCH_UART_HAL_TRIGGER8          (PCH_UART_FCR_RFTL8)
+#define PCH_UART_HAL_TRIGGER14         (PCH_UART_FCR_RFTL14)
+#define PCH_UART_HAL_TRIGGER_L         (PCH_UART_FCR_RFTL64)
+#define PCH_UART_HAL_TRIGGER_M         (PCH_UART_FCR_RFTL128)
+#define PCH_UART_HAL_TRIGGER_H         (PCH_UART_FCR_RFTL224)
+
+#define PCH_UART_HAL_RX_INT            (PCH_UART_IER_ERBFI)
+#define PCH_UART_HAL_TX_INT            (PCH_UART_IER_ETBEI)
+#define PCH_UART_HAL_RX_ERR_INT                (PCH_UART_IER_ELSI)
+#define PCH_UART_HAL_MS_INT            (PCH_UART_IER_EDSSI)
+#define PCH_UART_HAL_ALL_INT           (PCH_UART_IER_MASK)
+
+#define PCH_UART_HAL_DTR               (PCH_UART_MCR_DTR)
+#define PCH_UART_HAL_RTS               (PCH_UART_MCR_RTS)
+#define PCH_UART_HAL_OUT               (PCH_UART_MCR_OUT)
+#define PCH_UART_HAL_LOOP              (PCH_UART_MCR_LOOP)
+#define PCH_UART_HAL_AFE               (PCH_UART_MCR_AFE)
+
+struct pch_uart_buffer {
+       unsigned char *buf;
+       int size;
+};
+
+struct eg20t_port {
+       struct uart_port port;
+       int port_type;
+       void __iomem *membase;
+       resource_size_t mapbase;
+       unsigned int iobase;
+       struct pci_dev *pdev;
+       int fifo_size;
+       int base_baud;
+       int start_tx;
+       int start_rx;
+       int tx_empty;
+       int int_dis_flag;
+       int trigger;
+       int trigger_level;
+       struct pch_uart_buffer rxbuf;
+       unsigned int dmsr;
+       unsigned int fcr;
+       unsigned int use_dma;
+       unsigned int use_dma_flag;
+       struct dma_async_tx_descriptor  *desc_tx;
+       struct dma_async_tx_descriptor  *desc_rx;
+       struct pch_dma_slave            param_tx;
+       struct pch_dma_slave            param_rx;
+       struct dma_chan                 *chan_tx;
+       struct dma_chan                 *chan_rx;
+       struct scatterlist              sg_tx;
+       struct scatterlist              sg_rx;
+       int                             tx_dma_use;
+       void                            *rx_buf_virt;
+       dma_addr_t                      rx_buf_dma;
+};
+
+static unsigned int default_baud = 9600;
+static const int trigger_level_256[4] = { 1, 64, 128, 224 };
+static const int trigger_level_64[4] = { 1, 16, 32, 56 };
+static const int trigger_level_16[4] = { 1, 4, 8, 14 };
+static const int trigger_level_1[4] = { 1, 1, 1, 1 };
+
+static void pch_uart_hal_request(struct pci_dev *pdev, int fifosize,
+                                int base_baud)
+{
+       struct eg20t_port *priv = pci_get_drvdata(pdev);
+
+       priv->trigger_level = 1;
+       priv->fcr = 0;
+}
+
+static unsigned int get_msr(struct eg20t_port *priv, void __iomem *base)
+{
+       unsigned int msr = ioread8(base + UART_MSR);
+       priv->dmsr |= msr & PCH_UART_MSR_DELTA;
+
+       return msr;
+}
+
+static void pch_uart_hal_enable_interrupt(struct eg20t_port *priv,
+                                         unsigned int flag)
+{
+       u8 ier = ioread8(priv->membase + UART_IER);
+       ier |= flag & PCH_UART_IER_MASK;
+       iowrite8(ier, priv->membase + UART_IER);
+}
+
+static void pch_uart_hal_disable_interrupt(struct eg20t_port *priv,
+                                          unsigned int flag)
+{
+       u8 ier = ioread8(priv->membase + UART_IER);
+       ier &= ~(flag & PCH_UART_IER_MASK);
+       iowrite8(ier, priv->membase + UART_IER);
+}
+
+static int pch_uart_hal_set_line(struct eg20t_port *priv, int baud,
+                                unsigned int parity, unsigned int bits,
+                                unsigned int stb)
+{
+       unsigned int dll, dlm, lcr;
+       int div;
+
+       div = DIV_ROUND(priv->base_baud / 16, baud);
+       if (div < 0 || USHRT_MAX <= div) {
+               pr_err("Invalid Baud(div=0x%x)\n", div);
+               return -EINVAL;
+       }
+
+       dll = (unsigned int)div & 0x00FFU;
+       dlm = ((unsigned int)div >> 8) & 0x00FFU;
+
+       if (parity & ~(PCH_UART_LCR_PEN | PCH_UART_LCR_EPS | PCH_UART_LCR_SP)) {
+               pr_err("Invalid parity(0x%x)\n", parity);
+               return -EINVAL;
+       }
+
+       if (bits & ~PCH_UART_LCR_WLS) {
+               pr_err("Invalid bits(0x%x)\n", bits);
+               return -EINVAL;
+       }
+
+       if (stb & ~PCH_UART_LCR_STB) {
+               pr_err("Invalid STB(0x%x)\n", stb);
+               return -EINVAL;
+       }
+
+       lcr = parity;
+       lcr |= bits;
+       lcr |= stb;
+
+       pr_debug("%s:baud = %d, div = %04x, lcr = %02x (%lu)\n",
+                __func__, baud, div, lcr, jiffies);
+       iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR);
+       iowrite8(dll, priv->membase + PCH_UART_DLL);
+       iowrite8(dlm, priv->membase + PCH_UART_DLM);
+       iowrite8(lcr, priv->membase + UART_LCR);
+
+       return 0;
+}
+
+static int pch_uart_hal_fifo_reset(struct eg20t_port *priv,
+                                   unsigned int flag)
+{
+       if (flag & ~(PCH_UART_FCR_TFR | PCH_UART_FCR_RFR)) {
+               pr_err("%s:Invalid flag(0x%x)\n", __func__, flag);
+               return -EINVAL;
+       }
+
+       iowrite8(PCH_UART_FCR_FIFOE | priv->fcr, priv->membase + UART_FCR);
+       iowrite8(PCH_UART_FCR_FIFOE | priv->fcr | flag,
+                priv->membase + UART_FCR);
+       iowrite8(priv->fcr, priv->membase + UART_FCR);
+
+       return 0;
+}
+
+static int pch_uart_hal_set_fifo(struct eg20t_port *priv,
+                                unsigned int dmamode,
+                                unsigned int fifo_size, unsigned int trigger)
+{
+       u8 fcr;
+
+       if (dmamode & ~PCH_UART_FCR_DMS) {
+               pr_err("%s:Invalid DMA Mode(0x%x)\n", __func__, dmamode);
+               return -EINVAL;
+       }
+
+       if (fifo_size & ~(PCH_UART_FCR_FIFOE | PCH_UART_FCR_FIFO256)) {
+               pr_err("%s:Invalid FIFO SIZE(0x%x)\n", __func__, fifo_size);
+               return -EINVAL;
+       }
+
+       if (trigger & ~PCH_UART_FCR_RFTL) {
+               pr_err("%s:Invalid TRIGGER(0x%x)\n", __func__, trigger);
+               return -EINVAL;
+       }
+
+       switch (priv->fifo_size) {
+       case 256:
+               priv->trigger_level =
+                   trigger_level_256[trigger >> PCH_UART_FCR_RFTL_SHIFT];
+               break;
+       case 64:
+               priv->trigger_level =
+                   trigger_level_64[trigger >> PCH_UART_FCR_RFTL_SHIFT];
+               break;
+       case 16:
+               priv->trigger_level =
+                   trigger_level_16[trigger >> PCH_UART_FCR_RFTL_SHIFT];
+               break;
+       default:
+               priv->trigger_level =
+                   trigger_level_1[trigger >> PCH_UART_FCR_RFTL_SHIFT];
+               break;
+       }
+       fcr =
+           dmamode | fifo_size | trigger | PCH_UART_FCR_RFR | PCH_UART_FCR_TFR;
+       iowrite8(PCH_UART_FCR_FIFOE, priv->membase + UART_FCR);
+       iowrite8(PCH_UART_FCR_FIFOE | PCH_UART_FCR_RFR | PCH_UART_FCR_TFR,
+                priv->membase + UART_FCR);
+       iowrite8(fcr, priv->membase + UART_FCR);
+       priv->fcr = fcr;
+
+       return 0;
+}
+
+static u8 pch_uart_hal_get_modem(struct eg20t_port *priv)
+{
+       priv->dmsr = 0;
+       return get_msr(priv, priv->membase);
+}
+
+static int pch_uart_hal_write(struct eg20t_port *priv,
+                             const unsigned char *buf, int tx_size)
+{
+       int i;
+       unsigned int thr;
+
+       for (i = 0; i < tx_size;) {
+               thr = buf[i++];
+               iowrite8(thr, priv->membase + PCH_UART_THR);
+       }
+       return i;
+}
+
+static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf,
+                            int rx_size)
+{
+       int i;
+       u8 rbr, lsr;
+
+       lsr = ioread8(priv->membase + UART_LSR);
+       for (i = 0, lsr = ioread8(priv->membase + UART_LSR);
+            i < rx_size && lsr & UART_LSR_DR;
+            lsr = ioread8(priv->membase + UART_LSR)) {
+               rbr = ioread8(priv->membase + PCH_UART_RBR);
+               buf[i++] = rbr;
+       }
+       return i;
+}
+
+static unsigned int pch_uart_hal_get_iid(struct eg20t_port *priv)
+{
+       unsigned int iir;
+       int ret;
+
+       iir = ioread8(priv->membase + UART_IIR);
+       ret = (iir & (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP));
+       return ret;
+}
+
+static u8 pch_uart_hal_get_line_status(struct eg20t_port *priv)
+{
+       return ioread8(priv->membase + UART_LSR);
+}
+
+static void pch_uart_hal_set_break(struct eg20t_port *priv, int on)
+{
+       unsigned int lcr;
+
+       lcr = ioread8(priv->membase + UART_LCR);
+       if (on)
+               lcr |= PCH_UART_LCR_SB;
+       else
+               lcr &= ~PCH_UART_LCR_SB;
+
+       iowrite8(lcr, priv->membase + UART_LCR);
+}
+
+static int push_rx(struct eg20t_port *priv, const unsigned char *buf,
+                  int size)
+{
+       struct uart_port *port;
+       struct tty_struct *tty;
+
+       port = &priv->port;
+       tty = tty_port_tty_get(&port->state->port);
+       if (!tty) {
+               pr_debug("%s:tty is busy now", __func__);
+               return -EBUSY;
+       }
+
+       tty_insert_flip_string(tty, buf, size);
+       tty_flip_buffer_push(tty);
+       tty_kref_put(tty);
+
+       return 0;
+}
+
+static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf)
+{
+       int ret;
+       struct uart_port *port = &priv->port;
+
+       if (port->x_char) {
+               pr_debug("%s:X character send %02x (%lu)\n", __func__,
+                       port->x_char, jiffies);
+               buf[0] = port->x_char;
+               port->x_char = 0;
+               ret = 1;
+       } else {
+               ret = 0;
+       }
+
+       return ret;
+}
+
+static int dma_push_rx(struct eg20t_port *priv, int size)
+{
+       struct tty_struct *tty;
+       int room;
+       struct uart_port *port = &priv->port;
+
+       port = &priv->port;
+       tty = tty_port_tty_get(&port->state->port);
+       if (!tty) {
+               pr_debug("%s:tty is busy now", __func__);
+               return 0;
+       }
+
+       room = tty_buffer_request_room(tty, size);
+
+       if (room < size)
+               dev_warn(port->dev, "Rx overrun: dropping %u bytes\n",
+                        size - room);
+       if (!room)
+               return room;
+
+       tty_insert_flip_string(tty, sg_virt(&priv->sg_rx), size);
+
+       port->icount.rx += room;
+       tty_kref_put(tty);
+
+       return room;
+}
+
+static void pch_free_dma(struct uart_port *port)
+{
+       struct eg20t_port *priv;
+       priv = container_of(port, struct eg20t_port, port);
+
+       if (priv->chan_tx) {
+               dma_release_channel(priv->chan_tx);
+               priv->chan_tx = NULL;
+       }
+       if (priv->chan_rx) {
+               dma_release_channel(priv->chan_rx);
+               priv->chan_rx = NULL;
+       }
+       if (sg_dma_address(&priv->sg_rx))
+               dma_free_coherent(port->dev, port->fifosize,
+                                 sg_virt(&priv->sg_rx),
+                                 sg_dma_address(&priv->sg_rx));
+
+       return;
+}
+
+static bool filter(struct dma_chan *chan, void *slave)
+{
+       struct pch_dma_slave *param = slave;
+
+       if ((chan->chan_id == param->chan_id) && (param->dma_dev ==
+                                                 chan->device->dev)) {
+               chan->private = param;
+               return true;
+       } else {
+               return false;
+       }
+}
+
+static void pch_request_dma(struct uart_port *port)
+{
+       dma_cap_mask_t mask;
+       struct dma_chan *chan;
+       struct pci_dev *dma_dev;
+       struct pch_dma_slave *param;
+       struct eg20t_port *priv =
+                               container_of(port, struct eg20t_port, port);
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+
+       dma_dev = pci_get_bus_and_slot(2, PCI_DEVFN(0xa, 0)); /* Get DMA's dev
+                                                               information */
+       /* Set Tx DMA */
+       param = &priv->param_tx;
+       param->dma_dev = &dma_dev->dev;
+       param->chan_id = priv->port.line;
+       param->tx_reg = port->mapbase + UART_TX;
+       chan = dma_request_channel(mask, filter, param);
+       if (!chan) {
+               pr_err("%s:dma_request_channel FAILS(Tx)\n", __func__);
+               return;
+       }
+       priv->chan_tx = chan;
+
+       /* Set Rx DMA */
+       param = &priv->param_rx;
+       param->dma_dev = &dma_dev->dev;
+       param->chan_id = priv->port.line + 1; /* Rx = Tx + 1 */
+       param->rx_reg = port->mapbase + UART_RX;
+       chan = dma_request_channel(mask, filter, param);
+       if (!chan) {
+               pr_err("%s:dma_request_channel FAILS(Rx)\n", __func__);
+               dma_release_channel(priv->chan_tx);
+               return;
+       }
+
+       /* Get Consistent memory for DMA */
+       priv->rx_buf_virt = dma_alloc_coherent(port->dev, port->fifosize,
+                                   &priv->rx_buf_dma, GFP_KERNEL);
+       priv->chan_rx = chan;
+}
+
+static void pch_dma_rx_complete(void *arg)
+{
+       struct eg20t_port *priv = arg;
+       struct uart_port *port = &priv->port;
+       struct tty_struct *tty = tty_port_tty_get(&port->state->port);
+
+       if (!tty) {
+               pr_debug("%s:tty is busy now", __func__);
+               return;
+       }
+
+       if (dma_push_rx(priv, priv->trigger_level))
+               tty_flip_buffer_push(tty);
+
+       tty_kref_put(tty);
+}
+
+static void pch_dma_tx_complete(void *arg)
+{
+       struct eg20t_port *priv = arg;
+       struct uart_port *port = &priv->port;
+       struct circ_buf *xmit = &port->state->xmit;
+
+       xmit->tail += sg_dma_len(&priv->sg_tx);
+       xmit->tail &= UART_XMIT_SIZE - 1;
+       port->icount.tx += sg_dma_len(&priv->sg_tx);
+
+       async_tx_ack(priv->desc_tx);
+       priv->tx_dma_use = 0;
+}
+
+static int pop_tx(struct eg20t_port *priv, unsigned char *buf, int size)
+{
+       int count = 0;
+       struct uart_port *port = &priv->port;
+       struct circ_buf *xmit = &port->state->xmit;
+
+       if (uart_tx_stopped(port) || uart_circ_empty(xmit) || count >= size)
+               goto pop_tx_end;
+
+       do {
+               int cnt_to_end =
+                   CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+               int sz = min(size - count, cnt_to_end);
+               memcpy(&buf[count], &xmit->buf[xmit->tail], sz);
+               xmit->tail = (xmit->tail + sz) & (UART_XMIT_SIZE - 1);
+               count += sz;
+       } while (!uart_circ_empty(xmit) && count < size);
+
+pop_tx_end:
+       pr_debug("%d characters. Remained %d characters. (%lu)\n",
+                count, size - count, jiffies);
+
+       return count;
+}
+
+static int handle_rx_to(struct eg20t_port *priv)
+{
+       struct pch_uart_buffer *buf;
+       int rx_size;
+       int ret;
+       if (!priv->start_rx) {
+               pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT);
+               return 0;
+       }
+       buf = &priv->rxbuf;
+       do {
+               rx_size = pch_uart_hal_read(priv, buf->buf, buf->size);
+               ret = push_rx(priv, buf->buf, rx_size);
+               if (ret)
+                       return 0;
+       } while (rx_size == buf->size);
+
+       return PCH_UART_HANDLED_RX_INT;
+}
+
+static int handle_rx(struct eg20t_port *priv)
+{
+       return handle_rx_to(priv);
+}
+
+static int dma_handle_rx(struct eg20t_port *priv)
+{
+       struct uart_port *port = &priv->port;
+       struct dma_async_tx_descriptor *desc;
+       struct scatterlist *sg;
+
+       priv = container_of(port, struct eg20t_port, port);
+       sg = &priv->sg_rx;
+
+       sg_init_table(&priv->sg_rx, 1); /* Initialize SG table */
+
+       sg_dma_len(sg) = priv->fifo_size;
+
+       sg_set_page(&priv->sg_rx, virt_to_page(priv->rx_buf_virt),
+                    sg_dma_len(sg), (unsigned long)priv->rx_buf_virt &
+                    ~PAGE_MASK);
+
+       sg_dma_address(sg) = priv->rx_buf_dma;
+
+       desc = priv->chan_rx->device->device_prep_slave_sg(priv->chan_rx,
+                       sg, 1, DMA_FROM_DEVICE,
+                       DMA_PREP_INTERRUPT);
+       if (!desc)
+               return 0;
+
+       priv->desc_rx = desc;
+       desc->callback = pch_dma_rx_complete;
+       desc->callback_param = priv;
+       desc->tx_submit(desc);
+       dma_async_issue_pending(priv->chan_rx);
+
+       return PCH_UART_HANDLED_RX_INT;
+}
+
+static unsigned int handle_tx(struct eg20t_port *priv)
+{
+       struct uart_port *port = &priv->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       int ret;
+       int fifo_size;
+       int tx_size;
+       int size;
+       int tx_empty;
+
+       if (!priv->start_tx) {
+               pr_info("%s:Tx isn't started. (%lu)\n", __func__, jiffies);
+               pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
+               priv->tx_empty = 1;
+               return 0;
+       }
+
+       fifo_size = max(priv->fifo_size, 1);
+       tx_empty = 1;
+       if (pop_tx_x(priv, xmit->buf)) {
+               pch_uart_hal_write(priv, xmit->buf, 1);
+               port->icount.tx++;
+               tx_empty = 0;
+               fifo_size--;
+       }
+       size = min(xmit->head - xmit->tail, fifo_size);
+       tx_size = pop_tx(priv, xmit->buf, size);
+       if (tx_size > 0) {
+               ret = pch_uart_hal_write(priv, xmit->buf, tx_size);
+               port->icount.tx += ret;
+               tx_empty = 0;
+       }
+
+       priv->tx_empty = tx_empty;
+
+       if (tx_empty)
+               pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
+
+       return PCH_UART_HANDLED_TX_INT;
+}
+
+static unsigned int dma_handle_tx(struct eg20t_port *priv)
+{
+       struct uart_port *port = &priv->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       struct scatterlist *sg = &priv->sg_tx;
+       int nent;
+       int fifo_size;
+       int tx_empty;
+       struct dma_async_tx_descriptor *desc;
+
+       if (!priv->start_tx) {
+               pr_info("%s:Tx isn't started. (%lu)\n", __func__, jiffies);
+               pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
+               priv->tx_empty = 1;
+               return 0;
+       }
+
+       fifo_size = max(priv->fifo_size, 1);
+       tx_empty = 1;
+       if (pop_tx_x(priv, xmit->buf)) {
+               pch_uart_hal_write(priv, xmit->buf, 1);
+               port->icount.tx++;
+               tx_empty = 0;
+               fifo_size--;
+       }
+
+       pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
+
+       priv->tx_dma_use = 1;
+
+       sg_init_table(&priv->sg_tx, 1); /* Initialize SG table */
+
+       sg_set_page(&priv->sg_tx, virt_to_page(xmit->buf),
+                   UART_XMIT_SIZE, (int)xmit->buf & ~PAGE_MASK);
+
+       nent = dma_map_sg(port->dev, &priv->sg_tx, 1, DMA_TO_DEVICE);
+       if (!nent) {
+               pr_err("%s:dma_map_sg Failed\n", __func__);
+               return 0;
+       }
+
+       sg->offset = xmit->tail & (UART_XMIT_SIZE - 1);
+       sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) +
+                             sg->offset;
+       sg_dma_len(sg) = min((int)CIRC_CNT(xmit->head, xmit->tail,
+                            UART_XMIT_SIZE), CIRC_CNT_TO_END(xmit->head,
+                            xmit->tail, UART_XMIT_SIZE));
+
+       desc = priv->chan_tx->device->device_prep_slave_sg(priv->chan_tx,
+               sg, nent, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!desc) {
+               pr_err("%s:device_prep_slave_sg Failed\n", __func__);
+               return 0;
+       }
+
+       dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE);
+
+       priv->desc_tx = desc;
+       desc->callback = pch_dma_tx_complete;
+       desc->callback_param = priv;
+
+       desc->tx_submit(desc);
+
+       dma_async_issue_pending(priv->chan_tx);
+
+       return PCH_UART_HANDLED_TX_INT;
+}
+
+static void pch_uart_err_ir(struct eg20t_port *priv, unsigned int lsr)
+{
+       u8 fcr = ioread8(priv->membase + UART_FCR);
+
+       /* Reset FIFO */
+       fcr |= UART_FCR_CLEAR_RCVR;
+       iowrite8(fcr, priv->membase + UART_FCR);
+
+       if (lsr & PCH_UART_LSR_ERR)
+               dev_err(&priv->pdev->dev, "Error data in FIFO\n");
+
+       if (lsr & UART_LSR_FE)
+               dev_err(&priv->pdev->dev, "Framing Error\n");
+
+       if (lsr & UART_LSR_PE)
+               dev_err(&priv->pdev->dev, "Parity Error\n");
+
+       if (lsr & UART_LSR_OE)
+               dev_err(&priv->pdev->dev, "Overrun Error\n");
+}
+
+static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
+{
+       struct eg20t_port *priv = dev_id;
+       unsigned int handled;
+       u8 lsr;
+       int ret = 0;
+       unsigned int iid;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->port.lock, flags);
+       handled = 0;
+       while ((iid = pch_uart_hal_get_iid(priv)) > 1) {
+               switch (iid) {
+               case PCH_UART_IID_RLS:  /* Receiver Line Status */
+                       lsr = pch_uart_hal_get_line_status(priv);
+                       if (lsr & (PCH_UART_LSR_ERR | UART_LSR_FE |
+                                               UART_LSR_PE | UART_LSR_OE)) {
+                               pch_uart_err_ir(priv, lsr);
+                               ret = PCH_UART_HANDLED_RX_ERR_INT;
+                       }
+                       break;
+               case PCH_UART_IID_RDR:  /* Received Data Ready */
+                       if (priv->use_dma)
+                               ret = dma_handle_rx(priv);
+                       else
+                               ret = handle_rx(priv);
+                       break;
+               case PCH_UART_IID_RDR_TO:       /* Received Data Ready
+                                                  (FIFO Timeout) */
+                       ret = handle_rx_to(priv);
+                       break;
+               case PCH_UART_IID_THRE: /* Transmitter Holding Register
+                                                  Empty */
+                       if (priv->use_dma)
+                               ret = dma_handle_tx(priv);
+                       else
+                               ret = handle_tx(priv);
+                       break;
+               case PCH_UART_IID_MS:   /* Modem Status */
+                       ret = PCH_UART_HANDLED_MS_INT;
+                       break;
+               default:        /* Never junp to this label */
+                       pr_err("%s:iid=%d (%lu)\n", __func__, iid, jiffies);
+                       ret = -1;
+                       break;
+               }
+               handled |= (unsigned int)ret;
+       }
+       if (handled == 0 && iid <= 1) {
+               if (priv->int_dis_flag)
+                       priv->int_dis_flag = 0;
+       }
+
+       spin_unlock_irqrestore(&priv->port.lock, flags);
+       return IRQ_RETVAL(handled);
+}
+
+/* This function tests whether the transmitter fifo and shifter for the port
+                                               described by 'port' is empty. */
+static unsigned int pch_uart_tx_empty(struct uart_port *port)
+{
+       struct eg20t_port *priv;
+       int ret;
+       priv = container_of(port, struct eg20t_port, port);
+       if (priv->tx_empty)
+               ret = TIOCSER_TEMT;
+       else
+               ret = 0;
+
+       return ret;
+}
+
+/* Returns the current state of modem control inputs. */
+static unsigned int pch_uart_get_mctrl(struct uart_port *port)
+{
+       struct eg20t_port *priv;
+       u8 modem;
+       unsigned int ret = 0;
+
+       priv = container_of(port, struct eg20t_port, port);
+       modem = pch_uart_hal_get_modem(priv);
+
+       if (modem & UART_MSR_DCD)
+               ret |= TIOCM_CAR;
+
+       if (modem & UART_MSR_RI)
+               ret |= TIOCM_RNG;
+
+       if (modem & UART_MSR_DSR)
+               ret |= TIOCM_DSR;
+
+       if (modem & UART_MSR_CTS)
+               ret |= TIOCM_CTS;
+
+       return ret;
+}
+
+static void pch_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       u32 mcr = 0;
+       unsigned int dat;
+       struct eg20t_port *priv = container_of(port, struct eg20t_port, port);
+
+       if (mctrl & TIOCM_DTR)
+               mcr |= UART_MCR_DTR;
+       if (mctrl & TIOCM_RTS)
+               mcr |= UART_MCR_RTS;
+       if (mctrl & TIOCM_LOOP)
+               mcr |= UART_MCR_LOOP;
+
+       if (mctrl) {
+               dat = pch_uart_get_mctrl(port);
+               dat |= mcr;
+               iowrite8(dat, priv->membase + UART_MCR);
+       }
+}
+
+static void pch_uart_stop_tx(struct uart_port *port)
+{
+       struct eg20t_port *priv;
+       priv = container_of(port, struct eg20t_port, port);
+       priv->start_tx = 0;
+       priv->tx_dma_use = 0;
+}
+
+static void pch_uart_start_tx(struct uart_port *port)
+{
+       struct eg20t_port *priv;
+
+       priv = container_of(port, struct eg20t_port, port);
+
+       if (priv->use_dma)
+               if (priv->tx_dma_use)
+                       return;
+
+       priv->start_tx = 1;
+       pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_TX_INT);
+}
+
+static void pch_uart_stop_rx(struct uart_port *port)
+{
+       struct eg20t_port *priv;
+       priv = container_of(port, struct eg20t_port, port);
+       priv->start_rx = 0;
+       pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT);
+       priv->int_dis_flag = 1;
+}
+
+/* Enable the modem status interrupts. */
+static void pch_uart_enable_ms(struct uart_port *port)
+{
+       struct eg20t_port *priv;
+       priv = container_of(port, struct eg20t_port, port);
+       pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_MS_INT);
+}
+
+/* Control the transmission of a break signal. */
+static void pch_uart_break_ctl(struct uart_port *port, int ctl)
+{
+       struct eg20t_port *priv;
+       unsigned long flags;
+
+       priv = container_of(port, struct eg20t_port, port);
+       spin_lock_irqsave(&port->lock, flags);
+       pch_uart_hal_set_break(priv, ctl);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* Grab any interrupt resources and initialise any low level driver state. */
+static int pch_uart_startup(struct uart_port *port)
+{
+       struct eg20t_port *priv;
+       int ret;
+       int fifo_size;
+       int trigger_level;
+
+       priv = container_of(port, struct eg20t_port, port);
+       priv->tx_empty = 1;
+       port->uartclk = priv->base_baud;
+       pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT);
+       ret = pch_uart_hal_set_line(priv, default_baud,
+                             PCH_UART_HAL_PARITY_NONE, PCH_UART_HAL_8BIT,
+                             PCH_UART_HAL_STB1);
+       if (ret)
+               return ret;
+
+       switch (priv->fifo_size) {
+       case 256:
+               fifo_size = PCH_UART_HAL_FIFO256;
+               break;
+       case 64:
+               fifo_size = PCH_UART_HAL_FIFO64;
+               break;
+       case 16:
+               fifo_size = PCH_UART_HAL_FIFO16;
+       case 1:
+       default:
+               fifo_size = PCH_UART_HAL_FIFO_DIS;
+               break;
+       }
+
+       switch (priv->trigger) {
+       case PCH_UART_HAL_TRIGGER1:
+               trigger_level = 1;
+               break;
+       case PCH_UART_HAL_TRIGGER_L:
+               trigger_level = priv->fifo_size / 4;
+               break;
+       case PCH_UART_HAL_TRIGGER_M:
+               trigger_level = priv->fifo_size / 2;
+               break;
+       case PCH_UART_HAL_TRIGGER_H:
+       default:
+               trigger_level = priv->fifo_size - (priv->fifo_size / 8);
+               break;
+       }
+
+       priv->trigger_level = trigger_level;
+       ret = pch_uart_hal_set_fifo(priv, PCH_UART_HAL_DMA_MODE0,
+                                   fifo_size, priv->trigger);
+       if (ret < 0)
+               return ret;
+
+       ret = request_irq(priv->port.irq, pch_uart_interrupt, IRQF_SHARED,
+                       KBUILD_MODNAME, priv);
+       if (ret < 0)
+               return ret;
+
+       if (priv->use_dma)
+               pch_request_dma(port);
+
+       priv->start_rx = 1;
+       pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT);
+       uart_update_timeout(port, CS8, default_baud);
+
+       return 0;
+}
+
+static void pch_uart_shutdown(struct uart_port *port)
+{
+       struct eg20t_port *priv;
+       int ret;
+
+       priv = container_of(port, struct eg20t_port, port);
+       pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT);
+       pch_uart_hal_fifo_reset(priv, PCH_UART_HAL_CLR_ALL_FIFO);
+       ret = pch_uart_hal_set_fifo(priv, PCH_UART_HAL_DMA_MODE0,
+                             PCH_UART_HAL_FIFO_DIS, PCH_UART_HAL_TRIGGER1);
+       if (ret)
+               pr_err("pch_uart_hal_set_fifo Failed(ret=%d)\n", ret);
+
+       if (priv->use_dma_flag)
+               pch_free_dma(port);
+
+       free_irq(priv->port.irq, priv);
+}
+
+/* Change the port parameters, including word length, parity, stop
+ *bits.  Update read_status_mask and ignore_status_mask to indicate
+ *the types of events we are interested in receiving.  */
+static void pch_uart_set_termios(struct uart_port *port,
+                                struct ktermios *termios, struct ktermios *old)
+{
+       int baud;
+       int rtn;
+       unsigned int parity, bits, stb;
+       struct eg20t_port *priv;
+       unsigned long flags;
+
+       priv = container_of(port, struct eg20t_port, port);
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               bits = PCH_UART_HAL_5BIT;
+               break;
+       case CS6:
+               bits = PCH_UART_HAL_6BIT;
+               break;
+       case CS7:
+               bits = PCH_UART_HAL_7BIT;
+               break;
+       default:                /* CS8 */
+               bits = PCH_UART_HAL_8BIT;
+               break;
+       }
+       if (termios->c_cflag & CSTOPB)
+               stb = PCH_UART_HAL_STB2;
+       else
+               stb = PCH_UART_HAL_STB1;
+
+       if (termios->c_cflag & PARENB) {
+               if (!(termios->c_cflag & PARODD))
+                       parity = PCH_UART_HAL_PARITY_ODD;
+               else
+                       parity = PCH_UART_HAL_PARITY_EVEN;
+
+       } else {
+               parity = PCH_UART_HAL_PARITY_NONE;
+       }
+       termios->c_cflag &= ~CMSPAR; /* Mark/Space parity is not supported */
+
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       uart_update_timeout(port, termios->c_cflag, baud);
+       rtn = pch_uart_hal_set_line(priv, baud, parity, bits, stb);
+       if (rtn)
+               goto out;
+
+       /* Don't rewrite B0 */
+       if (tty_termios_baud_rate(termios))
+               tty_termios_encode_baud_rate(termios, baud, baud);
+
+out:
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *pch_uart_type(struct uart_port *port)
+{
+       return KBUILD_MODNAME;
+}
+
+static void pch_uart_release_port(struct uart_port *port)
+{
+       struct eg20t_port *priv;
+
+       priv = container_of(port, struct eg20t_port, port);
+       pci_iounmap(priv->pdev, priv->membase);
+       pci_release_regions(priv->pdev);
+}
+
+static int pch_uart_request_port(struct uart_port *port)
+{
+       struct eg20t_port *priv;
+       int ret;
+       void __iomem *membase;
+
+       priv = container_of(port, struct eg20t_port, port);
+       ret = pci_request_regions(priv->pdev, KBUILD_MODNAME);
+       if (ret < 0)
+               return -EBUSY;
+
+       membase = pci_iomap(priv->pdev, 1, 0);
+       if (!membase) {
+               pci_release_regions(priv->pdev);
+               return -EBUSY;
+       }
+       priv->membase = port->membase = membase;
+
+       return 0;
+}
+
+static void pch_uart_config_port(struct uart_port *port, int type)
+{
+       struct eg20t_port *priv;
+
+       priv = container_of(port, struct eg20t_port, port);
+       if (type & UART_CONFIG_TYPE) {
+               port->type = priv->port_type;
+               pch_uart_request_port(port);
+       }
+}
+
+static int pch_uart_verify_port(struct uart_port *port,
+                               struct serial_struct *serinfo)
+{
+       struct eg20t_port *priv;
+
+       priv = container_of(port, struct eg20t_port, port);
+       if (serinfo->flags & UPF_LOW_LATENCY) {
+               pr_info("PCH UART : Use PIO Mode (without DMA)\n");
+               priv->use_dma = 0;
+               serinfo->flags &= ~UPF_LOW_LATENCY;
+       } else {
+#ifndef CONFIG_PCH_DMA
+               pr_err("%s : PCH DMA is not Loaded.\n", __func__);
+               return -EOPNOTSUPP;
+#endif
+               priv->use_dma = 1;
+               priv->use_dma_flag = 1;
+               pr_info("PCH UART : Use DMA Mode\n");
+       }
+
+       return 0;
+}
+
+static struct uart_ops pch_uart_ops = {
+       .tx_empty = pch_uart_tx_empty,
+       .set_mctrl = pch_uart_set_mctrl,
+       .get_mctrl = pch_uart_get_mctrl,
+       .stop_tx = pch_uart_stop_tx,
+       .start_tx = pch_uart_start_tx,
+       .stop_rx = pch_uart_stop_rx,
+       .enable_ms = pch_uart_enable_ms,
+       .break_ctl = pch_uart_break_ctl,
+       .startup = pch_uart_startup,
+       .shutdown = pch_uart_shutdown,
+       .set_termios = pch_uart_set_termios,
+/*     .pm             = pch_uart_pm,          Not supported yet */
+/*     .set_wake       = pch_uart_set_wake,    Not supported yet */
+       .type = pch_uart_type,
+       .release_port = pch_uart_release_port,
+       .request_port = pch_uart_request_port,
+       .config_port = pch_uart_config_port,
+       .verify_port = pch_uart_verify_port
+};
+
+static struct uart_driver pch_uart_driver = {
+       .owner = THIS_MODULE,
+       .driver_name = KBUILD_MODNAME,
+       .dev_name = PCH_UART_DRIVER_DEVICE,
+       .major = 0,
+       .minor = 0,
+       .nr = PCH_UART_NR,
+};
+
+static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
+                                               int port_type)
+{
+       struct eg20t_port *priv;
+       int ret;
+       unsigned int iobase;
+       unsigned int mapbase;
+       unsigned char *rxbuf;
+       int fifosize, base_baud;
+       static int num;
+
+       priv = kzalloc(sizeof(struct eg20t_port), GFP_KERNEL);
+       if (priv == NULL)
+               goto init_port_alloc_err;
+
+       rxbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
+       if (!rxbuf)
+               goto init_port_free_txbuf;
+
+       switch (port_type) {
+       case PORT_UNKNOWN:
+               fifosize = 256; /* UART0 */
+               base_baud = 1843200; /* 1.8432MHz */
+               break;
+       case PORT_8250:
+               fifosize = 64; /* UART1~3 */
+               base_baud = 1843200; /* 1.8432MHz */
+               break;
+       default:
+               dev_err(&pdev->dev, "Invalid Port Type(=%d)\n", port_type);
+               goto init_port_hal_free;
+       }
+
+       iobase = pci_resource_start(pdev, 0);
+       mapbase = pci_resource_start(pdev, 1);
+       priv->mapbase = mapbase;
+       priv->iobase = iobase;
+       priv->pdev = pdev;
+       priv->tx_empty = 1;
+       priv->rxbuf.buf = rxbuf;
+       priv->rxbuf.size = PAGE_SIZE;
+
+       priv->fifo_size = fifosize;
+       priv->base_baud = base_baud;
+       priv->port_type = PORT_MAX_8250 + port_type + 1;
+       priv->port.dev = &pdev->dev;
+       priv->port.iobase = iobase;
+       priv->port.membase = NULL;
+       priv->port.mapbase = mapbase;
+       priv->port.irq = pdev->irq;
+       priv->port.iotype = UPIO_PORT;
+       priv->port.ops = &pch_uart_ops;
+       priv->port.flags = UPF_BOOT_AUTOCONF;
+       priv->port.fifosize = fifosize;
+       priv->port.line = num++;
+       priv->trigger = PCH_UART_HAL_TRIGGER_M;
+
+       pci_set_drvdata(pdev, priv);
+       pch_uart_hal_request(pdev, fifosize, base_baud);
+       ret = uart_add_one_port(&pch_uart_driver, &priv->port);
+       if (ret < 0)
+               goto init_port_hal_free;
+
+       return priv;
+
+init_port_hal_free:
+       free_page((unsigned long)rxbuf);
+init_port_free_txbuf:
+       kfree(priv);
+init_port_alloc_err:
+
+       return NULL;
+}
+
+static void pch_uart_exit_port(struct eg20t_port *priv)
+{
+       uart_remove_one_port(&pch_uart_driver, &priv->port);
+       pci_set_drvdata(priv->pdev, NULL);
+       free_page((unsigned long)priv->rxbuf.buf);
+}
+
+static void pch_uart_pci_remove(struct pci_dev *pdev)
+{
+       struct eg20t_port *priv;
+
+       priv = (struct eg20t_port *)pci_get_drvdata(pdev);
+       pch_uart_exit_port(priv);
+       pci_disable_device(pdev);
+       kfree(priv);
+       return;
+}
+#ifdef CONFIG_PM
+static int pch_uart_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct eg20t_port *priv = pci_get_drvdata(pdev);
+
+       uart_suspend_port(&pch_uart_driver, &priv->port);
+
+       pci_save_state(pdev);
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+       return 0;
+}
+
+static int pch_uart_pci_resume(struct pci_dev *pdev)
+{
+       struct eg20t_port *priv = pci_get_drvdata(pdev);
+       int ret;
+
+       pci_set_power_state(pdev, PCI_D0);
+       pci_restore_state(pdev);
+
+       ret = pci_enable_device(pdev);
+       if (ret) {
+               dev_err(&pdev->dev,
+               "%s-pci_enable_device failed(ret=%d) ", __func__, ret);
+               return ret;
+       }
+
+       uart_resume_port(&pch_uart_driver, &priv->port);
+
+       return 0;
+}
+#else
+#define pch_uart_pci_suspend NULL
+#define pch_uart_pci_resume NULL
+#endif
+
+static DEFINE_PCI_DEVICE_TABLE(pch_uart_pci_id) = {
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8811),
+        .driver_data = PCH_UART_8LINE},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8812),
+        .driver_data = PCH_UART_2LINE},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8813),
+        .driver_data = PCH_UART_2LINE},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8814),
+        .driver_data = PCH_UART_2LINE},
+       {0,},
+};
+
+static int __devinit pch_uart_pci_probe(struct pci_dev *pdev,
+                                       const struct pci_device_id *id)
+{
+       int ret;
+       struct eg20t_port *priv;
+
+       ret = pci_enable_device(pdev);
+       if (ret < 0)
+               goto probe_error;
+
+       priv = pch_uart_init_port(pdev, id->driver_data);
+       if (!priv) {
+               ret = -EBUSY;
+               goto probe_disable_device;
+       }
+       pci_set_drvdata(pdev, priv);
+
+       return ret;
+
+probe_disable_device:
+       pci_disable_device(pdev);
+probe_error:
+       return ret;
+}
+
+static struct pci_driver pch_uart_pci_driver = {
+       .name = "pch_uart",
+       .id_table = pch_uart_pci_id,
+       .probe = pch_uart_pci_probe,
+       .remove = __devexit_p(pch_uart_pci_remove),
+       .suspend = pch_uart_pci_suspend,
+       .resume = pch_uart_pci_resume,
+};
+
+static int __init pch_uart_module_init(void)
+{
+       int ret;
+
+       /* register as UART driver */
+       ret = uart_register_driver(&pch_uart_driver);
+       if (ret < 0)
+               return ret;
+
+       /* register as PCI driver */
+       ret = pci_register_driver(&pch_uart_pci_driver);
+       if (ret < 0)
+               uart_unregister_driver(&pch_uart_driver);
+
+       return ret;
+}
+module_init(pch_uart_module_init);
+
+static void __exit pch_uart_module_exit(void)
+{
+       pci_unregister_driver(&pch_uart_pci_driver);
+       uart_unregister_driver(&pch_uart_driver);
+}
+module_exit(pch_uart_module_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel EG20T PCH UART PCI Driver");
+module_param(default_baud, uint, S_IRUGO);
diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c
new file mode 100644 (file)
index 0000000..5b9cde7
--- /dev/null
@@ -0,0 +1,2208 @@
+/*
+ * linux/drivers/serial/pmac_zilog.c
+ * 
+ * Driver for PowerMac Z85c30 based ESCC cell found in the
+ * "macio" ASICs of various PowerMac models
+ * 
+ * Copyright (C) 2003 Ben. Herrenschmidt (benh@kernel.crashing.org)
+ *
+ * Derived from drivers/macintosh/macserial.c by Paul Mackerras
+ * and drivers/serial/sunzilog.c by David S. Miller
+ *
+ * Hrm... actually, I ripped most of sunzilog (Thanks David !) and
+ * adapted special tweaks needed for us. I don't think it's worth
+ * merging back those though. The DMA code still has to get in
+ * and once done, I expect that driver to remain fairly stable in
+ * the long term, unless we change the driver model again...
+ *
+ * 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
+ *
+ * 2004-08-06 Harald Welte <laforge@gnumonks.org>
+ *     - Enable BREAK interrupt
+ *     - Add support for sysreq
+ *
+ * TODO:   - Add DMA support
+ *         - Defer port shutdown to a few seconds after close
+ *         - maybe put something right into uap->clk_divisor
+ */
+
+#undef DEBUG
+#undef DEBUG_HARD
+#undef USE_CTRL_O_SYSRQ
+
+#include <linux/module.h>
+#include <linux/tty.h>
+
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <linux/bitops.h>
+#include <linux/sysrq.h>
+#include <linux/mutex.h>
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#ifdef CONFIG_PPC_PMAC
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/dbdma.h>
+#include <asm/macio.h>
+#else
+#include <linux/platform_device.h>
+#define of_machine_is_compatible(x) (0)
+#endif
+
+#if defined (CONFIG_SERIAL_PMACZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+
+#include "pmac_zilog.h"
+
+/* Not yet implemented */
+#undef HAS_DBDMA
+
+static char version[] __initdata = "pmac_zilog: 0.6 (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("Driver for the Mac and PowerMac serial ports.");
+MODULE_LICENSE("GPL");
+
+#ifdef CONFIG_SERIAL_PMACZILOG_TTYS
+#define PMACZILOG_MAJOR                TTY_MAJOR
+#define PMACZILOG_MINOR                64
+#define PMACZILOG_NAME         "ttyS"
+#else
+#define PMACZILOG_MAJOR                204
+#define PMACZILOG_MINOR                192
+#define PMACZILOG_NAME         "ttyPZ"
+#endif
+
+
+/*
+ * For the sake of early serial console, we can do a pre-probe
+ * (optional) of the ports at rather early boot time.
+ */
+static struct uart_pmac_port   pmz_ports[MAX_ZS_PORTS];
+static int                     pmz_ports_count;
+static DEFINE_MUTEX(pmz_irq_mutex);
+
+static struct uart_driver pmz_uart_reg = {
+       .owner          =       THIS_MODULE,
+       .driver_name    =       PMACZILOG_NAME,
+       .dev_name       =       PMACZILOG_NAME,
+       .major          =       PMACZILOG_MAJOR,
+       .minor          =       PMACZILOG_MINOR,
+};
+
+
+/* 
+ * Load all registers to reprogram the port
+ * This function must only be called when the TX is not busy.  The UART
+ * port lock must be held and local interrupts disabled.
+ */
+static void pmz_load_zsregs(struct uart_pmac_port *uap, u8 *regs)
+{
+       int i;
+
+       if (ZS_IS_ASLEEP(uap))
+               return;
+
+       /* Let pending transmits finish.  */
+       for (i = 0; i < 1000; i++) {
+               unsigned char stat = read_zsreg(uap, R1);
+               if (stat & ALL_SNT)
+                       break;
+               udelay(100);
+       }
+
+       ZS_CLEARERR(uap);
+       zssync(uap);
+       ZS_CLEARFIFO(uap);
+       zssync(uap);
+       ZS_CLEARERR(uap);
+
+       /* Disable all interrupts.  */
+       write_zsreg(uap, R1,
+                   regs[R1] & ~(RxINT_MASK | TxINT_ENAB | EXT_INT_ENAB));
+
+       /* Set parity, sync config, stop bits, and clock divisor.  */
+       write_zsreg(uap, R4, regs[R4]);
+
+       /* Set misc. TX/RX control bits.  */
+       write_zsreg(uap, R10, regs[R10]);
+
+       /* Set TX/RX controls sans the enable bits.  */
+       write_zsreg(uap, R3, regs[R3] & ~RxENABLE);
+       write_zsreg(uap, R5, regs[R5] & ~TxENABLE);
+
+       /* now set R7 "prime" on ESCC */
+       write_zsreg(uap, R15, regs[R15] | EN85C30);
+       write_zsreg(uap, R7, regs[R7P]);
+
+       /* make sure we use R7 "non-prime" on ESCC */
+       write_zsreg(uap, R15, regs[R15] & ~EN85C30);
+
+       /* Synchronous mode config.  */
+       write_zsreg(uap, R6, regs[R6]);
+       write_zsreg(uap, R7, regs[R7]);
+
+       /* Disable baud generator.  */
+       write_zsreg(uap, R14, regs[R14] & ~BRENAB);
+
+       /* Clock mode control.  */
+       write_zsreg(uap, R11, regs[R11]);
+
+       /* Lower and upper byte of baud rate generator divisor.  */
+       write_zsreg(uap, R12, regs[R12]);
+       write_zsreg(uap, R13, regs[R13]);
+       
+       /* Now rewrite R14, with BRENAB (if set).  */
+       write_zsreg(uap, R14, regs[R14]);
+
+       /* Reset external status interrupts.  */
+       write_zsreg(uap, R0, RES_EXT_INT);
+       write_zsreg(uap, R0, RES_EXT_INT);
+
+       /* Rewrite R3/R5, this time without enables masked.  */
+       write_zsreg(uap, R3, regs[R3]);
+       write_zsreg(uap, R5, regs[R5]);
+
+       /* Rewrite R1, this time without IRQ enabled masked.  */
+       write_zsreg(uap, R1, regs[R1]);
+
+       /* Enable interrupts */
+       write_zsreg(uap, R9, regs[R9]);
+}
+
+/* 
+ * We do like sunzilog to avoid disrupting pending Tx
+ * Reprogram the Zilog channel HW registers with the copies found in the
+ * software state struct.  If the transmitter is busy, we defer this update
+ * until the next TX complete interrupt.  Else, we do it right now.
+ *
+ * The UART port lock must be held and local interrupts disabled.
+ */
+static void pmz_maybe_update_regs(struct uart_pmac_port *uap)
+{
+       if (!ZS_REGS_HELD(uap)) {
+               if (ZS_TX_ACTIVE(uap)) {
+                       uap->flags |= PMACZILOG_FLAG_REGS_HELD;
+               } else {
+                       pmz_debug("pmz: maybe_update_regs: updating\n");
+                       pmz_load_zsregs(uap, uap->curregs);
+               }
+       }
+}
+
+static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
+{
+       struct tty_struct *tty = NULL;
+       unsigned char ch, r1, drop, error, flag;
+       int loops = 0;
+
+       /* The interrupt can be enabled when the port isn't open, typically
+        * that happens when using one port is open and the other closed (stale
+        * interrupt) or when one port is used as a console.
+        */
+       if (!ZS_IS_OPEN(uap)) {
+               pmz_debug("pmz: draining input\n");
+               /* Port is closed, drain input data */
+               for (;;) {
+                       if ((++loops) > 1000)
+                               goto flood;
+                       (void)read_zsreg(uap, R1);
+                       write_zsreg(uap, R0, ERR_RES);
+                       (void)read_zsdata(uap);
+                       ch = read_zsreg(uap, R0);
+                       if (!(ch & Rx_CH_AV))
+                               break;
+               }
+               return NULL;
+       }
+
+       /* Sanity check, make sure the old bug is no longer happening */
+       if (uap->port.state == NULL || uap->port.state->port.tty == NULL) {
+               WARN_ON(1);
+               (void)read_zsdata(uap);
+               return NULL;
+       }
+       tty = uap->port.state->port.tty;
+
+       while (1) {
+               error = 0;
+               drop = 0;
+
+               r1 = read_zsreg(uap, R1);
+               ch = read_zsdata(uap);
+
+               if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
+                       write_zsreg(uap, R0, ERR_RES);
+                       zssync(uap);
+               }
+
+               ch &= uap->parity_mask;
+               if (ch == 0 && uap->flags & PMACZILOG_FLAG_BREAK) {
+                       uap->flags &= ~PMACZILOG_FLAG_BREAK;
+               }
+
+#if defined(CONFIG_MAGIC_SYSRQ) && defined(CONFIG_SERIAL_CORE_CONSOLE)
+#ifdef USE_CTRL_O_SYSRQ
+               /* Handle the SysRq ^O Hack */
+               if (ch == '\x0f') {
+                       uap->port.sysrq = jiffies + HZ*5;
+                       goto next_char;
+               }
+#endif /* USE_CTRL_O_SYSRQ */
+               if (uap->port.sysrq) {
+                       int swallow;
+                       spin_unlock(&uap->port.lock);
+                       swallow = uart_handle_sysrq_char(&uap->port, ch);
+                       spin_lock(&uap->port.lock);
+                       if (swallow)
+                               goto next_char;
+               }
+#endif /* CONFIG_MAGIC_SYSRQ && CONFIG_SERIAL_CORE_CONSOLE */
+
+               /* A real serial line, record the character and status.  */
+               if (drop)
+                       goto next_char;
+
+               flag = TTY_NORMAL;
+               uap->port.icount.rx++;
+
+               if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | BRK_ABRT)) {
+                       error = 1;
+                       if (r1 & BRK_ABRT) {
+                               pmz_debug("pmz: got break !\n");
+                               r1 &= ~(PAR_ERR | CRC_ERR);
+                               uap->port.icount.brk++;
+                               if (uart_handle_break(&uap->port))
+                                       goto next_char;
+                       }
+                       else if (r1 & PAR_ERR)
+                               uap->port.icount.parity++;
+                       else if (r1 & CRC_ERR)
+                               uap->port.icount.frame++;
+                       if (r1 & Rx_OVR)
+                               uap->port.icount.overrun++;
+                       r1 &= uap->port.read_status_mask;
+                       if (r1 & BRK_ABRT)
+                               flag = TTY_BREAK;
+                       else if (r1 & PAR_ERR)
+                               flag = TTY_PARITY;
+                       else if (r1 & CRC_ERR)
+                               flag = TTY_FRAME;
+               }
+
+               if (uap->port.ignore_status_mask == 0xff ||
+                   (r1 & uap->port.ignore_status_mask) == 0) {
+                       tty_insert_flip_char(tty, ch, flag);
+               }
+               if (r1 & Rx_OVR)
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+       next_char:
+               /* We can get stuck in an infinite loop getting char 0 when the
+                * line is in a wrong HW state, we break that here.
+                * When that happens, I disable the receive side of the driver.
+                * Note that what I've been experiencing is a real irq loop where
+                * I'm getting flooded regardless of the actual port speed.
+                * Something stange is going on with the HW
+                */
+               if ((++loops) > 1000)
+                       goto flood;
+               ch = read_zsreg(uap, R0);
+               if (!(ch & Rx_CH_AV))
+                       break;
+       }
+
+       return tty;
+ flood:
+       uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
+       write_zsreg(uap, R1, uap->curregs[R1]);
+       zssync(uap);
+       pmz_error("pmz: rx irq flood !\n");
+       return tty;
+}
+
+static void pmz_status_handle(struct uart_pmac_port *uap)
+{
+       unsigned char status;
+
+       status = read_zsreg(uap, R0);
+       write_zsreg(uap, R0, RES_EXT_INT);
+       zssync(uap);
+
+       if (ZS_IS_OPEN(uap) && ZS_WANTS_MODEM_STATUS(uap)) {
+               if (status & SYNC_HUNT)
+                       uap->port.icount.dsr++;
+
+               /* The Zilog just gives us an interrupt when DCD/CTS/etc. change.
+                * But it does not tell us which bit has changed, we have to keep
+                * track of this ourselves.
+                * The CTS input is inverted for some reason.  -- paulus
+                */
+               if ((status ^ uap->prev_status) & DCD)
+                       uart_handle_dcd_change(&uap->port,
+                                              (status & DCD));
+               if ((status ^ uap->prev_status) & CTS)
+                       uart_handle_cts_change(&uap->port,
+                                              !(status & CTS));
+
+               wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
+       }
+
+       if (status & BRK_ABRT)
+               uap->flags |= PMACZILOG_FLAG_BREAK;
+
+       uap->prev_status = status;
+}
+
+static void pmz_transmit_chars(struct uart_pmac_port *uap)
+{
+       struct circ_buf *xmit;
+
+       if (ZS_IS_ASLEEP(uap))
+               return;
+       if (ZS_IS_CONS(uap)) {
+               unsigned char status = read_zsreg(uap, R0);
+
+               /* TX still busy?  Just wait for the next TX done interrupt.
+                *
+                * It can occur because of how we do serial console writes.  It would
+                * be nice to transmit console writes just like we normally would for
+                * a TTY line. (ie. buffered and TX interrupt driven).  That is not
+                * easy because console writes cannot sleep.  One solution might be
+                * to poll on enough port->xmit space becomming free.  -DaveM
+                */
+               if (!(status & Tx_BUF_EMP))
+                       return;
+       }
+
+       uap->flags &= ~PMACZILOG_FLAG_TX_ACTIVE;
+
+       if (ZS_REGS_HELD(uap)) {
+               pmz_load_zsregs(uap, uap->curregs);
+               uap->flags &= ~PMACZILOG_FLAG_REGS_HELD;
+       }
+
+       if (ZS_TX_STOPPED(uap)) {
+               uap->flags &= ~PMACZILOG_FLAG_TX_STOPPED;
+               goto ack_tx_int;
+       }
+
+       /* Under some circumstances, we see interrupts reported for
+        * a closed channel. The interrupt mask in R1 is clear, but
+        * R3 still signals the interrupts and we see them when taking
+        * an interrupt for the other channel (this could be a qemu
+        * bug but since the ESCC doc doesn't specify precsiely whether
+        * R3 interrup status bits are masked by R1 interrupt enable
+        * bits, better safe than sorry). --BenH.
+        */
+       if (!ZS_IS_OPEN(uap))
+               goto ack_tx_int;
+
+       if (uap->port.x_char) {
+               uap->flags |= PMACZILOG_FLAG_TX_ACTIVE;
+               write_zsdata(uap, uap->port.x_char);
+               zssync(uap);
+               uap->port.icount.tx++;
+               uap->port.x_char = 0;
+               return;
+       }
+
+       if (uap->port.state == NULL)
+               goto ack_tx_int;
+       xmit = &uap->port.state->xmit;
+       if (uart_circ_empty(xmit)) {
+               uart_write_wakeup(&uap->port);
+               goto ack_tx_int;
+       }
+       if (uart_tx_stopped(&uap->port))
+               goto ack_tx_int;
+
+       uap->flags |= PMACZILOG_FLAG_TX_ACTIVE;
+       write_zsdata(uap, xmit->buf[xmit->tail]);
+       zssync(uap);
+
+       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+       uap->port.icount.tx++;
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&uap->port);
+
+       return;
+
+ack_tx_int:
+       write_zsreg(uap, R0, RES_Tx_P);
+       zssync(uap);
+}
+
+/* Hrm... we register that twice, fixme later.... */
+static irqreturn_t pmz_interrupt(int irq, void *dev_id)
+{
+       struct uart_pmac_port *uap = dev_id;
+       struct uart_pmac_port *uap_a;
+       struct uart_pmac_port *uap_b;
+       int rc = IRQ_NONE;
+       struct tty_struct *tty;
+       u8 r3;
+
+       uap_a = pmz_get_port_A(uap);
+       uap_b = uap_a->mate;
+
+       spin_lock(&uap_a->port.lock);
+       r3 = read_zsreg(uap_a, R3);
+
+#ifdef DEBUG_HARD
+       pmz_debug("irq, r3: %x\n", r3);
+#endif
+       /* Channel A */
+       tty = NULL;
+       if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
+               write_zsreg(uap_a, R0, RES_H_IUS);
+               zssync(uap_a);          
+               if (r3 & CHAEXT)
+                       pmz_status_handle(uap_a);
+               if (r3 & CHARxIP)
+                       tty = pmz_receive_chars(uap_a);
+               if (r3 & CHATxIP)
+                       pmz_transmit_chars(uap_a);
+               rc = IRQ_HANDLED;
+       }
+       spin_unlock(&uap_a->port.lock);
+       if (tty != NULL)
+               tty_flip_buffer_push(tty);
+
+       if (uap_b->node == NULL)
+               goto out;
+
+       spin_lock(&uap_b->port.lock);
+       tty = NULL;
+       if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
+               write_zsreg(uap_b, R0, RES_H_IUS);
+               zssync(uap_b);
+               if (r3 & CHBEXT)
+                       pmz_status_handle(uap_b);
+               if (r3 & CHBRxIP)
+                       tty = pmz_receive_chars(uap_b);
+               if (r3 & CHBTxIP)
+                       pmz_transmit_chars(uap_b);
+               rc = IRQ_HANDLED;
+       }
+       spin_unlock(&uap_b->port.lock);
+       if (tty != NULL)
+               tty_flip_buffer_push(tty);
+
+ out:
+#ifdef DEBUG_HARD
+       pmz_debug("irq done.\n");
+#endif
+       return rc;
+}
+
+/*
+ * Peek the status register, lock not held by caller
+ */
+static inline u8 pmz_peek_status(struct uart_pmac_port *uap)
+{
+       unsigned long flags;
+       u8 status;
+       
+       spin_lock_irqsave(&uap->port.lock, flags);
+       status = read_zsreg(uap, R0);
+       spin_unlock_irqrestore(&uap->port.lock, flags);
+
+       return status;
+}
+
+/* 
+ * Check if transmitter is empty
+ * The port lock is not held.
+ */
+static unsigned int pmz_tx_empty(struct uart_port *port)
+{
+       struct uart_pmac_port *uap = to_pmz(port);
+       unsigned char status;
+
+       if (ZS_IS_ASLEEP(uap) || uap->node == NULL)
+               return TIOCSER_TEMT;
+
+       status = pmz_peek_status(to_pmz(port));
+       if (status & Tx_BUF_EMP)
+               return TIOCSER_TEMT;
+       return 0;
+}
+
+/* 
+ * Set Modem Control (RTS & DTR) bits
+ * The port lock is held and interrupts are disabled.
+ * Note: Shall we really filter out RTS on external ports or
+ * should that be dealt at higher level only ?
+ */
+static void pmz_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_pmac_port *uap = to_pmz(port);
+       unsigned char set_bits, clear_bits;
+
+        /* Do nothing for irda for now... */
+       if (ZS_IS_IRDA(uap))
+               return;
+       /* We get called during boot with a port not up yet */
+       if (ZS_IS_ASLEEP(uap) ||
+           !(ZS_IS_OPEN(uap) || ZS_IS_CONS(uap)))
+               return;
+
+       set_bits = clear_bits = 0;
+
+       if (ZS_IS_INTMODEM(uap)) {
+               if (mctrl & TIOCM_RTS)
+                       set_bits |= RTS;
+               else
+                       clear_bits |= RTS;
+       }
+       if (mctrl & TIOCM_DTR)
+               set_bits |= DTR;
+       else
+               clear_bits |= DTR;
+
+       /* NOTE: Not subject to 'transmitter active' rule.  */ 
+       uap->curregs[R5] |= set_bits;
+       uap->curregs[R5] &= ~clear_bits;
+       if (ZS_IS_ASLEEP(uap))
+               return;
+       write_zsreg(uap, R5, uap->curregs[R5]);
+       pmz_debug("pmz_set_mctrl: set bits: %x, clear bits: %x -> %x\n",
+                 set_bits, clear_bits, uap->curregs[R5]);
+       zssync(uap);
+}
+
+/* 
+ * Get Modem Control bits (only the input ones, the core will
+ * or that with a cached value of the control ones)
+ * The port lock is held and interrupts are disabled.
+ */
+static unsigned int pmz_get_mctrl(struct uart_port *port)
+{
+       struct uart_pmac_port *uap = to_pmz(port);
+       unsigned char status;
+       unsigned int ret;
+
+       if (ZS_IS_ASLEEP(uap) || uap->node == NULL)
+               return 0;
+
+       status = read_zsreg(uap, R0);
+
+       ret = 0;
+       if (status & DCD)
+               ret |= TIOCM_CAR;
+       if (status & SYNC_HUNT)
+               ret |= TIOCM_DSR;
+       if (!(status & CTS))
+               ret |= TIOCM_CTS;
+
+       return ret;
+}
+
+/* 
+ * Stop TX side. Dealt like sunzilog at next Tx interrupt,
+ * though for DMA, we will have to do a bit more.
+ * The port lock is held and interrupts are disabled.
+ */
+static void pmz_stop_tx(struct uart_port *port)
+{
+       to_pmz(port)->flags |= PMACZILOG_FLAG_TX_STOPPED;
+}
+
+/* 
+ * Kick the Tx side.
+ * The port lock is held and interrupts are disabled.
+ */
+static void pmz_start_tx(struct uart_port *port)
+{
+       struct uart_pmac_port *uap = to_pmz(port);
+       unsigned char status;
+
+       pmz_debug("pmz: start_tx()\n");
+
+       uap->flags |= PMACZILOG_FLAG_TX_ACTIVE;
+       uap->flags &= ~PMACZILOG_FLAG_TX_STOPPED;
+
+       if (ZS_IS_ASLEEP(uap) || uap->node == NULL)
+               return;
+
+       status = read_zsreg(uap, R0);
+
+       /* TX busy?  Just wait for the TX done interrupt.  */
+       if (!(status & Tx_BUF_EMP))
+               return;
+
+       /* Send the first character to jump-start the TX done
+        * IRQ sending engine.
+        */
+       if (port->x_char) {
+               write_zsdata(uap, port->x_char);
+               zssync(uap);
+               port->icount.tx++;
+               port->x_char = 0;
+       } else {
+               struct circ_buf *xmit = &port->state->xmit;
+
+               write_zsdata(uap, xmit->buf[xmit->tail]);
+               zssync(uap);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+
+               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+                       uart_write_wakeup(&uap->port);
+       }
+       pmz_debug("pmz: start_tx() done.\n");
+}
+
+/* 
+ * Stop Rx side, basically disable emitting of
+ * Rx interrupts on the port. We don't disable the rx
+ * side of the chip proper though
+ * The port lock is held.
+ */
+static void pmz_stop_rx(struct uart_port *port)
+{
+       struct uart_pmac_port *uap = to_pmz(port);
+
+       if (ZS_IS_ASLEEP(uap) || uap->node == NULL)
+               return;
+
+       pmz_debug("pmz: stop_rx()()\n");
+
+       /* Disable all RX interrupts.  */
+       uap->curregs[R1] &= ~RxINT_MASK;
+       pmz_maybe_update_regs(uap);
+
+       pmz_debug("pmz: stop_rx() done.\n");
+}
+
+/* 
+ * Enable modem status change interrupts
+ * The port lock is held.
+ */
+static void pmz_enable_ms(struct uart_port *port)
+{
+       struct uart_pmac_port *uap = to_pmz(port);
+       unsigned char new_reg;
+
+       if (ZS_IS_IRDA(uap) || uap->node == NULL)
+               return;
+       new_reg = uap->curregs[R15] | (DCDIE | SYNCIE | CTSIE);
+       if (new_reg != uap->curregs[R15]) {
+               uap->curregs[R15] = new_reg;
+
+               if (ZS_IS_ASLEEP(uap))
+                       return;
+               /* NOTE: Not subject to 'transmitter active' rule. */
+               write_zsreg(uap, R15, uap->curregs[R15]);
+       }
+}
+
+/* 
+ * Control break state emission
+ * The port lock is not held.
+ */
+static void pmz_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_pmac_port *uap = to_pmz(port);
+       unsigned char set_bits, clear_bits, new_reg;
+       unsigned long flags;
+
+       if (uap->node == NULL)
+               return;
+       set_bits = clear_bits = 0;
+
+       if (break_state)
+               set_bits |= SND_BRK;
+       else
+               clear_bits |= SND_BRK;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       new_reg = (uap->curregs[R5] | set_bits) & ~clear_bits;
+       if (new_reg != uap->curregs[R5]) {
+               uap->curregs[R5] = new_reg;
+
+               /* NOTE: Not subject to 'transmitter active' rule. */
+               if (ZS_IS_ASLEEP(uap)) {
+                       spin_unlock_irqrestore(&port->lock, flags);
+                       return;
+               }
+               write_zsreg(uap, R5, uap->curregs[R5]);
+       }
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+#ifdef CONFIG_PPC_PMAC
+
+/*
+ * Turn power on or off to the SCC and associated stuff
+ * (port drivers, modem, IR port, etc.)
+ * Returns the number of milliseconds we should wait before
+ * trying to use the port.
+ */
+static int pmz_set_scc_power(struct uart_pmac_port *uap, int state)
+{
+       int delay = 0;
+       int rc;
+
+       if (state) {
+               rc = pmac_call_feature(
+                       PMAC_FTR_SCC_ENABLE, uap->node, uap->port_type, 1);
+               pmz_debug("port power on result: %d\n", rc);
+               if (ZS_IS_INTMODEM(uap)) {
+                       rc = pmac_call_feature(
+                               PMAC_FTR_MODEM_ENABLE, uap->node, 0, 1);
+                       delay = 2500;   /* wait for 2.5s before using */
+                       pmz_debug("modem power result: %d\n", rc);
+               }
+       } else {
+               /* TODO: Make that depend on a timer, don't power down
+                * immediately
+                */
+               if (ZS_IS_INTMODEM(uap)) {
+                       rc = pmac_call_feature(
+                               PMAC_FTR_MODEM_ENABLE, uap->node, 0, 0);
+                       pmz_debug("port power off result: %d\n", rc);
+               }
+               pmac_call_feature(PMAC_FTR_SCC_ENABLE, uap->node, uap->port_type, 0);
+       }
+       return delay;
+}
+
+#else
+
+static int pmz_set_scc_power(struct uart_pmac_port *uap, int state)
+{
+       return 0;
+}
+
+#endif /* !CONFIG_PPC_PMAC */
+
+/*
+ * FixZeroBug....Works around a bug in the SCC receving channel.
+ * Inspired from Darwin code, 15 Sept. 2000  -DanM
+ *
+ * The following sequence prevents a problem that is seen with O'Hare ASICs
+ * (most versions -- also with some Heathrow and Hydra ASICs) where a zero
+ * at the input to the receiver becomes 'stuck' and locks up the receiver.
+ * This problem can occur as a result of a zero bit at the receiver input
+ * coincident with any of the following events:
+ *
+ *     The SCC is initialized (hardware or software).
+ *     A framing error is detected.
+ *     The clocking option changes from synchronous or X1 asynchronous
+ *             clocking to X16, X32, or X64 asynchronous clocking.
+ *     The decoding mode is changed among NRZ, NRZI, FM0, or FM1.
+ *
+ * This workaround attempts to recover from the lockup condition by placing
+ * the SCC in synchronous loopback mode with a fast clock before programming
+ * any of the asynchronous modes.
+ */
+static void pmz_fix_zero_bug_scc(struct uart_pmac_port *uap)
+{
+       write_zsreg(uap, 9, ZS_IS_CHANNEL_A(uap) ? CHRA : CHRB);
+       zssync(uap);
+       udelay(10);
+       write_zsreg(uap, 9, (ZS_IS_CHANNEL_A(uap) ? CHRA : CHRB) | NV);
+       zssync(uap);
+
+       write_zsreg(uap, 4, X1CLK | MONSYNC);
+       write_zsreg(uap, 3, Rx8);
+       write_zsreg(uap, 5, Tx8 | RTS);
+       write_zsreg(uap, 9, NV);        /* Didn't we already do this? */
+       write_zsreg(uap, 11, RCBR | TCBR);
+       write_zsreg(uap, 12, 0);
+       write_zsreg(uap, 13, 0);
+       write_zsreg(uap, 14, (LOOPBAK | BRSRC));
+       write_zsreg(uap, 14, (LOOPBAK | BRSRC | BRENAB));
+       write_zsreg(uap, 3, Rx8 | RxENABLE);
+       write_zsreg(uap, 0, RES_EXT_INT);
+       write_zsreg(uap, 0, RES_EXT_INT);
+       write_zsreg(uap, 0, RES_EXT_INT);       /* to kill some time */
+
+       /* The channel should be OK now, but it is probably receiving
+        * loopback garbage.
+        * Switch to asynchronous mode, disable the receiver,
+        * and discard everything in the receive buffer.
+        */
+       write_zsreg(uap, 9, NV);
+       write_zsreg(uap, 4, X16CLK | SB_MASK);
+       write_zsreg(uap, 3, Rx8);
+
+       while (read_zsreg(uap, 0) & Rx_CH_AV) {
+               (void)read_zsreg(uap, 8);
+               write_zsreg(uap, 0, RES_EXT_INT);
+               write_zsreg(uap, 0, ERR_RES);
+       }
+}
+
+/*
+ * Real startup routine, powers up the hardware and sets up
+ * the SCC. Returns a delay in ms where you need to wait before
+ * actually using the port, this is typically the internal modem
+ * powerup delay. This routine expect the lock to be taken.
+ */
+static int __pmz_startup(struct uart_pmac_port *uap)
+{
+       int pwr_delay = 0;
+
+       memset(&uap->curregs, 0, sizeof(uap->curregs));
+
+       /* Power up the SCC & underlying hardware (modem/irda) */
+       pwr_delay = pmz_set_scc_power(uap, 1);
+
+       /* Nice buggy HW ... */
+       pmz_fix_zero_bug_scc(uap);
+
+       /* Reset the channel */
+       uap->curregs[R9] = 0;
+       write_zsreg(uap, 9, ZS_IS_CHANNEL_A(uap) ? CHRA : CHRB);
+       zssync(uap);
+       udelay(10);
+       write_zsreg(uap, 9, 0);
+       zssync(uap);
+
+       /* Clear the interrupt registers */
+       write_zsreg(uap, R1, 0);
+       write_zsreg(uap, R0, ERR_RES);
+       write_zsreg(uap, R0, ERR_RES);
+       write_zsreg(uap, R0, RES_H_IUS);
+       write_zsreg(uap, R0, RES_H_IUS);
+
+       /* Setup some valid baud rate */
+       uap->curregs[R4] = X16CLK | SB1;
+       uap->curregs[R3] = Rx8;
+       uap->curregs[R5] = Tx8 | RTS;
+       if (!ZS_IS_IRDA(uap))
+               uap->curregs[R5] |= DTR;
+       uap->curregs[R12] = 0;
+       uap->curregs[R13] = 0;
+       uap->curregs[R14] = BRENAB;
+
+       /* Clear handshaking, enable BREAK interrupts */
+       uap->curregs[R15] = BRKIE;
+
+       /* Master interrupt enable */
+       uap->curregs[R9] |= NV | MIE;
+
+       pmz_load_zsregs(uap, uap->curregs);
+
+       /* Enable receiver and transmitter.  */
+       write_zsreg(uap, R3, uap->curregs[R3] |= RxENABLE);
+       write_zsreg(uap, R5, uap->curregs[R5] |= TxENABLE);
+
+       /* Remember status for DCD/CTS changes */
+       uap->prev_status = read_zsreg(uap, R0);
+
+       return pwr_delay;
+}
+
+static void pmz_irda_reset(struct uart_pmac_port *uap)
+{
+       uap->curregs[R5] |= DTR;
+       write_zsreg(uap, R5, uap->curregs[R5]);
+       zssync(uap);
+       mdelay(110);
+       uap->curregs[R5] &= ~DTR;
+       write_zsreg(uap, R5, uap->curregs[R5]);
+       zssync(uap);
+       mdelay(10);
+}
+
+/*
+ * This is the "normal" startup routine, using the above one
+ * wrapped with the lock and doing a schedule delay
+ */
+static int pmz_startup(struct uart_port *port)
+{
+       struct uart_pmac_port *uap = to_pmz(port);
+       unsigned long flags;
+       int pwr_delay = 0;
+
+       pmz_debug("pmz: startup()\n");
+
+       if (ZS_IS_ASLEEP(uap))
+               return -EAGAIN;
+       if (uap->node == NULL)
+               return -ENODEV;
+
+       mutex_lock(&pmz_irq_mutex);
+
+       uap->flags |= PMACZILOG_FLAG_IS_OPEN;
+
+       /* A console is never powered down. Else, power up and
+        * initialize the chip
+        */
+       if (!ZS_IS_CONS(uap)) {
+               spin_lock_irqsave(&port->lock, flags);
+               pwr_delay = __pmz_startup(uap);
+               spin_unlock_irqrestore(&port->lock, flags);
+       }       
+
+       pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON;
+       if (request_irq(uap->port.irq, pmz_interrupt, IRQF_SHARED,
+                       "SCC", uap)) {
+               pmz_error("Unable to register zs interrupt handler.\n");
+               pmz_set_scc_power(uap, 0);
+               mutex_unlock(&pmz_irq_mutex);
+               return -ENXIO;
+       }
+
+       mutex_unlock(&pmz_irq_mutex);
+
+       /* Right now, we deal with delay by blocking here, I'll be
+        * smarter later on
+        */
+       if (pwr_delay != 0) {
+               pmz_debug("pmz: delaying %d ms\n", pwr_delay);
+               msleep(pwr_delay);
+       }
+
+       /* IrDA reset is done now */
+       if (ZS_IS_IRDA(uap))
+               pmz_irda_reset(uap);
+
+       /* Enable interrupts emission from the chip */
+       spin_lock_irqsave(&port->lock, flags);
+       uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;
+       if (!ZS_IS_EXTCLK(uap))
+               uap->curregs[R1] |= EXT_INT_ENAB;
+       write_zsreg(uap, R1, uap->curregs[R1]);
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       pmz_debug("pmz: startup() done.\n");
+
+       return 0;
+}
+
+static void pmz_shutdown(struct uart_port *port)
+{
+       struct uart_pmac_port *uap = to_pmz(port);
+       unsigned long flags;
+
+       pmz_debug("pmz: shutdown()\n");
+
+       if (uap->node == NULL)
+               return;
+
+       mutex_lock(&pmz_irq_mutex);
+
+       /* Release interrupt handler */
+       free_irq(uap->port.irq, uap);
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       uap->flags &= ~PMACZILOG_FLAG_IS_OPEN;
+
+       if (!ZS_IS_OPEN(uap->mate))
+               pmz_get_port_A(uap)->flags &= ~PMACZILOG_FLAG_IS_IRQ_ON;
+
+       /* Disable interrupts */
+       if (!ZS_IS_ASLEEP(uap)) {
+               uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
+               write_zsreg(uap, R1, uap->curregs[R1]);
+               zssync(uap);
+       }
+
+       if (ZS_IS_CONS(uap) || ZS_IS_ASLEEP(uap)) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               mutex_unlock(&pmz_irq_mutex);
+               return;
+       }
+
+       /* Disable receiver and transmitter.  */
+       uap->curregs[R3] &= ~RxENABLE;
+       uap->curregs[R5] &= ~TxENABLE;
+
+       /* Disable all interrupts and BRK assertion.  */
+       uap->curregs[R5] &= ~SND_BRK;
+       pmz_maybe_update_regs(uap);
+
+       /* Shut the chip down */
+       pmz_set_scc_power(uap, 0);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       mutex_unlock(&pmz_irq_mutex);
+
+       pmz_debug("pmz: shutdown() done.\n");
+}
+
+/* Shared by TTY driver and serial console setup.  The port lock is held
+ * and local interrupts are disabled.
+ */
+static void pmz_convert_to_zs(struct uart_pmac_port *uap, unsigned int cflag,
+                             unsigned int iflag, unsigned long baud)
+{
+       int brg;
+
+       /* Switch to external clocking for IrDA high clock rates. That
+        * code could be re-used for Midi interfaces with different
+        * multipliers
+        */
+       if (baud >= 115200 && ZS_IS_IRDA(uap)) {
+               uap->curregs[R4] = X1CLK;
+               uap->curregs[R11] = RCTRxCP | TCTRxCP;
+               uap->curregs[R14] = 0; /* BRG off */
+               uap->curregs[R12] = 0;
+               uap->curregs[R13] = 0;
+               uap->flags |= PMACZILOG_FLAG_IS_EXTCLK;
+       } else {
+               switch (baud) {
+               case ZS_CLOCK/16:       /* 230400 */
+                       uap->curregs[R4] = X16CLK;
+                       uap->curregs[R11] = 0;
+                       uap->curregs[R14] = 0;
+                       break;
+               case ZS_CLOCK/32:       /* 115200 */
+                       uap->curregs[R4] = X32CLK;
+                       uap->curregs[R11] = 0;
+                       uap->curregs[R14] = 0;
+                       break;
+               default:
+                       uap->curregs[R4] = X16CLK;
+                       uap->curregs[R11] = TCBR | RCBR;
+                       brg = BPS_TO_BRG(baud, ZS_CLOCK / 16);
+                       uap->curregs[R12] = (brg & 255);
+                       uap->curregs[R13] = ((brg >> 8) & 255);
+                       uap->curregs[R14] = BRENAB;
+               }
+               uap->flags &= ~PMACZILOG_FLAG_IS_EXTCLK;
+       }
+
+       /* Character size, stop bits, and parity. */
+       uap->curregs[3] &= ~RxN_MASK;
+       uap->curregs[5] &= ~TxN_MASK;
+
+       switch (cflag & CSIZE) {
+       case CS5:
+               uap->curregs[3] |= Rx5;
+               uap->curregs[5] |= Tx5;
+               uap->parity_mask = 0x1f;
+               break;
+       case CS6:
+               uap->curregs[3] |= Rx6;
+               uap->curregs[5] |= Tx6;
+               uap->parity_mask = 0x3f;
+               break;
+       case CS7:
+               uap->curregs[3] |= Rx7;
+               uap->curregs[5] |= Tx7;
+               uap->parity_mask = 0x7f;
+               break;
+       case CS8:
+       default:
+               uap->curregs[3] |= Rx8;
+               uap->curregs[5] |= Tx8;
+               uap->parity_mask = 0xff;
+               break;
+       };
+       uap->curregs[4] &= ~(SB_MASK);
+       if (cflag & CSTOPB)
+               uap->curregs[4] |= SB2;
+       else
+               uap->curregs[4] |= SB1;
+       if (cflag & PARENB)
+               uap->curregs[4] |= PAR_ENAB;
+       else
+               uap->curregs[4] &= ~PAR_ENAB;
+       if (!(cflag & PARODD))
+               uap->curregs[4] |= PAR_EVEN;
+       else
+               uap->curregs[4] &= ~PAR_EVEN;
+
+       uap->port.read_status_mask = Rx_OVR;
+       if (iflag & INPCK)
+               uap->port.read_status_mask |= CRC_ERR | PAR_ERR;
+       if (iflag & (BRKINT | PARMRK))
+               uap->port.read_status_mask |= BRK_ABRT;
+
+       uap->port.ignore_status_mask = 0;
+       if (iflag & IGNPAR)
+               uap->port.ignore_status_mask |= CRC_ERR | PAR_ERR;
+       if (iflag & IGNBRK) {
+               uap->port.ignore_status_mask |= BRK_ABRT;
+               if (iflag & IGNPAR)
+                       uap->port.ignore_status_mask |= Rx_OVR;
+       }
+
+       if ((cflag & CREAD) == 0)
+               uap->port.ignore_status_mask = 0xff;
+}
+
+
+/*
+ * Set the irda codec on the imac to the specified baud rate.
+ */
+static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud)
+{
+       u8 cmdbyte;
+       int t, version;
+
+       switch (*baud) {
+       /* SIR modes */
+       case 2400:
+               cmdbyte = 0x53;
+               break;
+       case 4800:
+               cmdbyte = 0x52;
+               break;
+       case 9600:
+               cmdbyte = 0x51;
+               break;
+       case 19200:
+               cmdbyte = 0x50;
+               break;
+       case 38400:
+               cmdbyte = 0x4f;
+               break;
+       case 57600:
+               cmdbyte = 0x4e;
+               break;
+       case 115200:
+               cmdbyte = 0x4d;
+               break;
+       /* The FIR modes aren't really supported at this point, how
+        * do we select the speed ? via the FCR on KeyLargo ?
+        */
+       case 1152000:
+               cmdbyte = 0;
+               break;
+       case 4000000:
+               cmdbyte = 0;
+               break;
+       default: /* 9600 */
+               cmdbyte = 0x51;
+               *baud = 9600;
+               break;
+       }
+
+       /* Wait for transmitter to drain */
+       t = 10000;
+       while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0
+              || (read_zsreg(uap, R1) & ALL_SNT) == 0) {
+               if (--t <= 0) {
+                       pmz_error("transmitter didn't drain\n");
+                       return;
+               }
+               udelay(10);
+       }
+
+       /* Drain the receiver too */
+       t = 100;
+       (void)read_zsdata(uap);
+       (void)read_zsdata(uap);
+       (void)read_zsdata(uap);
+       mdelay(10);
+       while (read_zsreg(uap, R0) & Rx_CH_AV) {
+               read_zsdata(uap);
+               mdelay(10);
+               if (--t <= 0) {
+                       pmz_error("receiver didn't drain\n");
+                       return;
+               }
+       }
+
+       /* Switch to command mode */
+       uap->curregs[R5] |= DTR;
+       write_zsreg(uap, R5, uap->curregs[R5]);
+       zssync(uap);
+       mdelay(1);
+
+       /* Switch SCC to 19200 */
+       pmz_convert_to_zs(uap, CS8, 0, 19200);          
+       pmz_load_zsregs(uap, uap->curregs);
+       mdelay(1);
+
+       /* Write get_version command byte */
+       write_zsdata(uap, 1);
+       t = 5000;
+       while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) {
+               if (--t <= 0) {
+                       pmz_error("irda_setup timed out on get_version byte\n");
+                       goto out;
+               }
+               udelay(10);
+       }
+       version = read_zsdata(uap);
+
+       if (version < 4) {
+               pmz_info("IrDA: dongle version %d not supported\n", version);
+               goto out;
+       }
+
+       /* Send speed mode */
+       write_zsdata(uap, cmdbyte);
+       t = 5000;
+       while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) {
+               if (--t <= 0) {
+                       pmz_error("irda_setup timed out on speed mode byte\n");
+                       goto out;
+               }
+               udelay(10);
+       }
+       t = read_zsdata(uap);
+       if (t != cmdbyte)
+               pmz_error("irda_setup speed mode byte = %x (%x)\n", t, cmdbyte);
+
+       pmz_info("IrDA setup for %ld bps, dongle version: %d\n",
+                *baud, version);
+
+       (void)read_zsdata(uap);
+       (void)read_zsdata(uap);
+       (void)read_zsdata(uap);
+
+ out:
+       /* Switch back to data mode */
+       uap->curregs[R5] &= ~DTR;
+       write_zsreg(uap, R5, uap->curregs[R5]);
+       zssync(uap);
+
+       (void)read_zsdata(uap);
+       (void)read_zsdata(uap);
+       (void)read_zsdata(uap);
+}
+
+
+static void __pmz_set_termios(struct uart_port *port, struct ktermios *termios,
+                             struct ktermios *old)
+{
+       struct uart_pmac_port *uap = to_pmz(port);
+       unsigned long baud;
+
+       pmz_debug("pmz: set_termios()\n");
+
+       if (ZS_IS_ASLEEP(uap))
+               return;
+
+       memcpy(&uap->termios_cache, termios, sizeof(struct ktermios));
+
+       /* XXX Check which revs of machines actually allow 1 and 4Mb speeds
+        * on the IR dongle. Note that the IRTTY driver currently doesn't know
+        * about the FIR mode and high speed modes. So these are unused. For
+        * implementing proper support for these, we should probably add some
+        * DMA as well, at least on the Rx side, which isn't a simple thing
+        * at this point.
+        */
+       if (ZS_IS_IRDA(uap)) {
+               /* Calc baud rate */
+               baud = uart_get_baud_rate(port, termios, old, 1200, 4000000);
+               pmz_debug("pmz: switch IRDA to %ld bauds\n", baud);
+               /* Cet the irda codec to the right rate */
+               pmz_irda_setup(uap, &baud);
+               /* Set final baud rate */
+               pmz_convert_to_zs(uap, termios->c_cflag, termios->c_iflag, baud);
+               pmz_load_zsregs(uap, uap->curregs);
+               zssync(uap);
+       } else {
+               baud = uart_get_baud_rate(port, termios, old, 1200, 230400);
+               pmz_convert_to_zs(uap, termios->c_cflag, termios->c_iflag, baud);
+               /* Make sure modem status interrupts are correctly configured */
+               if (UART_ENABLE_MS(&uap->port, termios->c_cflag)) {
+                       uap->curregs[R15] |= DCDIE | SYNCIE | CTSIE;
+                       uap->flags |= PMACZILOG_FLAG_MODEM_STATUS;
+               } else {
+                       uap->curregs[R15] &= ~(DCDIE | SYNCIE | CTSIE);
+                       uap->flags &= ~PMACZILOG_FLAG_MODEM_STATUS;
+               }
+
+               /* Load registers to the chip */
+               pmz_maybe_update_regs(uap);
+       }
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       pmz_debug("pmz: set_termios() done.\n");
+}
+
+/* The port lock is not held.  */
+static void pmz_set_termios(struct uart_port *port, struct ktermios *termios,
+                           struct ktermios *old)
+{
+       struct uart_pmac_port *uap = to_pmz(port);
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);  
+
+       /* Disable IRQs on the port */
+       uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
+       write_zsreg(uap, R1, uap->curregs[R1]);
+
+       /* Setup new port configuration */
+       __pmz_set_termios(port, termios, old);
+
+       /* Re-enable IRQs on the port */
+       if (ZS_IS_OPEN(uap)) {
+               uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;
+               if (!ZS_IS_EXTCLK(uap))
+                       uap->curregs[R1] |= EXT_INT_ENAB;
+               write_zsreg(uap, R1, uap->curregs[R1]);
+       }
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *pmz_type(struct uart_port *port)
+{
+       struct uart_pmac_port *uap = to_pmz(port);
+
+       if (ZS_IS_IRDA(uap))
+               return "Z85c30 ESCC - Infrared port";
+       else if (ZS_IS_INTMODEM(uap))
+               return "Z85c30 ESCC - Internal modem";
+       return "Z85c30 ESCC - Serial port";
+}
+
+/* We do not request/release mappings of the registers here, this
+ * happens at early serial probe time.
+ */
+static void pmz_release_port(struct uart_port *port)
+{
+}
+
+static int pmz_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+/* These do not need to do anything interesting either.  */
+static void pmz_config_port(struct uart_port *port, int flags)
+{
+}
+
+/* We do not support letting the user mess with the divisor, IRQ, etc. */
+static int pmz_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       return -EINVAL;
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+
+static int pmz_poll_get_char(struct uart_port *port)
+{
+       struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
+
+       while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0)
+               udelay(5);
+       return read_zsdata(uap);
+}
+
+static void pmz_poll_put_char(struct uart_port *port, unsigned char c)
+{
+       struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
+
+       /* Wait for the transmit buffer to empty. */
+       while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0)
+               udelay(5);
+       write_zsdata(uap, c);
+}
+
+#endif /* CONFIG_CONSOLE_POLL */
+
+static struct uart_ops pmz_pops = {
+       .tx_empty       =       pmz_tx_empty,
+       .set_mctrl      =       pmz_set_mctrl,
+       .get_mctrl      =       pmz_get_mctrl,
+       .stop_tx        =       pmz_stop_tx,
+       .start_tx       =       pmz_start_tx,
+       .stop_rx        =       pmz_stop_rx,
+       .enable_ms      =       pmz_enable_ms,
+       .break_ctl      =       pmz_break_ctl,
+       .startup        =       pmz_startup,
+       .shutdown       =       pmz_shutdown,
+       .set_termios    =       pmz_set_termios,
+       .type           =       pmz_type,
+       .release_port   =       pmz_release_port,
+       .request_port   =       pmz_request_port,
+       .config_port    =       pmz_config_port,
+       .verify_port    =       pmz_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char  =       pmz_poll_get_char,
+       .poll_put_char  =       pmz_poll_put_char,
+#endif
+};
+
+#ifdef CONFIG_PPC_PMAC
+
+/*
+ * Setup one port structure after probing, HW is down at this point,
+ * Unlike sunzilog, we don't need to pre-init the spinlock as we don't
+ * register our console before uart_add_one_port() is called
+ */
+static int __init pmz_init_port(struct uart_pmac_port *uap)
+{
+       struct device_node *np = uap->node;
+       const char *conn;
+       const struct slot_names_prop {
+               int     count;
+               char    name[1];
+       } *slots;
+       int len;
+       struct resource r_ports, r_rxdma, r_txdma;
+
+       /*
+        * Request & map chip registers
+        */
+       if (of_address_to_resource(np, 0, &r_ports))
+               return -ENODEV;
+       uap->port.mapbase = r_ports.start;
+       uap->port.membase = ioremap(uap->port.mapbase, 0x1000);
+
+       uap->control_reg = uap->port.membase;
+       uap->data_reg = uap->control_reg + 0x10;
+       
+       /*
+        * Request & map DBDMA registers
+        */
+#ifdef HAS_DBDMA
+       if (of_address_to_resource(np, 1, &r_txdma) == 0 &&
+           of_address_to_resource(np, 2, &r_rxdma) == 0)
+               uap->flags |= PMACZILOG_FLAG_HAS_DMA;
+#else
+       memset(&r_txdma, 0, sizeof(struct resource));
+       memset(&r_rxdma, 0, sizeof(struct resource));
+#endif 
+       if (ZS_HAS_DMA(uap)) {
+               uap->tx_dma_regs = ioremap(r_txdma.start, 0x100);
+               if (uap->tx_dma_regs == NULL) { 
+                       uap->flags &= ~PMACZILOG_FLAG_HAS_DMA;
+                       goto no_dma;
+               }
+               uap->rx_dma_regs = ioremap(r_rxdma.start, 0x100);
+               if (uap->rx_dma_regs == NULL) { 
+                       iounmap(uap->tx_dma_regs);
+                       uap->tx_dma_regs = NULL;
+                       uap->flags &= ~PMACZILOG_FLAG_HAS_DMA;
+                       goto no_dma;
+               }
+               uap->tx_dma_irq = irq_of_parse_and_map(np, 1);
+               uap->rx_dma_irq = irq_of_parse_and_map(np, 2);
+       }
+no_dma:
+
+       /*
+        * Detect port type
+        */
+       if (of_device_is_compatible(np, "cobalt"))
+               uap->flags |= PMACZILOG_FLAG_IS_INTMODEM;
+       conn = of_get_property(np, "AAPL,connector", &len);
+       if (conn && (strcmp(conn, "infrared") == 0))
+               uap->flags |= PMACZILOG_FLAG_IS_IRDA;
+       uap->port_type = PMAC_SCC_ASYNC;
+       /* 1999 Powerbook G3 has slot-names property instead */
+       slots = of_get_property(np, "slot-names", &len);
+       if (slots && slots->count > 0) {
+               if (strcmp(slots->name, "IrDA") == 0)
+                       uap->flags |= PMACZILOG_FLAG_IS_IRDA;
+               else if (strcmp(slots->name, "Modem") == 0)
+                       uap->flags |= PMACZILOG_FLAG_IS_INTMODEM;
+       }
+       if (ZS_IS_IRDA(uap))
+               uap->port_type = PMAC_SCC_IRDA;
+       if (ZS_IS_INTMODEM(uap)) {
+               struct device_node* i2c_modem =
+                       of_find_node_by_name(NULL, "i2c-modem");
+               if (i2c_modem) {
+                       const char* mid =
+                               of_get_property(i2c_modem, "modem-id", NULL);
+                       if (mid) switch(*mid) {
+                       case 0x04 :
+                       case 0x05 :
+                       case 0x07 :
+                       case 0x08 :
+                       case 0x0b :
+                       case 0x0c :
+                               uap->port_type = PMAC_SCC_I2S1;
+                       }
+                       printk(KERN_INFO "pmac_zilog: i2c-modem detected, id: %d\n",
+                               mid ? (*mid) : 0);
+                       of_node_put(i2c_modem);
+               } else {
+                       printk(KERN_INFO "pmac_zilog: serial modem detected\n");
+               }
+       }
+
+       /*
+        * Init remaining bits of "port" structure
+        */
+       uap->port.iotype = UPIO_MEM;
+       uap->port.irq = irq_of_parse_and_map(np, 0);
+       uap->port.uartclk = ZS_CLOCK;
+       uap->port.fifosize = 1;
+       uap->port.ops = &pmz_pops;
+       uap->port.type = PORT_PMAC_ZILOG;
+       uap->port.flags = 0;
+
+       /*
+        * Fixup for the port on Gatwick for which the device-tree has
+        * missing interrupts. Normally, the macio_dev would contain
+        * fixed up interrupt info, but we use the device-tree directly
+        * here due to early probing so we need the fixup too.
+        */
+       if (uap->port.irq == NO_IRQ &&
+           np->parent && np->parent->parent &&
+           of_device_is_compatible(np->parent->parent, "gatwick")) {
+               /* IRQs on gatwick are offset by 64 */
+               uap->port.irq = irq_create_mapping(NULL, 64 + 15);
+               uap->tx_dma_irq = irq_create_mapping(NULL, 64 + 4);
+               uap->rx_dma_irq = irq_create_mapping(NULL, 64 + 5);
+       }
+
+       /* Setup some valid baud rate information in the register
+        * shadows so we don't write crap there before baud rate is
+        * first initialized.
+        */
+       pmz_convert_to_zs(uap, CS8, 0, 9600);
+
+       return 0;
+}
+
+/*
+ * Get rid of a port on module removal
+ */
+static void pmz_dispose_port(struct uart_pmac_port *uap)
+{
+       struct device_node *np;
+
+       np = uap->node;
+       iounmap(uap->rx_dma_regs);
+       iounmap(uap->tx_dma_regs);
+       iounmap(uap->control_reg);
+       uap->node = NULL;
+       of_node_put(np);
+       memset(uap, 0, sizeof(struct uart_pmac_port));
+}
+
+/*
+ * Called upon match with an escc node in the device-tree.
+ */
+static int pmz_attach(struct macio_dev *mdev, const struct of_device_id *match)
+{
+       int i;
+       
+       /* Iterate the pmz_ports array to find a matching entry
+        */
+       for (i = 0; i < MAX_ZS_PORTS; i++)
+               if (pmz_ports[i].node == mdev->ofdev.dev.of_node) {
+                       struct uart_pmac_port *uap = &pmz_ports[i];
+
+                       uap->dev = mdev;
+                       dev_set_drvdata(&mdev->ofdev.dev, uap);
+                       if (macio_request_resources(uap->dev, "pmac_zilog"))
+                               printk(KERN_WARNING "%s: Failed to request resource"
+                                      ", port still active\n",
+                                      uap->node->name);
+                       else
+                               uap->flags |= PMACZILOG_FLAG_RSRC_REQUESTED;                            
+                       return 0;
+               }
+       return -ENODEV;
+}
+
+/*
+ * That one should not be called, macio isn't really a hotswap device,
+ * we don't expect one of those serial ports to go away...
+ */
+static int pmz_detach(struct macio_dev *mdev)
+{
+       struct uart_pmac_port   *uap = dev_get_drvdata(&mdev->ofdev.dev);
+       
+       if (!uap)
+               return -ENODEV;
+
+       if (uap->flags & PMACZILOG_FLAG_RSRC_REQUESTED) {
+               macio_release_resources(uap->dev);
+               uap->flags &= ~PMACZILOG_FLAG_RSRC_REQUESTED;
+       }
+       dev_set_drvdata(&mdev->ofdev.dev, NULL);
+       uap->dev = NULL;
+       
+       return 0;
+}
+
+
+static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state)
+{
+       struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev);
+       struct uart_state *state;
+       unsigned long flags;
+
+       if (uap == NULL) {
+               printk("HRM... pmz_suspend with NULL uap\n");
+               return 0;
+       }
+
+       if (pm_state.event == mdev->ofdev.dev.power.power_state.event)
+               return 0;
+
+       pmz_debug("suspend, switching to state %d\n", pm_state.event);
+
+       state = pmz_uart_reg.state + uap->port.line;
+
+       mutex_lock(&pmz_irq_mutex);
+       mutex_lock(&state->port.mutex);
+
+       spin_lock_irqsave(&uap->port.lock, flags);
+
+       if (ZS_IS_OPEN(uap) || ZS_IS_CONS(uap)) {
+               /* Disable receiver and transmitter.  */
+               uap->curregs[R3] &= ~RxENABLE;
+               uap->curregs[R5] &= ~TxENABLE;
+
+               /* Disable all interrupts and BRK assertion.  */
+               uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
+               uap->curregs[R5] &= ~SND_BRK;
+               pmz_load_zsregs(uap, uap->curregs);
+               uap->flags |= PMACZILOG_FLAG_IS_ASLEEP;
+               mb();
+       }
+
+       spin_unlock_irqrestore(&uap->port.lock, flags);
+
+       if (ZS_IS_OPEN(uap) || ZS_IS_OPEN(uap->mate))
+               if (ZS_IS_ASLEEP(uap->mate) && ZS_IS_IRQ_ON(pmz_get_port_A(uap))) {
+                       pmz_get_port_A(uap)->flags &= ~PMACZILOG_FLAG_IS_IRQ_ON;
+                       disable_irq(uap->port.irq);
+               }
+
+       if (ZS_IS_CONS(uap))
+               uap->port.cons->flags &= ~CON_ENABLED;
+
+       /* Shut the chip down */
+       pmz_set_scc_power(uap, 0);
+
+       mutex_unlock(&state->port.mutex);
+       mutex_unlock(&pmz_irq_mutex);
+
+       pmz_debug("suspend, switching complete\n");
+
+       mdev->ofdev.dev.power.power_state = pm_state;
+
+       return 0;
+}
+
+
+static int pmz_resume(struct macio_dev *mdev)
+{
+       struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev);
+       struct uart_state *state;
+       unsigned long flags;
+       int pwr_delay = 0;
+
+       if (uap == NULL)
+               return 0;
+
+       if (mdev->ofdev.dev.power.power_state.event == PM_EVENT_ON)
+               return 0;
+       
+       pmz_debug("resume, switching to state 0\n");
+
+       state = pmz_uart_reg.state + uap->port.line;
+
+       mutex_lock(&pmz_irq_mutex);
+       mutex_lock(&state->port.mutex);
+
+       spin_lock_irqsave(&uap->port.lock, flags);
+       if (!ZS_IS_OPEN(uap) && !ZS_IS_CONS(uap)) {
+               spin_unlock_irqrestore(&uap->port.lock, flags);
+               goto bail;
+       }
+       pwr_delay = __pmz_startup(uap);
+
+       /* Take care of config that may have changed while asleep */
+       __pmz_set_termios(&uap->port, &uap->termios_cache, NULL);
+
+       if (ZS_IS_OPEN(uap)) {
+               /* Enable interrupts */         
+               uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;
+               if (!ZS_IS_EXTCLK(uap))
+                       uap->curregs[R1] |= EXT_INT_ENAB;
+               write_zsreg(uap, R1, uap->curregs[R1]);
+       }
+
+       spin_unlock_irqrestore(&uap->port.lock, flags);
+
+       if (ZS_IS_CONS(uap))
+               uap->port.cons->flags |= CON_ENABLED;
+
+       /* Re-enable IRQ on the controller */
+       if (ZS_IS_OPEN(uap) && !ZS_IS_IRQ_ON(pmz_get_port_A(uap))) {
+               pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON;
+               enable_irq(uap->port.irq);
+       }
+
+ bail:
+       mutex_unlock(&state->port.mutex);
+       mutex_unlock(&pmz_irq_mutex);
+
+       /* Right now, we deal with delay by blocking here, I'll be
+        * smarter later on
+        */
+       if (pwr_delay != 0) {
+               pmz_debug("pmz: delaying %d ms\n", pwr_delay);
+               msleep(pwr_delay);
+       }
+
+       pmz_debug("resume, switching complete\n");
+
+       mdev->ofdev.dev.power.power_state.event = PM_EVENT_ON;
+
+       return 0;
+}
+
+/*
+ * Probe all ports in the system and build the ports array, we register
+ * with the serial layer at this point, the macio-type probing is only
+ * used later to "attach" to the sysfs tree so we get power management
+ * events
+ */
+static int __init pmz_probe(void)
+{
+       struct device_node      *node_p, *node_a, *node_b, *np;
+       int                     count = 0;
+       int                     rc;
+
+       /*
+        * Find all escc chips in the system
+        */
+       node_p = of_find_node_by_name(NULL, "escc");
+       while (node_p) {
+               /*
+                * First get channel A/B node pointers
+                * 
+                * TODO: Add routines with proper locking to do that...
+                */
+               node_a = node_b = NULL;
+               for (np = NULL; (np = of_get_next_child(node_p, np)) != NULL;) {
+                       if (strncmp(np->name, "ch-a", 4) == 0)
+                               node_a = of_node_get(np);
+                       else if (strncmp(np->name, "ch-b", 4) == 0)
+                               node_b = of_node_get(np);
+               }
+               if (!node_a && !node_b) {
+                       of_node_put(node_a);
+                       of_node_put(node_b);
+                       printk(KERN_ERR "pmac_zilog: missing node %c for escc %s\n",
+                               (!node_a) ? 'a' : 'b', node_p->full_name);
+                       goto next;
+               }
+
+               /*
+                * Fill basic fields in the port structures
+                */
+               pmz_ports[count].mate           = &pmz_ports[count+1];
+               pmz_ports[count+1].mate         = &pmz_ports[count];
+               pmz_ports[count].flags          = PMACZILOG_FLAG_IS_CHANNEL_A;
+               pmz_ports[count].node           = node_a;
+               pmz_ports[count+1].node         = node_b;
+               pmz_ports[count].port.line      = count;
+               pmz_ports[count+1].port.line    = count+1;
+
+               /*
+                * Setup the ports for real
+                */
+               rc = pmz_init_port(&pmz_ports[count]);
+               if (rc == 0 && node_b != NULL)
+                       rc = pmz_init_port(&pmz_ports[count+1]);
+               if (rc != 0) {
+                       of_node_put(node_a);
+                       of_node_put(node_b);
+                       memset(&pmz_ports[count], 0, sizeof(struct uart_pmac_port));
+                       memset(&pmz_ports[count+1], 0, sizeof(struct uart_pmac_port));
+                       goto next;
+               }
+               count += 2;
+next:
+               node_p = of_find_node_by_name(node_p, "escc");
+       }
+       pmz_ports_count = count;
+
+       return 0;
+}
+
+#else
+
+extern struct platform_device scc_a_pdev, scc_b_pdev;
+
+static int __init pmz_init_port(struct uart_pmac_port *uap)
+{
+       struct resource *r_ports;
+       int irq;
+
+       r_ports = platform_get_resource(uap->node, IORESOURCE_MEM, 0);
+       irq = platform_get_irq(uap->node, 0);
+       if (!r_ports || !irq)
+               return -ENODEV;
+
+       uap->port.mapbase  = r_ports->start;
+       uap->port.membase  = (unsigned char __iomem *) r_ports->start;
+       uap->port.iotype   = UPIO_MEM;
+       uap->port.irq      = irq;
+       uap->port.uartclk  = ZS_CLOCK;
+       uap->port.fifosize = 1;
+       uap->port.ops      = &pmz_pops;
+       uap->port.type     = PORT_PMAC_ZILOG;
+       uap->port.flags    = 0;
+
+       uap->control_reg   = uap->port.membase;
+       uap->data_reg      = uap->control_reg + 4;
+       uap->port_type     = 0;
+
+       pmz_convert_to_zs(uap, CS8, 0, 9600);
+
+       return 0;
+}
+
+static int __init pmz_probe(void)
+{
+       int err;
+
+       pmz_ports_count = 0;
+
+       pmz_ports[0].mate      = &pmz_ports[1];
+       pmz_ports[0].port.line = 0;
+       pmz_ports[0].flags     = PMACZILOG_FLAG_IS_CHANNEL_A;
+       pmz_ports[0].node      = &scc_a_pdev;
+       err = pmz_init_port(&pmz_ports[0]);
+       if (err)
+               return err;
+       pmz_ports_count++;
+
+       pmz_ports[1].mate      = &pmz_ports[0];
+       pmz_ports[1].port.line = 1;
+       pmz_ports[1].flags     = 0;
+       pmz_ports[1].node      = &scc_b_pdev;
+       err = pmz_init_port(&pmz_ports[1]);
+       if (err)
+               return err;
+       pmz_ports_count++;
+
+       return 0;
+}
+
+static void pmz_dispose_port(struct uart_pmac_port *uap)
+{
+       memset(uap, 0, sizeof(struct uart_pmac_port));
+}
+
+static int __init pmz_attach(struct platform_device *pdev)
+{
+       int i;
+
+       for (i = 0; i < pmz_ports_count; i++)
+               if (pmz_ports[i].node == pdev)
+                       return 0;
+       return -ENODEV;
+}
+
+static int __exit pmz_detach(struct platform_device *pdev)
+{
+       return 0;
+}
+
+#endif /* !CONFIG_PPC_PMAC */
+
+#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
+
+static void pmz_console_write(struct console *con, const char *s, unsigned int count);
+static int __init pmz_console_setup(struct console *co, char *options);
+
+static struct console pmz_console = {
+       .name   =       PMACZILOG_NAME,
+       .write  =       pmz_console_write,
+       .device =       uart_console_device,
+       .setup  =       pmz_console_setup,
+       .flags  =       CON_PRINTBUFFER,
+       .index  =       -1,
+       .data   =       &pmz_uart_reg,
+};
+
+#define PMACZILOG_CONSOLE      &pmz_console
+#else /* CONFIG_SERIAL_PMACZILOG_CONSOLE */
+#define PMACZILOG_CONSOLE      (NULL)
+#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */
+
+/*
+ * Register the driver, console driver and ports with the serial
+ * core
+ */
+static int __init pmz_register(void)
+{
+       int i, rc;
+       
+       pmz_uart_reg.nr = pmz_ports_count;
+       pmz_uart_reg.cons = PMACZILOG_CONSOLE;
+
+       /*
+        * Register this driver with the serial core
+        */
+       rc = uart_register_driver(&pmz_uart_reg);
+       if (rc)
+               return rc;
+
+       /*
+        * Register each port with the serial core
+        */
+       for (i = 0; i < pmz_ports_count; i++) {
+               struct uart_pmac_port *uport = &pmz_ports[i];
+               /* NULL node may happen on wallstreet */
+               if (uport->node != NULL)
+                       rc = uart_add_one_port(&pmz_uart_reg, &uport->port);
+               if (rc)
+                       goto err_out;
+       }
+
+       return 0;
+err_out:
+       while (i-- > 0) {
+               struct uart_pmac_port *uport = &pmz_ports[i];
+               uart_remove_one_port(&pmz_uart_reg, &uport->port);
+       }
+       uart_unregister_driver(&pmz_uart_reg);
+       return rc;
+}
+
+#ifdef CONFIG_PPC_PMAC
+
+static struct of_device_id pmz_match[] = 
+{
+       {
+       .name           = "ch-a",
+       },
+       {
+       .name           = "ch-b",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE (of, pmz_match);
+
+static struct macio_driver pmz_driver = {
+       .driver = {
+               .name           = "pmac_zilog",
+               .owner          = THIS_MODULE,
+               .of_match_table = pmz_match,
+       },
+       .probe          = pmz_attach,
+       .remove         = pmz_detach,
+       .suspend        = pmz_suspend,
+       .resume         = pmz_resume,
+};
+
+#else
+
+static struct platform_driver pmz_driver = {
+       .remove         = __exit_p(pmz_detach),
+       .driver         = {
+               .name           = "scc",
+               .owner          = THIS_MODULE,
+       },
+};
+
+#endif /* !CONFIG_PPC_PMAC */
+
+static int __init init_pmz(void)
+{
+       int rc, i;
+       printk(KERN_INFO "%s\n", version);
+
+       /* 
+        * First, we need to do a direct OF-based probe pass. We
+        * do that because we want serial console up before the
+        * macio stuffs calls us back, and since that makes it
+        * easier to pass the proper number of channels to
+        * uart_register_driver()
+        */
+       if (pmz_ports_count == 0)
+               pmz_probe();
+
+       /*
+        * Bail early if no port found
+        */
+       if (pmz_ports_count == 0)
+               return -ENODEV;
+
+       /*
+        * Now we register with the serial layer
+        */
+       rc = pmz_register();
+       if (rc) {
+               printk(KERN_ERR 
+                       "pmac_zilog: Error registering serial device, disabling pmac_zilog.\n"
+                       "pmac_zilog: Did another serial driver already claim the minors?\n"); 
+               /* effectively "pmz_unprobe()" */
+               for (i=0; i < pmz_ports_count; i++)
+                       pmz_dispose_port(&pmz_ports[i]);
+               return rc;
+       }
+
+       /*
+        * Then we register the macio driver itself
+        */
+#ifdef CONFIG_PPC_PMAC
+       return macio_register_driver(&pmz_driver);
+#else
+       return platform_driver_probe(&pmz_driver, pmz_attach);
+#endif
+}
+
+static void __exit exit_pmz(void)
+{
+       int i;
+
+#ifdef CONFIG_PPC_PMAC
+       /* Get rid of macio-driver (detach from macio) */
+       macio_unregister_driver(&pmz_driver);
+#else
+       platform_driver_unregister(&pmz_driver);
+#endif
+
+       for (i = 0; i < pmz_ports_count; i++) {
+               struct uart_pmac_port *uport = &pmz_ports[i];
+               if (uport->node != NULL) {
+                       uart_remove_one_port(&pmz_uart_reg, &uport->port);
+                       pmz_dispose_port(uport);
+               }
+       }
+       /* Unregister UART driver */
+       uart_unregister_driver(&pmz_uart_reg);
+}
+
+#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
+
+static void pmz_console_putchar(struct uart_port *port, int ch)
+{
+       struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
+
+       /* Wait for the transmit buffer to empty. */
+       while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0)
+               udelay(5);
+       write_zsdata(uap, ch);
+}
+
+/*
+ * Print a string to the serial port trying not to disturb
+ * any possible real use of the port...
+ */
+static void pmz_console_write(struct console *con, const char *s, unsigned int count)
+{
+       struct uart_pmac_port *uap = &pmz_ports[con->index];
+       unsigned long flags;
+
+       if (ZS_IS_ASLEEP(uap))
+               return;
+       spin_lock_irqsave(&uap->port.lock, flags);
+
+       /* Turn of interrupts and enable the transmitter. */
+       write_zsreg(uap, R1, uap->curregs[1] & ~TxINT_ENAB);
+       write_zsreg(uap, R5, uap->curregs[5] | TxENABLE | RTS | DTR);
+
+       uart_console_write(&uap->port, s, count, pmz_console_putchar);
+
+       /* Restore the values in the registers. */
+       write_zsreg(uap, R1, uap->curregs[1]);
+       /* Don't disable the transmitter. */
+
+       spin_unlock_irqrestore(&uap->port.lock, flags);
+}
+
+/*
+ * Setup the serial console
+ */
+static int __init pmz_console_setup(struct console *co, char *options)
+{
+       struct uart_pmac_port *uap;
+       struct uart_port *port;
+       int baud = 38400;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+       unsigned long pwr_delay;
+
+       /*
+        * XServe's default to 57600 bps
+        */
+       if (of_machine_is_compatible("RackMac1,1")
+           || of_machine_is_compatible("RackMac1,2")
+           || of_machine_is_compatible("MacRISC4"))
+               baud = 57600;
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index >= pmz_ports_count)
+               co->index = 0;
+       uap = &pmz_ports[co->index];
+       if (uap->node == NULL)
+               return -ENODEV;
+       port = &uap->port;
+
+       /*
+        * Mark port as beeing a console
+        */
+       uap->flags |= PMACZILOG_FLAG_IS_CONS;
+
+       /*
+        * Temporary fix for uart layer who didn't setup the spinlock yet
+        */
+       spin_lock_init(&port->lock);
+
+       /*
+        * Enable the hardware
+        */
+       pwr_delay = __pmz_startup(uap);
+       if (pwr_delay)
+               mdelay(pwr_delay);
+       
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static int __init pmz_console_init(void)
+{
+       /* Probe ports */
+       pmz_probe();
+
+       /* TODO: Autoprobe console based on OF */
+       /* pmz_console.index = i; */
+       register_console(&pmz_console);
+
+       return 0;
+
+}
+console_initcall(pmz_console_init);
+#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */
+
+module_init(init_pmz);
+module_exit(exit_pmz);
diff --git a/drivers/tty/serial/pmac_zilog.h b/drivers/tty/serial/pmac_zilog.h
new file mode 100644 (file)
index 0000000..cbc34fb
--- /dev/null
@@ -0,0 +1,396 @@
+#ifndef __PMAC_ZILOG_H__
+#define __PMAC_ZILOG_H__
+
+#ifdef CONFIG_PPC_PMAC
+#define pmz_debug(fmt, arg...) dev_dbg(&uap->dev->ofdev.dev, fmt, ## arg)
+#define pmz_error(fmt, arg...) dev_err(&uap->dev->ofdev.dev, fmt, ## arg)
+#define pmz_info(fmt, arg...)  dev_info(&uap->dev->ofdev.dev, fmt, ## arg)
+#else
+#define pmz_debug(fmt, arg...) dev_dbg(&uap->node->dev, fmt, ## arg)
+#define pmz_error(fmt, arg...) dev_err(&uap->node->dev, fmt, ## arg)
+#define pmz_info(fmt, arg...)  dev_info(&uap->node->dev, fmt, ## arg)
+#endif
+
+/*
+ * At most 2 ESCCs with 2 ports each
+ */
+#define MAX_ZS_PORTS   4
+
+/* 
+ * We wrap our port structure around the generic uart_port.
+ */
+#define NUM_ZSREGS    17
+
+struct uart_pmac_port {
+       struct uart_port                port;
+       struct uart_pmac_port           *mate;
+
+#ifdef CONFIG_PPC_PMAC
+       /* macio_dev for the escc holding this port (maybe be null on
+        * early inited port)
+        */
+       struct macio_dev                *dev;
+       /* device node to this port, this points to one of 2 childs
+        * of "escc" node (ie. ch-a or ch-b)
+        */
+       struct device_node              *node;
+#else
+       struct platform_device          *node;
+#endif
+
+       /* Port type as obtained from device tree (IRDA, modem, ...) */
+       int                             port_type;
+       u8                              curregs[NUM_ZSREGS];
+
+       unsigned int                    flags;
+#define PMACZILOG_FLAG_IS_CONS         0x00000001
+#define PMACZILOG_FLAG_IS_KGDB         0x00000002
+#define PMACZILOG_FLAG_MODEM_STATUS    0x00000004
+#define PMACZILOG_FLAG_IS_CHANNEL_A    0x00000008
+#define PMACZILOG_FLAG_REGS_HELD       0x00000010
+#define PMACZILOG_FLAG_TX_STOPPED      0x00000020
+#define PMACZILOG_FLAG_TX_ACTIVE       0x00000040
+#define PMACZILOG_FLAG_ENABLED          0x00000080
+#define PMACZILOG_FLAG_IS_IRDA         0x00000100
+#define PMACZILOG_FLAG_IS_INTMODEM     0x00000200
+#define PMACZILOG_FLAG_HAS_DMA         0x00000400
+#define PMACZILOG_FLAG_RSRC_REQUESTED  0x00000800
+#define PMACZILOG_FLAG_IS_ASLEEP       0x00001000
+#define PMACZILOG_FLAG_IS_OPEN         0x00002000
+#define PMACZILOG_FLAG_IS_IRQ_ON       0x00004000
+#define PMACZILOG_FLAG_IS_EXTCLK       0x00008000
+#define PMACZILOG_FLAG_BREAK           0x00010000
+
+       unsigned char                   parity_mask;
+       unsigned char                   prev_status;
+
+       volatile u8                     __iomem *control_reg;
+       volatile u8                     __iomem *data_reg;
+
+#ifdef CONFIG_PPC_PMAC
+       unsigned int                    tx_dma_irq;
+       unsigned int                    rx_dma_irq;
+       volatile struct dbdma_regs      __iomem *tx_dma_regs;
+       volatile struct dbdma_regs      __iomem *rx_dma_regs;
+#endif
+
+       struct ktermios                 termios_cache;
+};
+
+#define to_pmz(p) ((struct uart_pmac_port *)(p))
+
+static inline struct uart_pmac_port *pmz_get_port_A(struct uart_pmac_port *uap)
+{
+       if (uap->flags & PMACZILOG_FLAG_IS_CHANNEL_A)
+               return uap;
+       return uap->mate;
+}
+
+/*
+ * Register accessors. Note that we don't need to enforce a recovery
+ * delay on PCI PowerMac hardware, it's dealt in HW by the MacIO chip,
+ * though if we try to use this driver on older machines, we might have
+ * to add it back
+ */
+static inline u8 read_zsreg(struct uart_pmac_port *port, u8 reg)
+{
+       if (reg != 0)
+               writeb(reg, port->control_reg);
+       return readb(port->control_reg);
+}
+
+static inline void write_zsreg(struct uart_pmac_port *port, u8 reg, u8 value)
+{
+       if (reg != 0)
+               writeb(reg, port->control_reg);
+       writeb(value, port->control_reg);
+}
+
+static inline u8 read_zsdata(struct uart_pmac_port *port)
+{
+       return readb(port->data_reg);
+}
+
+static inline void write_zsdata(struct uart_pmac_port *port, u8 data)
+{
+       writeb(data, port->data_reg);
+}
+
+static inline void zssync(struct uart_pmac_port *port)
+{
+       (void)readb(port->control_reg);
+}
+
+/* Conversion routines to/from brg time constants from/to bits
+ * per second.
+ */
+#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+#define ZS_CLOCK         3686400       /* Z8530 RTxC input clock rate */
+
+/* The Zilog register set */
+
+#define        FLAG    0x7e
+
+/* Write Register 0 */
+#define        R0      0               /* Register selects */
+#define        R1      1
+#define        R2      2
+#define        R3      3
+#define        R4      4
+#define        R5      5
+#define        R6      6
+#define        R7      7
+#define        R8      8
+#define        R9      9
+#define        R10     10
+#define        R11     11
+#define        R12     12
+#define        R13     13
+#define        R14     14
+#define        R15     15
+#define        R7P     16
+
+#define        NULLCODE        0       /* Null Code */
+#define        POINT_HIGH      0x8     /* Select upper half of registers */
+#define        RES_EXT_INT     0x10    /* Reset Ext. Status Interrupts */
+#define        SEND_ABORT      0x18    /* HDLC Abort */
+#define        RES_RxINT_FC    0x20    /* Reset RxINT on First Character */
+#define        RES_Tx_P        0x28    /* Reset TxINT Pending */
+#define        ERR_RES         0x30    /* Error Reset */
+#define        RES_H_IUS       0x38    /* Reset highest IUS */
+
+#define        RES_Rx_CRC      0x40    /* Reset Rx CRC Checker */
+#define        RES_Tx_CRC      0x80    /* Reset Tx CRC Checker */
+#define        RES_EOM_L       0xC0    /* Reset EOM latch */
+
+/* Write Register 1 */
+
+#define        EXT_INT_ENAB    0x1     /* Ext Int Enable */
+#define        TxINT_ENAB      0x2     /* Tx Int Enable */
+#define        PAR_SPEC        0x4     /* Parity is special condition */
+
+#define        RxINT_DISAB     0       /* Rx Int Disable */
+#define        RxINT_FCERR     0x8     /* Rx Int on First Character Only or Error */
+#define        INT_ALL_Rx      0x10    /* Int on all Rx Characters or error */
+#define        INT_ERR_Rx      0x18    /* Int on error only */
+#define RxINT_MASK     0x18
+
+#define        WT_RDY_RT       0x20    /* W/Req reflects recv if 1, xmit if 0 */
+#define        WT_FN_RDYFN     0x40    /* W/Req pin is DMA request if 1, wait if 0 */
+#define        WT_RDY_ENAB     0x80    /* Enable W/Req pin */
+
+/* Write Register #2 (Interrupt Vector) */
+
+/* Write Register 3 */
+
+#define        RxENABLE        0x1     /* Rx Enable */
+#define        SYNC_L_INH      0x2     /* Sync Character Load Inhibit */
+#define        ADD_SM          0x4     /* Address Search Mode (SDLC) */
+#define        RxCRC_ENAB      0x8     /* Rx CRC Enable */
+#define        ENT_HM          0x10    /* Enter Hunt Mode */
+#define        AUTO_ENAB       0x20    /* Auto Enables */
+#define        Rx5             0x0     /* Rx 5 Bits/Character */
+#define        Rx7             0x40    /* Rx 7 Bits/Character */
+#define        Rx6             0x80    /* Rx 6 Bits/Character */
+#define        Rx8             0xc0    /* Rx 8 Bits/Character */
+#define RxN_MASK       0xc0
+
+/* Write Register 4 */
+
+#define        PAR_ENAB        0x1     /* Parity Enable */
+#define        PAR_EVEN        0x2     /* Parity Even/Odd* */
+
+#define        SYNC_ENAB       0       /* Sync Modes Enable */
+#define        SB1             0x4     /* 1 stop bit/char */
+#define        SB15            0x8     /* 1.5 stop bits/char */
+#define        SB2             0xc     /* 2 stop bits/char */
+#define SB_MASK                0xc
+
+#define        MONSYNC         0       /* 8 Bit Sync character */
+#define        BISYNC          0x10    /* 16 bit sync character */
+#define        SDLC            0x20    /* SDLC Mode (01111110 Sync Flag) */
+#define        EXTSYNC         0x30    /* External Sync Mode */
+
+#define        X1CLK           0x0     /* x1 clock mode */
+#define        X16CLK          0x40    /* x16 clock mode */
+#define        X32CLK          0x80    /* x32 clock mode */
+#define        X64CLK          0xC0    /* x64 clock mode */
+#define XCLK_MASK      0xC0
+
+/* Write Register 5 */
+
+#define        TxCRC_ENAB      0x1     /* Tx CRC Enable */
+#define        RTS             0x2     /* RTS */
+#define        SDLC_CRC        0x4     /* SDLC/CRC-16 */
+#define        TxENABLE        0x8     /* Tx Enable */
+#define        SND_BRK         0x10    /* Send Break */
+#define        Tx5             0x0     /* Tx 5 bits (or less)/character */
+#define        Tx7             0x20    /* Tx 7 bits/character */
+#define        Tx6             0x40    /* Tx 6 bits/character */
+#define        Tx8             0x60    /* Tx 8 bits/character */
+#define TxN_MASK       0x60
+#define        DTR             0x80    /* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 7' (Some enhanced feature control) */
+#define        ENEXREAD        0x40    /* Enable read of some write registers */
+
+/* Write Register 8 (transmit buffer) */
+
+/* Write Register 9 (Master interrupt control) */
+#define        VIS     1       /* Vector Includes Status */
+#define        NV      2       /* No Vector */
+#define        DLC     4       /* Disable Lower Chain */
+#define        MIE     8       /* Master Interrupt Enable */
+#define        STATHI  0x10    /* Status high */
+#define        NORESET 0       /* No reset on write to R9 */
+#define        CHRB    0x40    /* Reset channel B */
+#define        CHRA    0x80    /* Reset channel A */
+#define        FHWRES  0xc0    /* Force hardware reset */
+
+/* Write Register 10 (misc control bits) */
+#define        BIT6    1       /* 6 bit/8bit sync */
+#define        LOOPMODE 2      /* SDLC Loop mode */
+#define        ABUNDER 4       /* Abort/flag on SDLC xmit underrun */
+#define        MARKIDLE 8      /* Mark/flag on idle */
+#define        GAOP    0x10    /* Go active on poll */
+#define        NRZ     0       /* NRZ mode */
+#define        NRZI    0x20    /* NRZI mode */
+#define        FM1     0x40    /* FM1 (transition = 1) */
+#define        FM0     0x60    /* FM0 (transition = 0) */
+#define        CRCPS   0x80    /* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode control) */
+#define        TRxCXT  0       /* TRxC = Xtal output */
+#define        TRxCTC  1       /* TRxC = Transmit clock */
+#define        TRxCBR  2       /* TRxC = BR Generator Output */
+#define        TRxCDP  3       /* TRxC = DPLL output */
+#define        TRxCOI  4       /* TRxC O/I */
+#define        TCRTxCP 0       /* Transmit clock = RTxC pin */
+#define        TCTRxCP 8       /* Transmit clock = TRxC pin */
+#define        TCBR    0x10    /* Transmit clock = BR Generator output */
+#define        TCDPLL  0x18    /* Transmit clock = DPLL output */
+#define        RCRTxCP 0       /* Receive clock = RTxC pin */
+#define        RCTRxCP 0x20    /* Receive clock = TRxC pin */
+#define        RCBR    0x40    /* Receive clock = BR Generator output */
+#define        RCDPLL  0x60    /* Receive clock = DPLL output */
+#define        RTxCX   0x80    /* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (lower byte of baud rate generator time constant) */
+
+/* Write Register 13 (upper byte of baud rate generator time constant) */
+
+/* Write Register 14 (Misc control bits) */
+#define        BRENAB  1       /* Baud rate generator enable */
+#define        BRSRC   2       /* Baud rate generator source */
+#define        DTRREQ  4       /* DTR/Request function */
+#define        AUTOECHO 8      /* Auto Echo */
+#define        LOOPBAK 0x10    /* Local loopback */
+#define        SEARCH  0x20    /* Enter search mode */
+#define        RMC     0x40    /* Reset missing clock */
+#define        DISDPLL 0x60    /* Disable DPLL */
+#define        SSBR    0x80    /* Set DPLL source = BR generator */
+#define        SSRTxC  0xa0    /* Set DPLL source = RTxC */
+#define        SFMM    0xc0    /* Set FM mode */
+#define        SNRZI   0xe0    /* Set NRZI mode */
+
+/* Write Register 15 (external/status interrupt control) */
+#define        EN85C30 1       /* Enable some 85c30-enhanced registers */
+#define        ZCIE    2       /* Zero count IE */
+#define        ENSTFIFO 4      /* Enable status FIFO (SDLC) */
+#define        DCDIE   8       /* DCD IE */
+#define        SYNCIE  0x10    /* Sync/hunt IE */
+#define        CTSIE   0x20    /* CTS IE */
+#define        TxUIE   0x40    /* Tx Underrun/EOM IE */
+#define        BRKIE   0x80    /* Break/Abort IE */
+
+
+/* Read Register 0 */
+#define        Rx_CH_AV        0x1     /* Rx Character Available */
+#define        ZCOUNT          0x2     /* Zero count */
+#define        Tx_BUF_EMP      0x4     /* Tx Buffer empty */
+#define        DCD             0x8     /* DCD */
+#define        SYNC_HUNT       0x10    /* Sync/hunt */
+#define        CTS             0x20    /* CTS */
+#define        TxEOM           0x40    /* Tx underrun */
+#define        BRK_ABRT        0x80    /* Break/Abort */
+
+/* Read Register 1 */
+#define        ALL_SNT         0x1     /* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define        RES3            0x8     /* 0/3 */
+#define        RES4            0x4     /* 0/4 */
+#define        RES5            0xc     /* 0/5 */
+#define        RES6            0x2     /* 0/6 */
+#define        RES7            0xa     /* 0/7 */
+#define        RES8            0x6     /* 0/8 */
+#define        RES18           0xe     /* 1/8 */
+#define        RES28           0x0     /* 2/8 */
+/* Special Rx Condition Interrupts */
+#define        PAR_ERR         0x10    /* Parity error */
+#define        Rx_OVR          0x20    /* Rx Overrun Error */
+#define        CRC_ERR         0x40    /* CRC/Framing Error */
+#define        END_FR          0x80    /* End of Frame (SDLC) */
+
+/* Read Register 2 (channel b only) - Interrupt vector */
+#define        CHB_Tx_EMPTY    0x00
+#define        CHB_EXT_STAT    0x02
+#define        CHB_Rx_AVAIL    0x04
+#define        CHB_SPECIAL     0x06
+#define        CHA_Tx_EMPTY    0x08
+#define        CHA_EXT_STAT    0x0a
+#define        CHA_Rx_AVAIL    0x0c
+#define        CHA_SPECIAL     0x0e
+#define        STATUS_MASK     0x06
+
+/* Read Register 3 (interrupt pending register) ch a only */
+#define        CHBEXT  0x1             /* Channel B Ext/Stat IP */
+#define        CHBTxIP 0x2             /* Channel B Tx IP */
+#define        CHBRxIP 0x4             /* Channel B Rx IP */
+#define        CHAEXT  0x8             /* Channel A Ext/Stat IP */
+#define        CHATxIP 0x10            /* Channel A Tx IP */
+#define        CHARxIP 0x20            /* Channel A Rx IP */
+
+/* Read Register 8 (receive data register) */
+
+/* Read Register 10  (misc status bits) */
+#define        ONLOOP  2               /* On loop */
+#define        LOOPSEND 0x10           /* Loop sending */
+#define        CLK2MIS 0x40            /* Two clocks missing */
+#define        CLK1MIS 0x80            /* One clock missing */
+
+/* Read Register 12 (lower byte of baud rate generator constant) */
+
+/* Read Register 13 (upper byte of baud rate generator constant) */
+
+/* Read Register 15 (value of WR 15) */
+
+/* Misc macros */
+#define ZS_CLEARERR(port)    (write_zsreg(port, 0, ERR_RES))
+#define ZS_CLEARFIFO(port)   do { volatile unsigned char garbage; \
+                                    garbage = read_zsdata(port); \
+                                    garbage = read_zsdata(port); \
+                                    garbage = read_zsdata(port); \
+                               } while(0)
+
+#define ZS_IS_CONS(UP)                 ((UP)->flags & PMACZILOG_FLAG_IS_CONS)
+#define ZS_IS_KGDB(UP)                 ((UP)->flags & PMACZILOG_FLAG_IS_KGDB)
+#define ZS_IS_CHANNEL_A(UP)            ((UP)->flags & PMACZILOG_FLAG_IS_CHANNEL_A)
+#define ZS_REGS_HELD(UP)               ((UP)->flags & PMACZILOG_FLAG_REGS_HELD)
+#define ZS_TX_STOPPED(UP)              ((UP)->flags & PMACZILOG_FLAG_TX_STOPPED)
+#define ZS_TX_ACTIVE(UP)               ((UP)->flags & PMACZILOG_FLAG_TX_ACTIVE)
+#define ZS_WANTS_MODEM_STATUS(UP)      ((UP)->flags & PMACZILOG_FLAG_MODEM_STATUS)
+#define ZS_IS_IRDA(UP)                 ((UP)->flags & PMACZILOG_FLAG_IS_IRDA)
+#define ZS_IS_INTMODEM(UP)             ((UP)->flags & PMACZILOG_FLAG_IS_INTMODEM)
+#define ZS_HAS_DMA(UP)                 ((UP)->flags & PMACZILOG_FLAG_HAS_DMA)
+#define ZS_IS_ASLEEP(UP)               ((UP)->flags & PMACZILOG_FLAG_IS_ASLEEP)
+#define ZS_IS_OPEN(UP)                 ((UP)->flags & PMACZILOG_FLAG_IS_OPEN)
+#define ZS_IS_IRQ_ON(UP)               ((UP)->flags & PMACZILOG_FLAG_IS_IRQ_ON)
+#define ZS_IS_EXTCLK(UP)               ((UP)->flags & PMACZILOG_FLAG_IS_EXTCLK)
+
+#endif /* __PMAC_ZILOG_H__ */
diff --git a/drivers/tty/serial/pnx8xxx_uart.c b/drivers/tty/serial/pnx8xxx_uart.c
new file mode 100644 (file)
index 0000000..0aa75a9
--- /dev/null
@@ -0,0 +1,854 @@
+/*
+ * UART driver for PNX8XXX SoCs
+ *
+ * Author: Per Hallsmark per.hallsmark@mvista.com
+ * Ported to 2.6 kernel by EmbeddedAlley
+ * Reworked by Vitaly Wool <vitalywool@gmail.com>
+ *
+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ * Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of
+ * any kind, whether express or implied.
+ *
+ */
+
+#if defined(CONFIG_SERIAL_PNX8XXX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/serial_pnx8xxx.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+/* We'll be using StrongARM sa1100 serial port major/minor */
+#define SERIAL_PNX8XXX_MAJOR   204
+#define MINOR_START            5
+
+#define NR_PORTS               2
+
+#define PNX8XXX_ISR_PASS_LIMIT 256
+
+/*
+ * Convert from ignore_status_mask or read_status_mask to FIFO
+ * and interrupt status bits
+ */
+#define SM_TO_FIFO(x)  ((x) >> 10)
+#define SM_TO_ISTAT(x) ((x) & 0x000001ff)
+#define FIFO_TO_SM(x)  ((x) << 10)
+#define ISTAT_TO_SM(x) ((x) & 0x000001ff)
+
+/*
+ * This is the size of our serial port register set.
+ */
+#define UART_PORT_SIZE 0x1000
+
+/*
+ * This determines how often we check the modem status signals
+ * for any change.  They generally aren't connected to an IRQ
+ * so we have to poll them.  We also check immediately before
+ * filling the TX fifo incase CTS has been dropped.
+ */
+#define MCTRL_TIMEOUT  (250*HZ/1000)
+
+extern struct pnx8xxx_port pnx8xxx_ports[];
+
+static inline int serial_in(struct pnx8xxx_port *sport, int offset)
+{
+       return (__raw_readl(sport->port.membase + offset));
+}
+
+static inline void serial_out(struct pnx8xxx_port *sport, int offset, int value)
+{
+       __raw_writel(value, sport->port.membase + offset);
+}
+
+/*
+ * Handle any change of modem status signal since we were last called.
+ */
+static void pnx8xxx_mctrl_check(struct pnx8xxx_port *sport)
+{
+       unsigned int status, changed;
+
+       status = sport->port.ops->get_mctrl(&sport->port);
+       changed = status ^ sport->old_status;
+
+       if (changed == 0)
+               return;
+
+       sport->old_status = status;
+
+       if (changed & TIOCM_RI)
+               sport->port.icount.rng++;
+       if (changed & TIOCM_DSR)
+               sport->port.icount.dsr++;
+       if (changed & TIOCM_CAR)
+               uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
+       if (changed & TIOCM_CTS)
+               uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
+
+       wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
+}
+
+/*
+ * This is our per-port timeout handler, for checking the
+ * modem status signals.
+ */
+static void pnx8xxx_timeout(unsigned long data)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)data;
+       unsigned long flags;
+
+       if (sport->port.state) {
+               spin_lock_irqsave(&sport->port.lock, flags);
+               pnx8xxx_mctrl_check(sport);
+               spin_unlock_irqrestore(&sport->port.lock, flags);
+
+               mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
+       }
+}
+
+/*
+ * interrupts disabled on entry
+ */
+static void pnx8xxx_stop_tx(struct uart_port *port)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+       u32 ien;
+
+       /* Disable TX intr */
+       ien = serial_in(sport, PNX8XXX_IEN);
+       serial_out(sport, PNX8XXX_IEN, ien & ~PNX8XXX_UART_INT_ALLTX);
+
+       /* Clear all pending TX intr */
+       serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLTX);
+}
+
+/*
+ * interrupts may not be disabled on entry
+ */
+static void pnx8xxx_start_tx(struct uart_port *port)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+       u32 ien;
+
+       /* Clear all pending TX intr */
+       serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLTX);
+
+       /* Enable TX intr */
+       ien = serial_in(sport, PNX8XXX_IEN);
+       serial_out(sport, PNX8XXX_IEN, ien | PNX8XXX_UART_INT_ALLTX);
+}
+
+/*
+ * Interrupts enabled
+ */
+static void pnx8xxx_stop_rx(struct uart_port *port)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+       u32 ien;
+
+       /* Disable RX intr */
+       ien = serial_in(sport, PNX8XXX_IEN);
+       serial_out(sport, PNX8XXX_IEN, ien & ~PNX8XXX_UART_INT_ALLRX);
+
+       /* Clear all pending RX intr */
+       serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX);
+}
+
+/*
+ * Set the modem control timer to fire immediately.
+ */
+static void pnx8xxx_enable_ms(struct uart_port *port)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+
+       mod_timer(&sport->timer, jiffies);
+}
+
+static void pnx8xxx_rx_chars(struct pnx8xxx_port *sport)
+{
+       struct tty_struct *tty = sport->port.state->port.tty;
+       unsigned int status, ch, flg;
+
+       status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) |
+                ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT));
+       while (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFIFO)) {
+               ch = serial_in(sport, PNX8XXX_FIFO) & 0xff;
+
+               sport->port.icount.rx++;
+
+               flg = TTY_NORMAL;
+
+               /*
+                * note that the error handling code is
+                * out of the main execution path
+                */
+               if (status & (FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE |
+                                       PNX8XXX_UART_FIFO_RXPAR |
+                                       PNX8XXX_UART_FIFO_RXBRK) |
+                             ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN))) {
+                       if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXBRK)) {
+                               status &= ~(FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) |
+                                       FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR));
+                               sport->port.icount.brk++;
+                               if (uart_handle_break(&sport->port))
+                                       goto ignore_char;
+                       } else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR))
+                               sport->port.icount.parity++;
+                       else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE))
+                               sport->port.icount.frame++;
+                       if (status & ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN))
+                               sport->port.icount.overrun++;
+
+                       status &= sport->port.read_status_mask;
+
+                       if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR))
+                               flg = TTY_PARITY;
+                       else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE))
+                               flg = TTY_FRAME;
+
+#ifdef SUPPORT_SYSRQ
+                       sport->port.sysrq = 0;
+#endif
+               }
+
+               if (uart_handle_sysrq_char(&sport->port, ch))
+                       goto ignore_char;
+
+               uart_insert_char(&sport->port, status,
+                               ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN), ch, flg);
+
+       ignore_char:
+               serial_out(sport, PNX8XXX_LCR, serial_in(sport, PNX8XXX_LCR) |
+                               PNX8XXX_UART_LCR_RX_NEXT);
+               status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) |
+                        ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT));
+       }
+       tty_flip_buffer_push(tty);
+}
+
+static void pnx8xxx_tx_chars(struct pnx8xxx_port *sport)
+{
+       struct circ_buf *xmit = &sport->port.state->xmit;
+
+       if (sport->port.x_char) {
+               serial_out(sport, PNX8XXX_FIFO, sport->port.x_char);
+               sport->port.icount.tx++;
+               sport->port.x_char = 0;
+               return;
+       }
+
+       /*
+        * Check the modem control lines before
+        * transmitting anything.
+        */
+       pnx8xxx_mctrl_check(sport);
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
+               pnx8xxx_stop_tx(&sport->port);
+               return;
+       }
+
+       /*
+        * TX while bytes available
+        */
+       while (((serial_in(sport, PNX8XXX_FIFO) &
+                                       PNX8XXX_UART_FIFO_TXFIFO) >> 16) < 16) {
+               serial_out(sport, PNX8XXX_FIFO, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               sport->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&sport->port);
+
+       if (uart_circ_empty(xmit))
+               pnx8xxx_stop_tx(&sport->port);
+}
+
+static irqreturn_t pnx8xxx_int(int irq, void *dev_id)
+{
+       struct pnx8xxx_port *sport = dev_id;
+       unsigned int status;
+
+       spin_lock(&sport->port.lock);
+       /* Get the interrupts */
+       status  = serial_in(sport, PNX8XXX_ISTAT) & serial_in(sport, PNX8XXX_IEN);
+
+       /* Byte or break signal received */
+       if (status & (PNX8XXX_UART_INT_RX | PNX8XXX_UART_INT_BREAK))
+               pnx8xxx_rx_chars(sport);
+
+       /* TX holding register empty - transmit a byte */
+       if (status & PNX8XXX_UART_INT_TX)
+               pnx8xxx_tx_chars(sport);
+
+       /* Clear the ISTAT register */
+       serial_out(sport, PNX8XXX_ICLR, status);
+
+       spin_unlock(&sport->port.lock);
+       return IRQ_HANDLED;
+}
+
+/*
+ * Return TIOCSER_TEMT when transmitter is not busy.
+ */
+static unsigned int pnx8xxx_tx_empty(struct uart_port *port)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+
+       return serial_in(sport, PNX8XXX_FIFO) & PNX8XXX_UART_FIFO_TXFIFO_STA ? 0 : TIOCSER_TEMT;
+}
+
+static unsigned int pnx8xxx_get_mctrl(struct uart_port *port)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+       unsigned int mctrl = TIOCM_DSR;
+       unsigned int msr;
+
+       /* REVISIT */
+
+       msr = serial_in(sport, PNX8XXX_MCR);
+
+       mctrl |= msr & PNX8XXX_UART_MCR_CTS ? TIOCM_CTS : 0;
+       mctrl |= msr & PNX8XXX_UART_MCR_DCD ? TIOCM_CAR : 0;
+
+       return mctrl;
+}
+
+static void pnx8xxx_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+#if    0       /* FIXME */
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+       unsigned int msr;
+#endif
+}
+
+/*
+ * Interrupts always disabled.
+ */
+static void pnx8xxx_break_ctl(struct uart_port *port, int break_state)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+       unsigned long flags;
+       unsigned int lcr;
+
+       spin_lock_irqsave(&sport->port.lock, flags);
+       lcr = serial_in(sport, PNX8XXX_LCR);
+       if (break_state == -1)
+               lcr |= PNX8XXX_UART_LCR_TXBREAK;
+       else
+               lcr &= ~PNX8XXX_UART_LCR_TXBREAK;
+       serial_out(sport, PNX8XXX_LCR, lcr);
+       spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static int pnx8xxx_startup(struct uart_port *port)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+       int retval;
+
+       /*
+        * Allocate the IRQ
+        */
+       retval = request_irq(sport->port.irq, pnx8xxx_int, 0,
+                            "pnx8xxx-uart", sport);
+       if (retval)
+               return retval;
+
+       /*
+        * Finally, clear and enable interrupts
+        */
+
+       serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX |
+                            PNX8XXX_UART_INT_ALLTX);
+
+       serial_out(sport, PNX8XXX_IEN, serial_in(sport, PNX8XXX_IEN) |
+                           PNX8XXX_UART_INT_ALLRX |
+                           PNX8XXX_UART_INT_ALLTX);
+
+       /*
+        * Enable modem status interrupts
+        */
+       spin_lock_irq(&sport->port.lock);
+       pnx8xxx_enable_ms(&sport->port);
+       spin_unlock_irq(&sport->port.lock);
+
+       return 0;
+}
+
+static void pnx8xxx_shutdown(struct uart_port *port)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+       int lcr;
+
+       /*
+        * Stop our timer.
+        */
+       del_timer_sync(&sport->timer);
+
+       /*
+        * Disable all interrupts
+        */
+       serial_out(sport, PNX8XXX_IEN, 0);
+
+       /*
+        * Reset the Tx and Rx FIFOS, disable the break condition
+        */
+       lcr = serial_in(sport, PNX8XXX_LCR);
+       lcr &= ~PNX8XXX_UART_LCR_TXBREAK;
+       lcr |= PNX8XXX_UART_LCR_TX_RST | PNX8XXX_UART_LCR_RX_RST;
+       serial_out(sport, PNX8XXX_LCR, lcr);
+
+       /*
+        * Clear all interrupts
+        */
+       serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX |
+                            PNX8XXX_UART_INT_ALLTX);
+
+       /*
+        * Free the interrupt
+        */
+       free_irq(sport->port.irq, sport);
+}
+
+static void
+pnx8xxx_set_termios(struct uart_port *port, struct ktermios *termios,
+                  struct ktermios *old)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+       unsigned long flags;
+       unsigned int lcr_fcr, old_ien, baud, quot;
+       unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
+
+       /*
+        * We only support CS7 and CS8.
+        */
+       while ((termios->c_cflag & CSIZE) != CS7 &&
+              (termios->c_cflag & CSIZE) != CS8) {
+               termios->c_cflag &= ~CSIZE;
+               termios->c_cflag |= old_csize;
+               old_csize = CS8;
+       }
+
+       if ((termios->c_cflag & CSIZE) == CS8)
+               lcr_fcr = PNX8XXX_UART_LCR_8BIT;
+       else
+               lcr_fcr = 0;
+
+       if (termios->c_cflag & CSTOPB)
+               lcr_fcr |= PNX8XXX_UART_LCR_2STOPB;
+       if (termios->c_cflag & PARENB) {
+               lcr_fcr |= PNX8XXX_UART_LCR_PAREN;
+               if (!(termios->c_cflag & PARODD))
+                       lcr_fcr |= PNX8XXX_UART_LCR_PAREVN;
+       }
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+       quot = uart_get_divisor(port, baud);
+
+       spin_lock_irqsave(&sport->port.lock, flags);
+
+       sport->port.read_status_mask = ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN) |
+                               ISTAT_TO_SM(PNX8XXX_UART_INT_EMPTY) |
+                               ISTAT_TO_SM(PNX8XXX_UART_INT_RX);
+       if (termios->c_iflag & INPCK)
+               sport->port.read_status_mask |=
+                       FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) |
+                       FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR);
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               sport->port.read_status_mask |=
+                       ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK);
+
+       /*
+        * Characters to ignore
+        */
+       sport->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               sport->port.ignore_status_mask |=
+                       FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) |
+                       FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR);
+       if (termios->c_iflag & IGNBRK) {
+               sport->port.ignore_status_mask |=
+                       ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK);
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       sport->port.ignore_status_mask |=
+                               ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN);
+       }
+
+       /*
+        * ignore all characters if CREAD is not set
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               sport->port.ignore_status_mask |=
+                       ISTAT_TO_SM(PNX8XXX_UART_INT_RX);
+
+       del_timer_sync(&sport->timer);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       /*
+        * disable interrupts and drain transmitter
+        */
+       old_ien = serial_in(sport, PNX8XXX_IEN);
+       serial_out(sport, PNX8XXX_IEN, old_ien & ~(PNX8XXX_UART_INT_ALLTX |
+                                       PNX8XXX_UART_INT_ALLRX));
+
+       while (serial_in(sport, PNX8XXX_FIFO) & PNX8XXX_UART_FIFO_TXFIFO_STA)
+               barrier();
+
+       /* then, disable everything */
+       serial_out(sport, PNX8XXX_IEN, 0);
+
+       /* Reset the Rx and Tx FIFOs too */
+       lcr_fcr |= PNX8XXX_UART_LCR_TX_RST;
+       lcr_fcr |= PNX8XXX_UART_LCR_RX_RST;
+
+       /* set the parity, stop bits and data size */
+       serial_out(sport, PNX8XXX_LCR, lcr_fcr);
+
+       /* set the baud rate */
+       quot -= 1;
+       serial_out(sport, PNX8XXX_BAUD, quot);
+
+       serial_out(sport, PNX8XXX_ICLR, -1);
+
+       serial_out(sport, PNX8XXX_IEN, old_ien);
+
+       if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
+               pnx8xxx_enable_ms(&sport->port);
+
+       spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static const char *pnx8xxx_type(struct uart_port *port)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+
+       return sport->port.type == PORT_PNX8XXX ? "PNX8XXX" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'.
+ */
+static void pnx8xxx_release_port(struct uart_port *port)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+
+       release_mem_region(sport->port.mapbase, UART_PORT_SIZE);
+}
+
+/*
+ * Request the memory region(s) being used by 'port'.
+ */
+static int pnx8xxx_request_port(struct uart_port *port)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+       return request_mem_region(sport->port.mapbase, UART_PORT_SIZE,
+                       "pnx8xxx-uart") != NULL ? 0 : -EBUSY;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void pnx8xxx_config_port(struct uart_port *port, int flags)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+
+       if (flags & UART_CONFIG_TYPE &&
+           pnx8xxx_request_port(&sport->port) == 0)
+               sport->port.type = PORT_PNX8XXX;
+}
+
+/*
+ * Verify the new serial_struct (for TIOCSSERIAL).
+ * The only change we allow are to the flags and type, and
+ * even then only between PORT_PNX8XXX and PORT_UNKNOWN
+ */
+static int
+pnx8xxx_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+       int ret = 0;
+
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_PNX8XXX)
+               ret = -EINVAL;
+       if (sport->port.irq != ser->irq)
+               ret = -EINVAL;
+       if (ser->io_type != SERIAL_IO_MEM)
+               ret = -EINVAL;
+       if (sport->port.uartclk / 16 != ser->baud_base)
+               ret = -EINVAL;
+       if ((void *)sport->port.mapbase != ser->iomem_base)
+               ret = -EINVAL;
+       if (sport->port.iobase != ser->port)
+               ret = -EINVAL;
+       if (ser->hub6 != 0)
+               ret = -EINVAL;
+       return ret;
+}
+
+static struct uart_ops pnx8xxx_pops = {
+       .tx_empty       = pnx8xxx_tx_empty,
+       .set_mctrl      = pnx8xxx_set_mctrl,
+       .get_mctrl      = pnx8xxx_get_mctrl,
+       .stop_tx        = pnx8xxx_stop_tx,
+       .start_tx       = pnx8xxx_start_tx,
+       .stop_rx        = pnx8xxx_stop_rx,
+       .enable_ms      = pnx8xxx_enable_ms,
+       .break_ctl      = pnx8xxx_break_ctl,
+       .startup        = pnx8xxx_startup,
+       .shutdown       = pnx8xxx_shutdown,
+       .set_termios    = pnx8xxx_set_termios,
+       .type           = pnx8xxx_type,
+       .release_port   = pnx8xxx_release_port,
+       .request_port   = pnx8xxx_request_port,
+       .config_port    = pnx8xxx_config_port,
+       .verify_port    = pnx8xxx_verify_port,
+};
+
+
+/*
+ * Setup the PNX8XXX serial ports.
+ *
+ * Note also that we support "console=ttySx" where "x" is either 0 or 1.
+ */
+static void __init pnx8xxx_init_ports(void)
+{
+       static int first = 1;
+       int i;
+
+       if (!first)
+               return;
+       first = 0;
+
+       for (i = 0; i < NR_PORTS; i++) {
+               init_timer(&pnx8xxx_ports[i].timer);
+               pnx8xxx_ports[i].timer.function = pnx8xxx_timeout;
+               pnx8xxx_ports[i].timer.data     = (unsigned long)&pnx8xxx_ports[i];
+               pnx8xxx_ports[i].port.ops = &pnx8xxx_pops;
+       }
+}
+
+#ifdef CONFIG_SERIAL_PNX8XXX_CONSOLE
+
+static void pnx8xxx_console_putchar(struct uart_port *port, int ch)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+       int status;
+
+       do {
+               /* Wait for UART_TX register to empty */
+               status = serial_in(sport, PNX8XXX_FIFO);
+       } while (status & PNX8XXX_UART_FIFO_TXFIFO);
+       serial_out(sport, PNX8XXX_FIFO, ch);
+}
+
+/*
+ * Interrupts are disabled on entering
+ */static void
+pnx8xxx_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct pnx8xxx_port *sport = &pnx8xxx_ports[co->index];
+       unsigned int old_ien, status;
+
+       /*
+        *      First, save IEN and then disable interrupts
+        */
+       old_ien = serial_in(sport, PNX8XXX_IEN);
+       serial_out(sport, PNX8XXX_IEN, old_ien & ~(PNX8XXX_UART_INT_ALLTX |
+                                       PNX8XXX_UART_INT_ALLRX));
+
+       uart_console_write(&sport->port, s, count, pnx8xxx_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore IEN
+        */
+       do {
+               /* Wait for UART_TX register to empty */
+               status = serial_in(sport, PNX8XXX_FIFO);
+       } while (status & PNX8XXX_UART_FIFO_TXFIFO);
+
+       /* Clear TX and EMPTY interrupt */
+       serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_TX |
+                            PNX8XXX_UART_INT_EMPTY);
+
+       serial_out(sport, PNX8XXX_IEN, old_ien);
+}
+
+static int __init
+pnx8xxx_console_setup(struct console *co, char *options)
+{
+       struct pnx8xxx_port *sport;
+       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.
+        */
+       if (co->index == -1 || co->index >= NR_PORTS)
+               co->index = 0;
+       sport = &pnx8xxx_ports[co->index];
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(&sport->port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver pnx8xxx_reg;
+static struct console pnx8xxx_console = {
+       .name           = "ttyS",
+       .write          = pnx8xxx_console_write,
+       .device         = uart_console_device,
+       .setup          = pnx8xxx_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &pnx8xxx_reg,
+};
+
+static int __init pnx8xxx_rs_console_init(void)
+{
+       pnx8xxx_init_ports();
+       register_console(&pnx8xxx_console);
+       return 0;
+}
+console_initcall(pnx8xxx_rs_console_init);
+
+#define PNX8XXX_CONSOLE        &pnx8xxx_console
+#else
+#define PNX8XXX_CONSOLE        NULL
+#endif
+
+static struct uart_driver pnx8xxx_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "ttyS",
+       .dev_name               = "ttyS",
+       .major                  = SERIAL_PNX8XXX_MAJOR,
+       .minor                  = MINOR_START,
+       .nr                     = NR_PORTS,
+       .cons                   = PNX8XXX_CONSOLE,
+};
+
+static int pnx8xxx_serial_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct pnx8xxx_port *sport = platform_get_drvdata(pdev);
+
+       return uart_suspend_port(&pnx8xxx_reg, &sport->port);
+}
+
+static int pnx8xxx_serial_resume(struct platform_device *pdev)
+{
+       struct pnx8xxx_port *sport = platform_get_drvdata(pdev);
+
+       return uart_resume_port(&pnx8xxx_reg, &sport->port);
+}
+
+static int pnx8xxx_serial_probe(struct platform_device *pdev)
+{
+       struct resource *res = pdev->resource;
+       int i;
+
+       for (i = 0; i < pdev->num_resources; i++, res++) {
+               if (!(res->flags & IORESOURCE_MEM))
+                       continue;
+
+               for (i = 0; i < NR_PORTS; i++) {
+                       if (pnx8xxx_ports[i].port.mapbase != res->start)
+                               continue;
+
+                       pnx8xxx_ports[i].port.dev = &pdev->dev;
+                       uart_add_one_port(&pnx8xxx_reg, &pnx8xxx_ports[i].port);
+                       platform_set_drvdata(pdev, &pnx8xxx_ports[i]);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static int pnx8xxx_serial_remove(struct platform_device *pdev)
+{
+       struct pnx8xxx_port *sport = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+
+       if (sport)
+               uart_remove_one_port(&pnx8xxx_reg, &sport->port);
+
+       return 0;
+}
+
+static struct platform_driver pnx8xxx_serial_driver = {
+       .driver         = {
+               .name   = "pnx8xxx-uart",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = pnx8xxx_serial_probe,
+       .remove         = pnx8xxx_serial_remove,
+       .suspend        = pnx8xxx_serial_suspend,
+       .resume         = pnx8xxx_serial_resume,
+};
+
+static int __init pnx8xxx_serial_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "Serial: PNX8XXX driver\n");
+
+       pnx8xxx_init_ports();
+
+       ret = uart_register_driver(&pnx8xxx_reg);
+       if (ret == 0) {
+               ret = platform_driver_register(&pnx8xxx_serial_driver);
+               if (ret)
+                       uart_unregister_driver(&pnx8xxx_reg);
+       }
+       return ret;
+}
+
+static void __exit pnx8xxx_serial_exit(void)
+{
+       platform_driver_unregister(&pnx8xxx_serial_driver);
+       uart_unregister_driver(&pnx8xxx_reg);
+}
+
+module_init(pnx8xxx_serial_init);
+module_exit(pnx8xxx_serial_exit);
+
+MODULE_AUTHOR("Embedded Alley Solutions, Inc.");
+MODULE_DESCRIPTION("PNX8XXX SoCs serial port driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_PNX8XXX_MAJOR);
+MODULE_ALIAS("platform:pnx8xxx-uart");
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
new file mode 100644 (file)
index 0000000..1102a39
--- /dev/null
@@ -0,0 +1,879 @@
+/*
+ *  linux/drivers/serial/pxa.c
+ *
+ *  Based on drivers/serial/8250.c by Russell King.
+ *
+ *  Author:    Nicolas Pitre
+ *  Created:   Feb 20, 2003
+ *  Copyright: (C) 2003 Monta Vista Software, Inc.
+ *
+ * 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.
+ *
+ * Note 1: This driver is made separate from the already too overloaded
+ * 8250.c because it needs some kirks of its own and that'll make it
+ * easier to add DMA support.
+ *
+ * Note 2: I'm too sick of device allocation policies for serial ports.
+ * If someone else wants to request an "official" allocation of major/minor
+ * for this driver please be my guest.  And don't forget that new hardware
+ * to come from Intel might have more than 3 or 4 of those UARTs.  Let's
+ * hope for a better port registration and dynamic device allocation scheme
+ * with the serial core maintainer satisfaction to appear soon.
+ */
+
+
+#if defined(CONFIG_SERIAL_PXA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/serial_reg.h>
+#include <linux/circ_buf.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+struct uart_pxa_port {
+       struct uart_port        port;
+       unsigned char           ier;
+       unsigned char           lcr;
+       unsigned char           mcr;
+       unsigned int            lsr_break_flag;
+       struct clk              *clk;
+       char                    *name;
+};
+
+static inline unsigned int serial_in(struct uart_pxa_port *up, int offset)
+{
+       offset <<= 2;
+       return readl(up->port.membase + offset);
+}
+
+static inline void serial_out(struct uart_pxa_port *up, int offset, int value)
+{
+       offset <<= 2;
+       writel(value, up->port.membase + offset);
+}
+
+static void serial_pxa_enable_ms(struct uart_port *port)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+
+       up->ier |= UART_IER_MSI;
+       serial_out(up, UART_IER, up->ier);
+}
+
+static void serial_pxa_stop_tx(struct uart_port *port)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+
+       if (up->ier & UART_IER_THRI) {
+               up->ier &= ~UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+       }
+}
+
+static void serial_pxa_stop_rx(struct uart_port *port)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+
+       up->ier &= ~UART_IER_RLSI;
+       up->port.read_status_mask &= ~UART_LSR_DR;
+       serial_out(up, UART_IER, up->ier);
+}
+
+static inline void receive_chars(struct uart_pxa_port *up, int *status)
+{
+       struct tty_struct *tty = up->port.state->port.tty;
+       unsigned int ch, flag;
+       int max_count = 256;
+
+       do {
+               ch = serial_in(up, UART_RX);
+               flag = TTY_NORMAL;
+               up->port.icount.rx++;
+
+               if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
+                                      UART_LSR_FE | UART_LSR_OE))) {
+                       /*
+                        * For statistics only
+                        */
+                       if (*status & UART_LSR_BI) {
+                               *status &= ~(UART_LSR_FE | UART_LSR_PE);
+                               up->port.icount.brk++;
+                               /*
+                                * We do the SysRQ and SAK checking
+                                * here because otherwise the break
+                                * may get masked by ignore_status_mask
+                                * or read_status_mask.
+                                */
+                               if (uart_handle_break(&up->port))
+                                       goto ignore_char;
+                       } else if (*status & UART_LSR_PE)
+                               up->port.icount.parity++;
+                       else if (*status & UART_LSR_FE)
+                               up->port.icount.frame++;
+                       if (*status & UART_LSR_OE)
+                               up->port.icount.overrun++;
+
+                       /*
+                        * Mask off conditions which should be ignored.
+                        */
+                       *status &= up->port.read_status_mask;
+
+#ifdef CONFIG_SERIAL_PXA_CONSOLE
+                       if (up->port.line == up->port.cons->index) {
+                               /* Recover the break flag from console xmit */
+                               *status |= up->lsr_break_flag;
+                               up->lsr_break_flag = 0;
+                       }
+#endif
+                       if (*status & UART_LSR_BI) {
+                               flag = TTY_BREAK;
+                       } else if (*status & UART_LSR_PE)
+                               flag = TTY_PARITY;
+                       else if (*status & UART_LSR_FE)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(&up->port, ch))
+                       goto ignore_char;
+
+               uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag);
+
+       ignore_char:
+               *status = serial_in(up, UART_LSR);
+       } while ((*status & UART_LSR_DR) && (max_count-- > 0));
+       tty_flip_buffer_push(tty);
+}
+
+static void transmit_chars(struct uart_pxa_port *up)
+{
+       struct circ_buf *xmit = &up->port.state->xmit;
+       int count;
+
+       if (up->port.x_char) {
+               serial_out(up, UART_TX, up->port.x_char);
+               up->port.icount.tx++;
+               up->port.x_char = 0;
+               return;
+       }
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+               serial_pxa_stop_tx(&up->port);
+               return;
+       }
+
+       count = up->port.fifosize / 2;
+       do {
+               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               up->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (--count > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+
+       if (uart_circ_empty(xmit))
+               serial_pxa_stop_tx(&up->port);
+}
+
+static void serial_pxa_start_tx(struct uart_port *port)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+
+       if (!(up->ier & UART_IER_THRI)) {
+               up->ier |= UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+       }
+}
+
+static inline void check_modem_status(struct uart_pxa_port *up)
+{
+       int status;
+
+       status = serial_in(up, UART_MSR);
+
+       if ((status & UART_MSR_ANY_DELTA) == 0)
+               return;
+
+       if (status & UART_MSR_TERI)
+               up->port.icount.rng++;
+       if (status & UART_MSR_DDSR)
+               up->port.icount.dsr++;
+       if (status & UART_MSR_DDCD)
+               uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
+       if (status & UART_MSR_DCTS)
+               uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
+
+       wake_up_interruptible(&up->port.state->port.delta_msr_wait);
+}
+
+/*
+ * This handles the interrupt from one port.
+ */
+static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id)
+{
+       struct uart_pxa_port *up = dev_id;
+       unsigned int iir, lsr;
+
+       iir = serial_in(up, UART_IIR);
+       if (iir & UART_IIR_NO_INT)
+               return IRQ_NONE;
+       lsr = serial_in(up, UART_LSR);
+       if (lsr & UART_LSR_DR)
+               receive_chars(up, &lsr);
+       check_modem_status(up);
+       if (lsr & UART_LSR_THRE)
+               transmit_chars(up);
+       return IRQ_HANDLED;
+}
+
+static unsigned int serial_pxa_tx_empty(struct uart_port *port)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+       unsigned long flags;
+       unsigned int ret;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       return ret;
+}
+
+static unsigned int serial_pxa_get_mctrl(struct uart_port *port)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+       unsigned char status;
+       unsigned int ret;
+
+       status = serial_in(up, UART_MSR);
+
+       ret = 0;
+       if (status & UART_MSR_DCD)
+               ret |= TIOCM_CAR;
+       if (status & UART_MSR_RI)
+               ret |= TIOCM_RNG;
+       if (status & UART_MSR_DSR)
+               ret |= TIOCM_DSR;
+       if (status & UART_MSR_CTS)
+               ret |= TIOCM_CTS;
+       return ret;
+}
+
+static void serial_pxa_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+       unsigned char mcr = 0;
+
+       if (mctrl & TIOCM_RTS)
+               mcr |= UART_MCR_RTS;
+       if (mctrl & TIOCM_DTR)
+               mcr |= UART_MCR_DTR;
+       if (mctrl & TIOCM_OUT1)
+               mcr |= UART_MCR_OUT1;
+       if (mctrl & TIOCM_OUT2)
+               mcr |= UART_MCR_OUT2;
+       if (mctrl & TIOCM_LOOP)
+               mcr |= UART_MCR_LOOP;
+
+       mcr |= up->mcr;
+
+       serial_out(up, UART_MCR, mcr);
+}
+
+static void serial_pxa_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       if (break_state == -1)
+               up->lcr |= UART_LCR_SBC;
+       else
+               up->lcr &= ~UART_LCR_SBC;
+       serial_out(up, UART_LCR, up->lcr);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+#if 0
+static void serial_pxa_dma_init(struct pxa_uart *up)
+{
+       up->rxdma =
+               pxa_request_dma(up->name, DMA_PRIO_LOW, pxa_receive_dma, up);
+       if (up->rxdma < 0)
+               goto out;
+       up->txdma =
+               pxa_request_dma(up->name, DMA_PRIO_LOW, pxa_transmit_dma, up);
+       if (up->txdma < 0)
+               goto err_txdma;
+       up->dmadesc = kmalloc(4 * sizeof(pxa_dma_desc), GFP_KERNEL);
+       if (!up->dmadesc)
+               goto err_alloc;
+
+       /* ... */
+err_alloc:
+       pxa_free_dma(up->txdma);
+err_rxdma:
+       pxa_free_dma(up->rxdma);
+out:
+       return;
+}
+#endif
+
+static int serial_pxa_startup(struct uart_port *port)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+       unsigned long flags;
+       int retval;
+
+       if (port->line == 3) /* HWUART */
+               up->mcr |= UART_MCR_AFE;
+       else
+               up->mcr = 0;
+
+       up->port.uartclk = clk_get_rate(up->clk);
+
+       /*
+        * Allocate the IRQ
+        */
+       retval = request_irq(up->port.irq, serial_pxa_irq, 0, up->name, up);
+       if (retval)
+               return retval;
+
+       /*
+        * Clear the FIFO buffers and disable them.
+        * (they will be reenabled in set_termios())
+        */
+       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+                       UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+       serial_out(up, UART_FCR, 0);
+
+       /*
+        * Clear the interrupt registers.
+        */
+       (void) serial_in(up, UART_LSR);
+       (void) serial_in(up, UART_RX);
+       (void) serial_in(up, UART_IIR);
+       (void) serial_in(up, UART_MSR);
+
+       /*
+        * Now, initialize the UART
+        */
+       serial_out(up, UART_LCR, UART_LCR_WLEN8);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       up->port.mctrl |= TIOCM_OUT2;
+       serial_pxa_set_mctrl(&up->port, up->port.mctrl);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       /*
+        * Finally, enable interrupts.  Note: Modem status interrupts
+        * are set via set_termios(), which will be occurring imminently
+        * anyway, so we don't enable them here.
+        */
+       up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE;
+       serial_out(up, UART_IER, up->ier);
+
+       /*
+        * And clear the interrupt registers again for luck.
+        */
+       (void) serial_in(up, UART_LSR);
+       (void) serial_in(up, UART_RX);
+       (void) serial_in(up, UART_IIR);
+       (void) serial_in(up, UART_MSR);
+
+       return 0;
+}
+
+static void serial_pxa_shutdown(struct uart_port *port)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+       unsigned long flags;
+
+       free_irq(up->port.irq, up);
+
+       /*
+        * Disable interrupts from this port
+        */
+       up->ier = 0;
+       serial_out(up, UART_IER, 0);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       up->port.mctrl &= ~TIOCM_OUT2;
+       serial_pxa_set_mctrl(&up->port, up->port.mctrl);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       /*
+        * Disable break condition and FIFOs
+        */
+       serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
+       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+                                 UART_FCR_CLEAR_RCVR |
+                                 UART_FCR_CLEAR_XMIT);
+       serial_out(up, UART_FCR, 0);
+}
+
+static void
+serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,
+                      struct ktermios *old)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+       unsigned char cval, fcr = 0;
+       unsigned long flags;
+       unsigned int baud, quot;
+       unsigned int dll;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               cval = UART_LCR_WLEN5;
+               break;
+       case CS6:
+               cval = UART_LCR_WLEN6;
+               break;
+       case CS7:
+               cval = UART_LCR_WLEN7;
+               break;
+       default:
+       case CS8:
+               cval = UART_LCR_WLEN8;
+               break;
+       }
+
+       if (termios->c_cflag & CSTOPB)
+               cval |= UART_LCR_STOP;
+       if (termios->c_cflag & PARENB)
+               cval |= UART_LCR_PARITY;
+       if (!(termios->c_cflag & PARODD))
+               cval |= UART_LCR_EPAR;
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+       quot = uart_get_divisor(port, baud);
+
+       if ((up->port.uartclk / quot) < (2400 * 16))
+               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR1;
+       else if ((up->port.uartclk / quot) < (230400 * 16))
+               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR8;
+       else
+               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR32;
+
+       /*
+        * Ok, we're now changing the port state.  Do it with
+        * interrupts disabled.
+        */
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       /*
+        * Ensure the port will be enabled.
+        * This is required especially for serial console.
+        */
+       up->ier |= UART_IER_UUE;
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+       if (termios->c_iflag & INPCK)
+               up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               up->port.read_status_mask |= UART_LSR_BI;
+
+       /*
+        * Characters to ignore
+        */
+       up->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+       if (termios->c_iflag & IGNBRK) {
+               up->port.ignore_status_mask |= UART_LSR_BI;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       up->port.ignore_status_mask |= UART_LSR_OE;
+       }
+
+       /*
+        * ignore all characters if CREAD is not set
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               up->port.ignore_status_mask |= UART_LSR_DR;
+
+       /*
+        * CTS flow control flag and modem status interrupts
+        */
+       up->ier &= ~UART_IER_MSI;
+       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
+               up->ier |= UART_IER_MSI;
+
+       serial_out(up, UART_IER, up->ier);
+
+       if (termios->c_cflag & CRTSCTS)
+               up->mcr |= UART_MCR_AFE;
+       else
+               up->mcr &= ~UART_MCR_AFE;
+
+       serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
+       serial_out(up, UART_DLL, quot & 0xff);          /* LS of divisor */
+
+       /*
+        * work around Errata #75 according to Intel(R) PXA27x Processor Family
+        * Specification Update (Nov 2005)
+        */
+       dll = serial_in(up, UART_DLL);
+       WARN_ON(dll != (quot & 0xff));
+
+       serial_out(up, UART_DLM, quot >> 8);            /* MS of divisor */
+       serial_out(up, UART_LCR, cval);                 /* reset DLAB */
+       up->lcr = cval;                                 /* Save LCR */
+       serial_pxa_set_mctrl(&up->port, up->port.mctrl);
+       serial_out(up, UART_FCR, fcr);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static void
+serial_pxa_pm(struct uart_port *port, unsigned int state,
+             unsigned int oldstate)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+
+       if (!state)
+               clk_enable(up->clk);
+       else
+               clk_disable(up->clk);
+}
+
+static void serial_pxa_release_port(struct uart_port *port)
+{
+}
+
+static int serial_pxa_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static void serial_pxa_config_port(struct uart_port *port, int flags)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+       up->port.type = PORT_PXA;
+}
+
+static int
+serial_pxa_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       /* we don't want the core code to modify any port params */
+       return -EINVAL;
+}
+
+static const char *
+serial_pxa_type(struct uart_port *port)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+       return up->name;
+}
+
+static struct uart_pxa_port *serial_pxa_ports[4];
+static struct uart_driver serial_pxa_reg;
+
+#ifdef CONFIG_SERIAL_PXA_CONSOLE
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+/*
+ *     Wait for transmitter & holding register to empty
+ */
+static inline void wait_for_xmitr(struct uart_pxa_port *up)
+{
+       unsigned int status, tmout = 10000;
+
+       /* Wait up to 10ms for the character(s) to be sent. */
+       do {
+               status = serial_in(up, UART_LSR);
+
+               if (status & UART_LSR_BI)
+                       up->lsr_break_flag = UART_LSR_BI;
+
+               if (--tmout == 0)
+                       break;
+               udelay(1);
+       } while ((status & BOTH_EMPTY) != BOTH_EMPTY);
+
+       /* Wait up to 1s for flow control if necessary */
+       if (up->port.flags & UPF_CONS_FLOW) {
+               tmout = 1000000;
+               while (--tmout &&
+                      ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
+                       udelay(1);
+       }
+}
+
+static void serial_pxa_console_putchar(struct uart_port *port, int ch)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+
+       wait_for_xmitr(up);
+       serial_out(up, UART_TX, ch);
+}
+
+/*
+ * 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.
+ */
+static void
+serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct uart_pxa_port *up = serial_pxa_ports[co->index];
+       unsigned int ier;
+
+       clk_enable(up->clk);
+
+       /*
+        *      First save the IER then disable the interrupts
+        */
+       ier = serial_in(up, UART_IER);
+       serial_out(up, UART_IER, UART_IER_UUE);
+
+       uart_console_write(&up->port, s, count, serial_pxa_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the IER
+        */
+       wait_for_xmitr(up);
+       serial_out(up, UART_IER, ier);
+
+       clk_disable(up->clk);
+}
+
+static int __init
+serial_pxa_console_setup(struct console *co, char *options)
+{
+       struct uart_pxa_port *up;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (co->index == -1 || co->index >= serial_pxa_reg.nr)
+               co->index = 0;
+       up = serial_pxa_ports[co->index];
+       if (!up)
+               return -ENODEV;
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(&up->port, co, baud, parity, bits, flow);
+}
+
+static struct console serial_pxa_console = {
+       .name           = "ttyS",
+       .write          = serial_pxa_console_write,
+       .device         = uart_console_device,
+       .setup          = serial_pxa_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &serial_pxa_reg,
+};
+
+#define PXA_CONSOLE    &serial_pxa_console
+#else
+#define PXA_CONSOLE    NULL
+#endif
+
+struct uart_ops serial_pxa_pops = {
+       .tx_empty       = serial_pxa_tx_empty,
+       .set_mctrl      = serial_pxa_set_mctrl,
+       .get_mctrl      = serial_pxa_get_mctrl,
+       .stop_tx        = serial_pxa_stop_tx,
+       .start_tx       = serial_pxa_start_tx,
+       .stop_rx        = serial_pxa_stop_rx,
+       .enable_ms      = serial_pxa_enable_ms,
+       .break_ctl      = serial_pxa_break_ctl,
+       .startup        = serial_pxa_startup,
+       .shutdown       = serial_pxa_shutdown,
+       .set_termios    = serial_pxa_set_termios,
+       .pm             = serial_pxa_pm,
+       .type           = serial_pxa_type,
+       .release_port   = serial_pxa_release_port,
+       .request_port   = serial_pxa_request_port,
+       .config_port    = serial_pxa_config_port,
+       .verify_port    = serial_pxa_verify_port,
+};
+
+static struct uart_driver serial_pxa_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "PXA serial",
+       .dev_name       = "ttyS",
+       .major          = TTY_MAJOR,
+       .minor          = 64,
+       .nr             = 4,
+       .cons           = PXA_CONSOLE,
+};
+
+#ifdef CONFIG_PM
+static int serial_pxa_suspend(struct device *dev)
+{
+        struct uart_pxa_port *sport = dev_get_drvdata(dev);
+
+        if (sport)
+                uart_suspend_port(&serial_pxa_reg, &sport->port);
+
+        return 0;
+}
+
+static int serial_pxa_resume(struct device *dev)
+{
+        struct uart_pxa_port *sport = dev_get_drvdata(dev);
+
+        if (sport)
+                uart_resume_port(&serial_pxa_reg, &sport->port);
+
+        return 0;
+}
+
+static const struct dev_pm_ops serial_pxa_pm_ops = {
+       .suspend        = serial_pxa_suspend,
+       .resume         = serial_pxa_resume,
+};
+#endif
+
+static int serial_pxa_probe(struct platform_device *dev)
+{
+       struct uart_pxa_port *sport;
+       struct resource *mmres, *irqres;
+       int ret;
+
+       mmres = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       irqres = platform_get_resource(dev, IORESOURCE_IRQ, 0);
+       if (!mmres || !irqres)
+               return -ENODEV;
+
+       sport = kzalloc(sizeof(struct uart_pxa_port), GFP_KERNEL);
+       if (!sport)
+               return -ENOMEM;
+
+       sport->clk = clk_get(&dev->dev, NULL);
+       if (IS_ERR(sport->clk)) {
+               ret = PTR_ERR(sport->clk);
+               goto err_free;
+       }
+
+       sport->port.type = PORT_PXA;
+       sport->port.iotype = UPIO_MEM;
+       sport->port.mapbase = mmres->start;
+       sport->port.irq = irqres->start;
+       sport->port.fifosize = 64;
+       sport->port.ops = &serial_pxa_pops;
+       sport->port.line = dev->id;
+       sport->port.dev = &dev->dev;
+       sport->port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
+       sport->port.uartclk = clk_get_rate(sport->clk);
+
+       switch (dev->id) {
+       case 0: sport->name = "FFUART"; break;
+       case 1: sport->name = "BTUART"; break;
+       case 2: sport->name = "STUART"; break;
+       case 3: sport->name = "HWUART"; break;
+       default:
+               sport->name = "???";
+               break;
+       }
+
+       sport->port.membase = ioremap(mmres->start, mmres->end - mmres->start + 1);
+       if (!sport->port.membase) {
+               ret = -ENOMEM;
+               goto err_clk;
+       }
+
+       serial_pxa_ports[dev->id] = sport;
+
+       uart_add_one_port(&serial_pxa_reg, &sport->port);
+       platform_set_drvdata(dev, sport);
+
+       return 0;
+
+ err_clk:
+       clk_put(sport->clk);
+ err_free:
+       kfree(sport);
+       return ret;
+}
+
+static int serial_pxa_remove(struct platform_device *dev)
+{
+       struct uart_pxa_port *sport = platform_get_drvdata(dev);
+
+       platform_set_drvdata(dev, NULL);
+
+       uart_remove_one_port(&serial_pxa_reg, &sport->port);
+       clk_put(sport->clk);
+       kfree(sport);
+
+       return 0;
+}
+
+static struct platform_driver serial_pxa_driver = {
+        .probe          = serial_pxa_probe,
+        .remove         = serial_pxa_remove,
+
+       .driver         = {
+               .name   = "pxa2xx-uart",
+               .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &serial_pxa_pm_ops,
+#endif
+       },
+};
+
+int __init serial_pxa_init(void)
+{
+       int ret;
+
+       ret = uart_register_driver(&serial_pxa_reg);
+       if (ret != 0)
+               return ret;
+
+       ret = platform_driver_register(&serial_pxa_driver);
+       if (ret != 0)
+               uart_unregister_driver(&serial_pxa_reg);
+
+       return ret;
+}
+
+void __exit serial_pxa_exit(void)
+{
+       platform_driver_unregister(&serial_pxa_driver);
+       uart_unregister_driver(&serial_pxa_reg);
+}
+
+module_init(serial_pxa_init);
+module_exit(serial_pxa_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-uart");
diff --git a/drivers/tty/serial/s3c2400.c b/drivers/tty/serial/s3c2400.c
new file mode 100644 (file)
index 0000000..fed1a9a
--- /dev/null
@@ -0,0 +1,106 @@
+/* linux/drivers/serial/s3c240.c
+ *
+ * Driver for Samsung SoC onboard UARTs.
+ *
+ * Ben Dooks, Copyright (c) 2003-2005 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+#include <asm/irq.h>
+
+#include <mach/hardware.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+
+#include "samsung.h"
+
+static int s3c2400_serial_getsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       clk->divisor = 1;
+       clk->name = "pclk";
+
+       return 0;
+}
+
+static int s3c2400_serial_setsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       return 0;
+}
+
+static int s3c2400_serial_resetport(struct uart_port *port,
+                                   struct s3c2410_uartcfg *cfg)
+{
+       dbg("s3c2400_serial_resetport: port=%p (%08lx), cfg=%p\n",
+           port, port->mapbase, cfg);
+
+       wr_regl(port, S3C2410_UCON,  cfg->ucon);
+       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
+
+       /* reset both fifos */
+
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+
+       return 0;
+}
+
+static struct s3c24xx_uart_info s3c2400_uart_inf = {
+       .name           = "Samsung S3C2400 UART",
+       .type           = PORT_S3C2400,
+       .fifosize       = 16,
+       .rx_fifomask    = S3C2410_UFSTAT_RXMASK,
+       .rx_fifoshift   = S3C2410_UFSTAT_RXSHIFT,
+       .rx_fifofull    = S3C2410_UFSTAT_RXFULL,
+       .tx_fifofull    = S3C2410_UFSTAT_TXFULL,
+       .tx_fifomask    = S3C2410_UFSTAT_TXMASK,
+       .tx_fifoshift   = S3C2410_UFSTAT_TXSHIFT,
+       .get_clksrc     = s3c2400_serial_getsource,
+       .set_clksrc     = s3c2400_serial_setsource,
+       .reset_port     = s3c2400_serial_resetport,
+};
+
+static int s3c2400_serial_probe(struct platform_device *dev)
+{
+       return s3c24xx_serial_probe(dev, &s3c2400_uart_inf);
+}
+
+static struct platform_driver s3c2400_serial_driver = {
+       .probe          = s3c2400_serial_probe,
+       .remove         = __devexit_p(s3c24xx_serial_remove),
+       .driver         = {
+               .name   = "s3c2400-uart",
+               .owner  = THIS_MODULE,
+       },
+};
+
+s3c24xx_console_init(&s3c2400_serial_driver, &s3c2400_uart_inf);
+
+static inline int s3c2400_serial_init(void)
+{
+       return s3c24xx_serial_init(&s3c2400_serial_driver, &s3c2400_uart_inf);
+}
+
+static inline void s3c2400_serial_exit(void)
+{
+       platform_driver_unregister(&s3c2400_serial_driver);
+}
+
+module_init(s3c2400_serial_init);
+module_exit(s3c2400_serial_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("Samsung S3C2400 SoC Serial port driver");
+MODULE_ALIAS("platform:s3c2400-uart");
diff --git a/drivers/tty/serial/s3c2410.c b/drivers/tty/serial/s3c2410.c
new file mode 100644 (file)
index 0000000..73f089d
--- /dev/null
@@ -0,0 +1,118 @@
+/* linux/drivers/serial/s3c2410.c
+ *
+ * Driver for Samsung S3C2410 SoC onboard UARTs.
+ *
+ * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+
+#include <asm/irq.h>
+#include <mach/hardware.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+
+#include "samsung.h"
+
+static int s3c2410_serial_setsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       if (strcmp(clk->name, "uclk") == 0)
+               ucon |= S3C2410_UCON_UCLK;
+       else
+               ucon &= ~S3C2410_UCON_UCLK;
+
+       wr_regl(port, S3C2410_UCON, ucon);
+       return 0;
+}
+
+static int s3c2410_serial_getsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       clk->divisor = 1;
+       clk->name = (ucon & S3C2410_UCON_UCLK) ? "uclk" : "pclk";
+
+       return 0;
+}
+
+static int s3c2410_serial_resetport(struct uart_port *port,
+                                   struct s3c2410_uartcfg *cfg)
+{
+       dbg("s3c2410_serial_resetport: port=%p (%08lx), cfg=%p\n",
+           port, port->mapbase, cfg);
+
+       wr_regl(port, S3C2410_UCON,  cfg->ucon);
+       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
+
+       /* reset both fifos */
+
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+
+       return 0;
+}
+
+static struct s3c24xx_uart_info s3c2410_uart_inf = {
+       .name           = "Samsung S3C2410 UART",
+       .type           = PORT_S3C2410,
+       .fifosize       = 16,
+       .rx_fifomask    = S3C2410_UFSTAT_RXMASK,
+       .rx_fifoshift   = S3C2410_UFSTAT_RXSHIFT,
+       .rx_fifofull    = S3C2410_UFSTAT_RXFULL,
+       .tx_fifofull    = S3C2410_UFSTAT_TXFULL,
+       .tx_fifomask    = S3C2410_UFSTAT_TXMASK,
+       .tx_fifoshift   = S3C2410_UFSTAT_TXSHIFT,
+       .get_clksrc     = s3c2410_serial_getsource,
+       .set_clksrc     = s3c2410_serial_setsource,
+       .reset_port     = s3c2410_serial_resetport,
+};
+
+static int s3c2410_serial_probe(struct platform_device *dev)
+{
+       return s3c24xx_serial_probe(dev, &s3c2410_uart_inf);
+}
+
+static struct platform_driver s3c2410_serial_driver = {
+       .probe          = s3c2410_serial_probe,
+       .remove         = __devexit_p(s3c24xx_serial_remove),
+       .driver         = {
+               .name   = "s3c2410-uart",
+               .owner  = THIS_MODULE,
+       },
+};
+
+s3c24xx_console_init(&s3c2410_serial_driver, &s3c2410_uart_inf);
+
+static int __init s3c2410_serial_init(void)
+{
+       return s3c24xx_serial_init(&s3c2410_serial_driver, &s3c2410_uart_inf);
+}
+
+static void __exit s3c2410_serial_exit(void)
+{
+       platform_driver_unregister(&s3c2410_serial_driver);
+}
+
+module_init(s3c2410_serial_init);
+module_exit(s3c2410_serial_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("Samsung S3C2410 SoC Serial port driver");
+MODULE_ALIAS("platform:s3c2410-uart");
diff --git a/drivers/tty/serial/s3c2412.c b/drivers/tty/serial/s3c2412.c
new file mode 100644 (file)
index 0000000..1700b1a
--- /dev/null
@@ -0,0 +1,152 @@
+/* linux/drivers/serial/s3c2412.c
+ *
+ * Driver for Samsung S3C2412 and S3C2413 SoC onboard UARTs.
+ *
+ * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+
+#include <asm/irq.h>
+#include <mach/hardware.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+
+#include "samsung.h"
+
+static int s3c2412_serial_setsource(struct uart_port *port,
+                                    struct s3c24xx_uart_clksrc *clk)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       ucon &= ~S3C2412_UCON_CLKMASK;
+
+       if (strcmp(clk->name, "uclk") == 0)
+               ucon |= S3C2440_UCON_UCLK;
+       else if (strcmp(clk->name, "pclk") == 0)
+               ucon |= S3C2440_UCON_PCLK;
+       else if (strcmp(clk->name, "usysclk") == 0)
+               ucon |= S3C2412_UCON_USYSCLK;
+       else {
+               printk(KERN_ERR "unknown clock source %s\n", clk->name);
+               return -EINVAL;
+       }
+
+       wr_regl(port, S3C2410_UCON, ucon);
+       return 0;
+}
+
+
+static int s3c2412_serial_getsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       switch (ucon & S3C2412_UCON_CLKMASK) {
+       case S3C2412_UCON_UCLK:
+               clk->divisor = 1;
+               clk->name = "uclk";
+               break;
+
+       case S3C2412_UCON_PCLK:
+       case S3C2412_UCON_PCLK2:
+               clk->divisor = 1;
+               clk->name = "pclk";
+               break;
+
+       case S3C2412_UCON_USYSCLK:
+               clk->divisor = 1;
+               clk->name = "usysclk";
+               break;
+       }
+
+       return 0;
+}
+
+static int s3c2412_serial_resetport(struct uart_port *port,
+                                   struct s3c2410_uartcfg *cfg)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       dbg("%s: port=%p (%08lx), cfg=%p\n",
+           __func__, port, port->mapbase, cfg);
+
+       /* ensure we don't change the clock settings... */
+
+       ucon &= S3C2412_UCON_CLKMASK;
+
+       wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);
+       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
+
+       /* reset both fifos */
+
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+
+       return 0;
+}
+
+static struct s3c24xx_uart_info s3c2412_uart_inf = {
+       .name           = "Samsung S3C2412 UART",
+       .type           = PORT_S3C2412,
+       .fifosize       = 64,
+       .has_divslot    = 1,
+       .rx_fifomask    = S3C2440_UFSTAT_RXMASK,
+       .rx_fifoshift   = S3C2440_UFSTAT_RXSHIFT,
+       .rx_fifofull    = S3C2440_UFSTAT_RXFULL,
+       .tx_fifofull    = S3C2440_UFSTAT_TXFULL,
+       .tx_fifomask    = S3C2440_UFSTAT_TXMASK,
+       .tx_fifoshift   = S3C2440_UFSTAT_TXSHIFT,
+       .get_clksrc     = s3c2412_serial_getsource,
+       .set_clksrc     = s3c2412_serial_setsource,
+       .reset_port     = s3c2412_serial_resetport,
+};
+
+/* device management */
+
+static int s3c2412_serial_probe(struct platform_device *dev)
+{
+       dbg("s3c2440_serial_probe: dev=%p\n", dev);
+       return s3c24xx_serial_probe(dev, &s3c2412_uart_inf);
+}
+
+static struct platform_driver s3c2412_serial_driver = {
+       .probe          = s3c2412_serial_probe,
+       .remove         = __devexit_p(s3c24xx_serial_remove),
+       .driver         = {
+               .name   = "s3c2412-uart",
+               .owner  = THIS_MODULE,
+       },
+};
+
+s3c24xx_console_init(&s3c2412_serial_driver, &s3c2412_uart_inf);
+
+static inline int s3c2412_serial_init(void)
+{
+       return s3c24xx_serial_init(&s3c2412_serial_driver, &s3c2412_uart_inf);
+}
+
+static inline void s3c2412_serial_exit(void)
+{
+       platform_driver_unregister(&s3c2412_serial_driver);
+}
+
+module_init(s3c2412_serial_init);
+module_exit(s3c2412_serial_exit);
+
+MODULE_DESCRIPTION("Samsung S3C2412,S3C2413 SoC Serial port driver");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:s3c2412-uart");
diff --git a/drivers/tty/serial/s3c2440.c b/drivers/tty/serial/s3c2440.c
new file mode 100644 (file)
index 0000000..094cc39
--- /dev/null
@@ -0,0 +1,181 @@
+/* linux/drivers/serial/s3c2440.c
+ *
+ * Driver for Samsung S3C2440 and S3C2442 SoC onboard UARTs.
+ *
+ * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+
+#include <asm/irq.h>
+#include <mach/hardware.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+
+#include "samsung.h"
+
+
+static int s3c2440_serial_setsource(struct uart_port *port,
+                                    struct s3c24xx_uart_clksrc *clk)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       /* todo - proper fclk<>nonfclk switch. */
+
+       ucon &= ~S3C2440_UCON_CLKMASK;
+
+       if (strcmp(clk->name, "uclk") == 0)
+               ucon |= S3C2440_UCON_UCLK;
+       else if (strcmp(clk->name, "pclk") == 0)
+               ucon |= S3C2440_UCON_PCLK;
+       else if (strcmp(clk->name, "fclk") == 0)
+               ucon |= S3C2440_UCON_FCLK;
+       else {
+               printk(KERN_ERR "unknown clock source %s\n", clk->name);
+               return -EINVAL;
+       }
+
+       wr_regl(port, S3C2410_UCON, ucon);
+       return 0;
+}
+
+
+static int s3c2440_serial_getsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+       unsigned long ucon0, ucon1, ucon2;
+
+       switch (ucon & S3C2440_UCON_CLKMASK) {
+       case S3C2440_UCON_UCLK:
+               clk->divisor = 1;
+               clk->name = "uclk";
+               break;
+
+       case S3C2440_UCON_PCLK:
+       case S3C2440_UCON_PCLK2:
+               clk->divisor = 1;
+               clk->name = "pclk";
+               break;
+
+       case S3C2440_UCON_FCLK:
+               /* the fun of calculating the uart divisors on
+                * the s3c2440 */
+
+               ucon0 = __raw_readl(S3C24XX_VA_UART0 + S3C2410_UCON);
+               ucon1 = __raw_readl(S3C24XX_VA_UART1 + S3C2410_UCON);
+               ucon2 = __raw_readl(S3C24XX_VA_UART2 + S3C2410_UCON);
+
+               printk("ucons: %08lx, %08lx, %08lx\n", ucon0, ucon1, ucon2);
+
+               ucon0 &= S3C2440_UCON0_DIVMASK;
+               ucon1 &= S3C2440_UCON1_DIVMASK;
+               ucon2 &= S3C2440_UCON2_DIVMASK;
+
+               if (ucon0 != 0) {
+                       clk->divisor = ucon0 >> S3C2440_UCON_DIVSHIFT;
+                       clk->divisor += 6;
+               } else if (ucon1 != 0) {
+                       clk->divisor = ucon1 >> S3C2440_UCON_DIVSHIFT;
+                       clk->divisor += 21;
+               } else if (ucon2 != 0) {
+                       clk->divisor = ucon2 >> S3C2440_UCON_DIVSHIFT;
+                       clk->divisor += 36;
+               } else {
+                       /* manual calims 44, seems to be 9 */
+                       clk->divisor = 9;
+               }
+
+               clk->name = "fclk";
+               break;
+       }
+
+       return 0;
+}
+
+static int s3c2440_serial_resetport(struct uart_port *port,
+                                   struct s3c2410_uartcfg *cfg)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       dbg("s3c2440_serial_resetport: port=%p (%08lx), cfg=%p\n",
+           port, port->mapbase, cfg);
+
+       /* ensure we don't change the clock settings... */
+
+       ucon &= (S3C2440_UCON0_DIVMASK | (3<<10));
+
+       wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);
+       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
+
+       /* reset both fifos */
+
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+
+       return 0;
+}
+
+static struct s3c24xx_uart_info s3c2440_uart_inf = {
+       .name           = "Samsung S3C2440 UART",
+       .type           = PORT_S3C2440,
+       .fifosize       = 64,
+       .rx_fifomask    = S3C2440_UFSTAT_RXMASK,
+       .rx_fifoshift   = S3C2440_UFSTAT_RXSHIFT,
+       .rx_fifofull    = S3C2440_UFSTAT_RXFULL,
+       .tx_fifofull    = S3C2440_UFSTAT_TXFULL,
+       .tx_fifomask    = S3C2440_UFSTAT_TXMASK,
+       .tx_fifoshift   = S3C2440_UFSTAT_TXSHIFT,
+       .get_clksrc     = s3c2440_serial_getsource,
+       .set_clksrc     = s3c2440_serial_setsource,
+       .reset_port     = s3c2440_serial_resetport,
+};
+
+/* device management */
+
+static int s3c2440_serial_probe(struct platform_device *dev)
+{
+       dbg("s3c2440_serial_probe: dev=%p\n", dev);
+       return s3c24xx_serial_probe(dev, &s3c2440_uart_inf);
+}
+
+static struct platform_driver s3c2440_serial_driver = {
+       .probe          = s3c2440_serial_probe,
+       .remove         = __devexit_p(s3c24xx_serial_remove),
+       .driver         = {
+               .name   = "s3c2440-uart",
+               .owner  = THIS_MODULE,
+       },
+};
+
+s3c24xx_console_init(&s3c2440_serial_driver, &s3c2440_uart_inf);
+
+static int __init s3c2440_serial_init(void)
+{
+       return s3c24xx_serial_init(&s3c2440_serial_driver, &s3c2440_uart_inf);
+}
+
+static void __exit s3c2440_serial_exit(void)
+{
+       platform_driver_unregister(&s3c2440_serial_driver);
+}
+
+module_init(s3c2440_serial_init);
+module_exit(s3c2440_serial_exit);
+
+MODULE_DESCRIPTION("Samsung S3C2440,S3C2442 SoC Serial port driver");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:s3c2440-uart");
diff --git a/drivers/tty/serial/s3c24a0.c b/drivers/tty/serial/s3c24a0.c
new file mode 100644 (file)
index 0000000..fad6083
--- /dev/null
@@ -0,0 +1,118 @@
+/* linux/drivers/serial/s3c24a0.c
+ *
+ * Driver for Samsung S3C24A0 SoC onboard UARTs.
+ *
+ * Based on drivers/serial/s3c2410.c
+ *
+ * Author: Sandeep Patil <sandeep.patil@azingo.com>
+ *
+ * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <mach/hardware.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+
+#include "samsung.h"
+
+static int s3c24a0_serial_setsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       if (strcmp(clk->name, "uclk") == 0)
+               ucon |= S3C2410_UCON_UCLK;
+       else
+               ucon &= ~S3C2410_UCON_UCLK;
+
+       wr_regl(port, S3C2410_UCON, ucon);
+       return 0;
+}
+
+static int s3c24a0_serial_getsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       clk->divisor = 1;
+       clk->name = (ucon & S3C2410_UCON_UCLK) ? "uclk" : "pclk";
+
+       return 0;
+}
+
+static int s3c24a0_serial_resetport(struct uart_port *port,
+                                   struct s3c2410_uartcfg *cfg)
+{
+       dbg("s3c24a0_serial_resetport: port=%p (%08lx), cfg=%p\n",
+           port, port->mapbase, cfg);
+
+       wr_regl(port, S3C2410_UCON,  cfg->ucon);
+       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
+
+       /* reset both fifos */
+
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+
+       return 0;
+}
+
+static struct s3c24xx_uart_info s3c24a0_uart_inf = {
+       .name           = "Samsung S3C24A0 UART",
+       .type           = PORT_S3C2410,
+       .fifosize       = 16,
+       .rx_fifomask    = S3C24A0_UFSTAT_RXMASK,
+       .rx_fifoshift   = S3C24A0_UFSTAT_RXSHIFT,
+       .rx_fifofull    = S3C24A0_UFSTAT_RXFULL,
+       .tx_fifofull    = S3C24A0_UFSTAT_TXFULL,
+       .tx_fifomask    = S3C24A0_UFSTAT_TXMASK,
+       .tx_fifoshift   = S3C24A0_UFSTAT_TXSHIFT,
+       .get_clksrc     = s3c24a0_serial_getsource,
+       .set_clksrc     = s3c24a0_serial_setsource,
+       .reset_port     = s3c24a0_serial_resetport,
+};
+
+static int s3c24a0_serial_probe(struct platform_device *dev)
+{
+       return s3c24xx_serial_probe(dev, &s3c24a0_uart_inf);
+}
+
+static struct platform_driver s3c24a0_serial_driver = {
+       .probe          = s3c24a0_serial_probe,
+       .remove         = __devexit_p(s3c24xx_serial_remove),
+       .driver         = {
+               .name   = "s3c24a0-uart",
+               .owner  = THIS_MODULE,
+       },
+};
+
+s3c24xx_console_init(&s3c24a0_serial_driver, &s3c24a0_uart_inf);
+
+static int __init s3c24a0_serial_init(void)
+{
+       return s3c24xx_serial_init(&s3c24a0_serial_driver, &s3c24a0_uart_inf);
+}
+
+static void __exit s3c24a0_serial_exit(void)
+{
+       platform_driver_unregister(&s3c24a0_serial_driver);
+}
+
+module_init(s3c24a0_serial_init);
+module_exit(s3c24a0_serial_exit);
+
diff --git a/drivers/tty/serial/s3c6400.c b/drivers/tty/serial/s3c6400.c
new file mode 100644 (file)
index 0000000..4be92ab
--- /dev/null
@@ -0,0 +1,152 @@
+/* linux/drivers/serial/s3c6400.c
+ *
+ * Driver for Samsung S3C6400 and S3C6410 SoC onboard UARTs.
+ *
+ * Copyright 2008 Openmoko,  Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+
+#include <asm/irq.h>
+#include <mach/hardware.h>
+
+#include <plat/regs-serial.h>
+
+#include "samsung.h"
+
+static int s3c6400_serial_setsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       if (strcmp(clk->name, "uclk0") == 0) {
+               ucon &= ~S3C6400_UCON_CLKMASK;
+               ucon |= S3C6400_UCON_UCLK0;
+       } else if (strcmp(clk->name, "uclk1") == 0)
+               ucon |= S3C6400_UCON_UCLK1;
+       else if (strcmp(clk->name, "pclk") == 0) {
+               /* See notes about transitioning from UCLK to PCLK */
+               ucon &= ~S3C6400_UCON_UCLK0;
+       } else {
+               printk(KERN_ERR "unknown clock source %s\n", clk->name);
+               return -EINVAL;
+       }
+
+       wr_regl(port, S3C2410_UCON, ucon);
+       return 0;
+}
+
+
+static int s3c6400_serial_getsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       u32 ucon = rd_regl(port, S3C2410_UCON);
+
+       clk->divisor = 1;
+
+       switch (ucon & S3C6400_UCON_CLKMASK) {
+       case S3C6400_UCON_UCLK0:
+               clk->name = "uclk0";
+               break;
+
+       case S3C6400_UCON_UCLK1:
+               clk->name = "uclk1";
+               break;
+
+       case S3C6400_UCON_PCLK:
+       case S3C6400_UCON_PCLK2:
+               clk->name = "pclk";
+               break;
+       }
+
+       return 0;
+}
+
+static int s3c6400_serial_resetport(struct uart_port *port,
+                                   struct s3c2410_uartcfg *cfg)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       dbg("s3c6400_serial_resetport: port=%p (%08lx), cfg=%p\n",
+           port, port->mapbase, cfg);
+
+       /* ensure we don't change the clock settings... */
+
+       ucon &= S3C6400_UCON_CLKMASK;
+
+       wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);
+       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
+
+       /* reset both fifos */
+
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+
+       return 0;
+}
+
+static struct s3c24xx_uart_info s3c6400_uart_inf = {
+       .name           = "Samsung S3C6400 UART",
+       .type           = PORT_S3C6400,
+       .fifosize       = 64,
+       .has_divslot    = 1,
+       .rx_fifomask    = S3C2440_UFSTAT_RXMASK,
+       .rx_fifoshift   = S3C2440_UFSTAT_RXSHIFT,
+       .rx_fifofull    = S3C2440_UFSTAT_RXFULL,
+       .tx_fifofull    = S3C2440_UFSTAT_TXFULL,
+       .tx_fifomask    = S3C2440_UFSTAT_TXMASK,
+       .tx_fifoshift   = S3C2440_UFSTAT_TXSHIFT,
+       .get_clksrc     = s3c6400_serial_getsource,
+       .set_clksrc     = s3c6400_serial_setsource,
+       .reset_port     = s3c6400_serial_resetport,
+};
+
+/* device management */
+
+static int s3c6400_serial_probe(struct platform_device *dev)
+{
+       dbg("s3c6400_serial_probe: dev=%p\n", dev);
+       return s3c24xx_serial_probe(dev, &s3c6400_uart_inf);
+}
+
+static struct platform_driver s3c6400_serial_driver = {
+       .probe          = s3c6400_serial_probe,
+       .remove         = __devexit_p(s3c24xx_serial_remove),
+       .driver         = {
+               .name   = "s3c6400-uart",
+               .owner  = THIS_MODULE,
+       },
+};
+
+s3c24xx_console_init(&s3c6400_serial_driver, &s3c6400_uart_inf);
+
+static int __init s3c6400_serial_init(void)
+{
+       return s3c24xx_serial_init(&s3c6400_serial_driver, &s3c6400_uart_inf);
+}
+
+static void __exit s3c6400_serial_exit(void)
+{
+       platform_driver_unregister(&s3c6400_serial_driver);
+}
+
+module_init(s3c6400_serial_init);
+module_exit(s3c6400_serial_exit);
+
+MODULE_DESCRIPTION("Samsung S3C6400,S3C6410 SoC Serial port driver");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:s3c6400-uart");
diff --git a/drivers/tty/serial/s5pv210.c b/drivers/tty/serial/s5pv210.c
new file mode 100644 (file)
index 0000000..6ebccd7
--- /dev/null
@@ -0,0 +1,162 @@
+/* linux/drivers/serial/s5pv210.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * Based on drivers/serial/s3c6400.c
+ *
+ * Driver for Samsung S5PV210 SoC UARTs.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+
+#include <asm/irq.h>
+#include <mach/hardware.h>
+#include <plat/regs-serial.h>
+#include "samsung.h"
+
+static int s5pv210_serial_setsource(struct uart_port *port,
+                                       struct s3c24xx_uart_clksrc *clk)
+{
+       struct s3c2410_uartcfg *cfg = port->dev->platform_data;
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       if ((cfg->clocks_size) == 1)
+               return 0;
+
+       if (strcmp(clk->name, "pclk") == 0)
+               ucon &= ~S5PV210_UCON_CLKMASK;
+       else if (strcmp(clk->name, "uclk1") == 0)
+               ucon |= S5PV210_UCON_CLKMASK;
+       else {
+               printk(KERN_ERR "unknown clock source %s\n", clk->name);
+               return -EINVAL;
+       }
+
+       wr_regl(port, S3C2410_UCON, ucon);
+       return 0;
+}
+
+
+static int s5pv210_serial_getsource(struct uart_port *port,
+                                       struct s3c24xx_uart_clksrc *clk)
+{
+       struct s3c2410_uartcfg *cfg = port->dev->platform_data;
+       u32 ucon = rd_regl(port, S3C2410_UCON);
+
+       clk->divisor = 1;
+
+       if ((cfg->clocks_size) == 1)
+               return 0;
+
+       switch (ucon & S5PV210_UCON_CLKMASK) {
+       case S5PV210_UCON_PCLK:
+               clk->name = "pclk";
+               break;
+       case S5PV210_UCON_UCLK:
+               clk->name = "uclk1";
+               break;
+       }
+
+       return 0;
+}
+
+static int s5pv210_serial_resetport(struct uart_port *port,
+                                       struct s3c2410_uartcfg *cfg)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       ucon &= S5PV210_UCON_CLKMASK;
+       wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);
+       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
+
+       /* reset both fifos */
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+
+       return 0;
+}
+
+#define S5PV210_UART_DEFAULT_INFO(fifo_size)                   \
+               .name           = "Samsung S5PV210 UART0",      \
+               .type           = PORT_S3C6400,                 \
+               .fifosize       = fifo_size,                    \
+               .has_divslot    = 1,                            \
+               .rx_fifomask    = S5PV210_UFSTAT_RXMASK,        \
+               .rx_fifoshift   = S5PV210_UFSTAT_RXSHIFT,       \
+               .rx_fifofull    = S5PV210_UFSTAT_RXFULL,        \
+               .tx_fifofull    = S5PV210_UFSTAT_TXFULL,        \
+               .tx_fifomask    = S5PV210_UFSTAT_TXMASK,        \
+               .tx_fifoshift   = S5PV210_UFSTAT_TXSHIFT,       \
+               .get_clksrc     = s5pv210_serial_getsource,     \
+               .set_clksrc     = s5pv210_serial_setsource,     \
+               .reset_port     = s5pv210_serial_resetport
+
+static struct s3c24xx_uart_info s5p_port_fifo256 = {
+       S5PV210_UART_DEFAULT_INFO(256),
+};
+
+static struct s3c24xx_uart_info s5p_port_fifo64 = {
+       S5PV210_UART_DEFAULT_INFO(64),
+};
+
+static struct s3c24xx_uart_info s5p_port_fifo16 = {
+       S5PV210_UART_DEFAULT_INFO(16),
+};
+
+static struct s3c24xx_uart_info *s5p_uart_inf[] = {
+       [0] = &s5p_port_fifo256,
+       [1] = &s5p_port_fifo64,
+       [2] = &s5p_port_fifo16,
+       [3] = &s5p_port_fifo16,
+};
+
+/* device management */
+static int s5p_serial_probe(struct platform_device *pdev)
+{
+       return s3c24xx_serial_probe(pdev, s5p_uart_inf[pdev->id]);
+}
+
+static struct platform_driver s5p_serial_driver = {
+       .probe          = s5p_serial_probe,
+       .remove         = __devexit_p(s3c24xx_serial_remove),
+       .driver         = {
+               .name   = "s5pv210-uart",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init s5pv210_serial_console_init(void)
+{
+       return s3c24xx_serial_initconsole(&s5p_serial_driver, s5p_uart_inf);
+}
+
+console_initcall(s5pv210_serial_console_init);
+
+static int __init s5p_serial_init(void)
+{
+       return s3c24xx_serial_init(&s5p_serial_driver, *s5p_uart_inf);
+}
+
+static void __exit s5p_serial_exit(void)
+{
+       platform_driver_unregister(&s5p_serial_driver);
+}
+
+module_init(s5p_serial_init);
+module_exit(s5p_serial_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s5pv210-uart");
+MODULE_DESCRIPTION("Samsung S5PV210 UART Driver support");
+MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com>");
diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c
new file mode 100644 (file)
index 0000000..2199d81
--- /dev/null
@@ -0,0 +1,918 @@
+/*
+ *  linux/drivers/char/sa1100.c
+ *
+ *  Driver for SA11x0 serial ports
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ *  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
+ */
+
+#if defined(CONFIG_SERIAL_SA1100_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+#include <mach/hardware.h>
+#include <asm/mach/serial_sa1100.h>
+
+/* We've been assigned a range on the "Low-density serial ports" major */
+#define SERIAL_SA1100_MAJOR    204
+#define MINOR_START            5
+
+#define NR_PORTS               3
+
+#define SA1100_ISR_PASS_LIMIT  256
+
+/*
+ * Convert from ignore_status_mask or read_status_mask to UTSR[01]
+ */
+#define SM_TO_UTSR0(x) ((x) & 0xff)
+#define SM_TO_UTSR1(x) ((x) >> 8)
+#define UTSR0_TO_SM(x) ((x))
+#define UTSR1_TO_SM(x) ((x) << 8)
+
+#define UART_GET_UTCR0(sport)  __raw_readl((sport)->port.membase + UTCR0)
+#define UART_GET_UTCR1(sport)  __raw_readl((sport)->port.membase + UTCR1)
+#define UART_GET_UTCR2(sport)  __raw_readl((sport)->port.membase + UTCR2)
+#define UART_GET_UTCR3(sport)  __raw_readl((sport)->port.membase + UTCR3)
+#define UART_GET_UTSR0(sport)  __raw_readl((sport)->port.membase + UTSR0)
+#define UART_GET_UTSR1(sport)  __raw_readl((sport)->port.membase + UTSR1)
+#define UART_GET_CHAR(sport)   __raw_readl((sport)->port.membase + UTDR)
+
+#define UART_PUT_UTCR0(sport,v)        __raw_writel((v),(sport)->port.membase + UTCR0)
+#define UART_PUT_UTCR1(sport,v)        __raw_writel((v),(sport)->port.membase + UTCR1)
+#define UART_PUT_UTCR2(sport,v)        __raw_writel((v),(sport)->port.membase + UTCR2)
+#define UART_PUT_UTCR3(sport,v)        __raw_writel((v),(sport)->port.membase + UTCR3)
+#define UART_PUT_UTSR0(sport,v)        __raw_writel((v),(sport)->port.membase + UTSR0)
+#define UART_PUT_UTSR1(sport,v)        __raw_writel((v),(sport)->port.membase + UTSR1)
+#define UART_PUT_CHAR(sport,v) __raw_writel((v),(sport)->port.membase + UTDR)
+
+/*
+ * This is the size of our serial port register set.
+ */
+#define UART_PORT_SIZE 0x24
+
+/*
+ * This determines how often we check the modem status signals
+ * for any change.  They generally aren't connected to an IRQ
+ * so we have to poll them.  We also check immediately before
+ * filling the TX fifo incase CTS has been dropped.
+ */
+#define MCTRL_TIMEOUT  (250*HZ/1000)
+
+struct sa1100_port {
+       struct uart_port        port;
+       struct timer_list       timer;
+       unsigned int            old_status;
+};
+
+/*
+ * Handle any change of modem status signal since we were last called.
+ */
+static void sa1100_mctrl_check(struct sa1100_port *sport)
+{
+       unsigned int status, changed;
+
+       status = sport->port.ops->get_mctrl(&sport->port);
+       changed = status ^ sport->old_status;
+
+       if (changed == 0)
+               return;
+
+       sport->old_status = status;
+
+       if (changed & TIOCM_RI)
+               sport->port.icount.rng++;
+       if (changed & TIOCM_DSR)
+               sport->port.icount.dsr++;
+       if (changed & TIOCM_CAR)
+               uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
+       if (changed & TIOCM_CTS)
+               uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
+
+       wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
+}
+
+/*
+ * This is our per-port timeout handler, for checking the
+ * modem status signals.
+ */
+static void sa1100_timeout(unsigned long data)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)data;
+       unsigned long flags;
+
+       if (sport->port.state) {
+               spin_lock_irqsave(&sport->port.lock, flags);
+               sa1100_mctrl_check(sport);
+               spin_unlock_irqrestore(&sport->port.lock, flags);
+
+               mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
+       }
+}
+
+/*
+ * interrupts disabled on entry
+ */
+static void sa1100_stop_tx(struct uart_port *port)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+       u32 utcr3;
+
+       utcr3 = UART_GET_UTCR3(sport);
+       UART_PUT_UTCR3(sport, utcr3 & ~UTCR3_TIE);
+       sport->port.read_status_mask &= ~UTSR0_TO_SM(UTSR0_TFS);
+}
+
+/*
+ * port locked and interrupts disabled
+ */
+static void sa1100_start_tx(struct uart_port *port)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+       u32 utcr3;
+
+       utcr3 = UART_GET_UTCR3(sport);
+       sport->port.read_status_mask |= UTSR0_TO_SM(UTSR0_TFS);
+       UART_PUT_UTCR3(sport, utcr3 | UTCR3_TIE);
+}
+
+/*
+ * Interrupts enabled
+ */
+static void sa1100_stop_rx(struct uart_port *port)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+       u32 utcr3;
+
+       utcr3 = UART_GET_UTCR3(sport);
+       UART_PUT_UTCR3(sport, utcr3 & ~UTCR3_RIE);
+}
+
+/*
+ * Set the modem control timer to fire immediately.
+ */
+static void sa1100_enable_ms(struct uart_port *port)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+
+       mod_timer(&sport->timer, jiffies);
+}
+
+static void
+sa1100_rx_chars(struct sa1100_port *sport)
+{
+       struct tty_struct *tty = sport->port.state->port.tty;
+       unsigned int status, ch, flg;
+
+       status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) |
+                UTSR0_TO_SM(UART_GET_UTSR0(sport));
+       while (status & UTSR1_TO_SM(UTSR1_RNE)) {
+               ch = UART_GET_CHAR(sport);
+
+               sport->port.icount.rx++;
+
+               flg = TTY_NORMAL;
+
+               /*
+                * note that the error handling code is
+                * out of the main execution path
+                */
+               if (status & UTSR1_TO_SM(UTSR1_PRE | UTSR1_FRE | UTSR1_ROR)) {
+                       if (status & UTSR1_TO_SM(UTSR1_PRE))
+                               sport->port.icount.parity++;
+                       else if (status & UTSR1_TO_SM(UTSR1_FRE))
+                               sport->port.icount.frame++;
+                       if (status & UTSR1_TO_SM(UTSR1_ROR))
+                               sport->port.icount.overrun++;
+
+                       status &= sport->port.read_status_mask;
+
+                       if (status & UTSR1_TO_SM(UTSR1_PRE))
+                               flg = TTY_PARITY;
+                       else if (status & UTSR1_TO_SM(UTSR1_FRE))
+                               flg = TTY_FRAME;
+
+#ifdef SUPPORT_SYSRQ
+                       sport->port.sysrq = 0;
+#endif
+               }
+
+               if (uart_handle_sysrq_char(&sport->port, ch))
+                       goto ignore_char;
+
+               uart_insert_char(&sport->port, status, UTSR1_TO_SM(UTSR1_ROR), ch, flg);
+
+       ignore_char:
+               status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) |
+                        UTSR0_TO_SM(UART_GET_UTSR0(sport));
+       }
+       tty_flip_buffer_push(tty);
+}
+
+static void sa1100_tx_chars(struct sa1100_port *sport)
+{
+       struct circ_buf *xmit = &sport->port.state->xmit;
+
+       if (sport->port.x_char) {
+               UART_PUT_CHAR(sport, sport->port.x_char);
+               sport->port.icount.tx++;
+               sport->port.x_char = 0;
+               return;
+       }
+
+       /*
+        * Check the modem control lines before
+        * transmitting anything.
+        */
+       sa1100_mctrl_check(sport);
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
+               sa1100_stop_tx(&sport->port);
+               return;
+       }
+
+       /*
+        * Tried using FIFO (not checking TNF) for fifo fill:
+        * still had the '4 bytes repeated' problem.
+        */
+       while (UART_GET_UTSR1(sport) & UTSR1_TNF) {
+               UART_PUT_CHAR(sport, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               sport->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&sport->port);
+
+       if (uart_circ_empty(xmit))
+               sa1100_stop_tx(&sport->port);
+}
+
+static irqreturn_t sa1100_int(int irq, void *dev_id)
+{
+       struct sa1100_port *sport = dev_id;
+       unsigned int status, pass_counter = 0;
+
+       spin_lock(&sport->port.lock);
+       status = UART_GET_UTSR0(sport);
+       status &= SM_TO_UTSR0(sport->port.read_status_mask) | ~UTSR0_TFS;
+       do {
+               if (status & (UTSR0_RFS | UTSR0_RID)) {
+                       /* Clear the receiver idle bit, if set */
+                       if (status & UTSR0_RID)
+                               UART_PUT_UTSR0(sport, UTSR0_RID);
+                       sa1100_rx_chars(sport);
+               }
+
+               /* Clear the relevant break bits */
+               if (status & (UTSR0_RBB | UTSR0_REB))
+                       UART_PUT_UTSR0(sport, status & (UTSR0_RBB | UTSR0_REB));
+
+               if (status & UTSR0_RBB)
+                       sport->port.icount.brk++;
+
+               if (status & UTSR0_REB)
+                       uart_handle_break(&sport->port);
+
+               if (status & UTSR0_TFS)
+                       sa1100_tx_chars(sport);
+               if (pass_counter++ > SA1100_ISR_PASS_LIMIT)
+                       break;
+               status = UART_GET_UTSR0(sport);
+               status &= SM_TO_UTSR0(sport->port.read_status_mask) |
+                         ~UTSR0_TFS;
+       } while (status & (UTSR0_TFS | UTSR0_RFS | UTSR0_RID));
+       spin_unlock(&sport->port.lock);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * Return TIOCSER_TEMT when transmitter is not busy.
+ */
+static unsigned int sa1100_tx_empty(struct uart_port *port)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+
+       return UART_GET_UTSR1(sport) & UTSR1_TBY ? 0 : TIOCSER_TEMT;
+}
+
+static unsigned int sa1100_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void sa1100_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+/*
+ * Interrupts always disabled.
+ */
+static void sa1100_break_ctl(struct uart_port *port, int break_state)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+       unsigned long flags;
+       unsigned int utcr3;
+
+       spin_lock_irqsave(&sport->port.lock, flags);
+       utcr3 = UART_GET_UTCR3(sport);
+       if (break_state == -1)
+               utcr3 |= UTCR3_BRK;
+       else
+               utcr3 &= ~UTCR3_BRK;
+       UART_PUT_UTCR3(sport, utcr3);
+       spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static int sa1100_startup(struct uart_port *port)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+       int retval;
+
+       /*
+        * Allocate the IRQ
+        */
+       retval = request_irq(sport->port.irq, sa1100_int, 0,
+                            "sa11x0-uart", sport);
+       if (retval)
+               return retval;
+
+       /*
+        * Finally, clear and enable interrupts
+        */
+       UART_PUT_UTSR0(sport, -1);
+       UART_PUT_UTCR3(sport, UTCR3_RXE | UTCR3_TXE | UTCR3_RIE);
+
+       /*
+        * Enable modem status interrupts
+        */
+       spin_lock_irq(&sport->port.lock);
+       sa1100_enable_ms(&sport->port);
+       spin_unlock_irq(&sport->port.lock);
+
+       return 0;
+}
+
+static void sa1100_shutdown(struct uart_port *port)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+
+       /*
+        * Stop our timer.
+        */
+       del_timer_sync(&sport->timer);
+
+       /*
+        * Free the interrupt
+        */
+       free_irq(sport->port.irq, sport);
+
+       /*
+        * Disable all interrupts, port and break condition.
+        */
+       UART_PUT_UTCR3(sport, 0);
+}
+
+static void
+sa1100_set_termios(struct uart_port *port, struct ktermios *termios,
+                  struct ktermios *old)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+       unsigned long flags;
+       unsigned int utcr0, old_utcr3, baud, quot;
+       unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
+
+       /*
+        * We only support CS7 and CS8.
+        */
+       while ((termios->c_cflag & CSIZE) != CS7 &&
+              (termios->c_cflag & CSIZE) != CS8) {
+               termios->c_cflag &= ~CSIZE;
+               termios->c_cflag |= old_csize;
+               old_csize = CS8;
+       }
+
+       if ((termios->c_cflag & CSIZE) == CS8)
+               utcr0 = UTCR0_DSS;
+       else
+               utcr0 = 0;
+
+       if (termios->c_cflag & CSTOPB)
+               utcr0 |= UTCR0_SBS;
+       if (termios->c_cflag & PARENB) {
+               utcr0 |= UTCR0_PE;
+               if (!(termios->c_cflag & PARODD))
+                       utcr0 |= UTCR0_OES;
+       }
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
+       quot = uart_get_divisor(port, baud);
+
+       spin_lock_irqsave(&sport->port.lock, flags);
+
+       sport->port.read_status_mask &= UTSR0_TO_SM(UTSR0_TFS);
+       sport->port.read_status_mask |= UTSR1_TO_SM(UTSR1_ROR);
+       if (termios->c_iflag & INPCK)
+               sport->port.read_status_mask |=
+                               UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE);
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               sport->port.read_status_mask |=
+                               UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB);
+
+       /*
+        * Characters to ignore
+        */
+       sport->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               sport->port.ignore_status_mask |=
+                               UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE);
+       if (termios->c_iflag & IGNBRK) {
+               sport->port.ignore_status_mask |=
+                               UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB);
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       sport->port.ignore_status_mask |=
+                               UTSR1_TO_SM(UTSR1_ROR);
+       }
+
+       del_timer_sync(&sport->timer);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       /*
+        * disable interrupts and drain transmitter
+        */
+       old_utcr3 = UART_GET_UTCR3(sport);
+       UART_PUT_UTCR3(sport, old_utcr3 & ~(UTCR3_RIE | UTCR3_TIE));
+
+       while (UART_GET_UTSR1(sport) & UTSR1_TBY)
+               barrier();
+
+       /* then, disable everything */
+       UART_PUT_UTCR3(sport, 0);
+
+       /* set the parity, stop bits and data size */
+       UART_PUT_UTCR0(sport, utcr0);
+
+       /* set the baud rate */
+       quot -= 1;
+       UART_PUT_UTCR1(sport, ((quot & 0xf00) >> 8));
+       UART_PUT_UTCR2(sport, (quot & 0xff));
+
+       UART_PUT_UTSR0(sport, -1);
+
+       UART_PUT_UTCR3(sport, old_utcr3);
+
+       if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
+               sa1100_enable_ms(&sport->port);
+
+       spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static const char *sa1100_type(struct uart_port *port)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+
+       return sport->port.type == PORT_SA1100 ? "SA1100" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'.
+ */
+static void sa1100_release_port(struct uart_port *port)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+
+       release_mem_region(sport->port.mapbase, UART_PORT_SIZE);
+}
+
+/*
+ * Request the memory region(s) being used by 'port'.
+ */
+static int sa1100_request_port(struct uart_port *port)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+
+       return request_mem_region(sport->port.mapbase, UART_PORT_SIZE,
+                       "sa11x0-uart") != NULL ? 0 : -EBUSY;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void sa1100_config_port(struct uart_port *port, int flags)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+
+       if (flags & UART_CONFIG_TYPE &&
+           sa1100_request_port(&sport->port) == 0)
+               sport->port.type = PORT_SA1100;
+}
+
+/*
+ * Verify the new serial_struct (for TIOCSSERIAL).
+ * The only change we allow are to the flags and type, and
+ * even then only between PORT_SA1100 and PORT_UNKNOWN
+ */
+static int
+sa1100_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+       int ret = 0;
+
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_SA1100)
+               ret = -EINVAL;
+       if (sport->port.irq != ser->irq)
+               ret = -EINVAL;
+       if (ser->io_type != SERIAL_IO_MEM)
+               ret = -EINVAL;
+       if (sport->port.uartclk / 16 != ser->baud_base)
+               ret = -EINVAL;
+       if ((void *)sport->port.mapbase != ser->iomem_base)
+               ret = -EINVAL;
+       if (sport->port.iobase != ser->port)
+               ret = -EINVAL;
+       if (ser->hub6 != 0)
+               ret = -EINVAL;
+       return ret;
+}
+
+static struct uart_ops sa1100_pops = {
+       .tx_empty       = sa1100_tx_empty,
+       .set_mctrl      = sa1100_set_mctrl,
+       .get_mctrl      = sa1100_get_mctrl,
+       .stop_tx        = sa1100_stop_tx,
+       .start_tx       = sa1100_start_tx,
+       .stop_rx        = sa1100_stop_rx,
+       .enable_ms      = sa1100_enable_ms,
+       .break_ctl      = sa1100_break_ctl,
+       .startup        = sa1100_startup,
+       .shutdown       = sa1100_shutdown,
+       .set_termios    = sa1100_set_termios,
+       .type           = sa1100_type,
+       .release_port   = sa1100_release_port,
+       .request_port   = sa1100_request_port,
+       .config_port    = sa1100_config_port,
+       .verify_port    = sa1100_verify_port,
+};
+
+static struct sa1100_port sa1100_ports[NR_PORTS];
+
+/*
+ * Setup the SA1100 serial ports.  Note that we don't include the IrDA
+ * port here since we have our own SIR/FIR driver (see drivers/net/irda)
+ *
+ * Note also that we support "console=ttySAx" where "x" is either 0 or 1.
+ * Which serial port this ends up being depends on the machine you're
+ * running this kernel on.  I'm not convinced that this is a good idea,
+ * but that's the way it traditionally works.
+ *
+ * Note that NanoEngine UART3 becomes UART2, and UART2 is no longer
+ * used here.
+ */
+static void __init sa1100_init_ports(void)
+{
+       static int first = 1;
+       int i;
+
+       if (!first)
+               return;
+       first = 0;
+
+       for (i = 0; i < NR_PORTS; i++) {
+               sa1100_ports[i].port.uartclk   = 3686400;
+               sa1100_ports[i].port.ops       = &sa1100_pops;
+               sa1100_ports[i].port.fifosize  = 8;
+               sa1100_ports[i].port.line      = i;
+               sa1100_ports[i].port.iotype    = UPIO_MEM;
+               init_timer(&sa1100_ports[i].timer);
+               sa1100_ports[i].timer.function = sa1100_timeout;
+               sa1100_ports[i].timer.data     = (unsigned long)&sa1100_ports[i];
+       }
+
+       /*
+        * make transmit lines outputs, so that when the port
+        * is closed, the output is in the MARK state.
+        */
+       PPDR |= PPC_TXD1 | PPC_TXD3;
+       PPSR |= PPC_TXD1 | PPC_TXD3;
+}
+
+void __devinit sa1100_register_uart_fns(struct sa1100_port_fns *fns)
+{
+       if (fns->get_mctrl)
+               sa1100_pops.get_mctrl = fns->get_mctrl;
+       if (fns->set_mctrl)
+               sa1100_pops.set_mctrl = fns->set_mctrl;
+
+       sa1100_pops.pm       = fns->pm;
+       sa1100_pops.set_wake = fns->set_wake;
+}
+
+void __init sa1100_register_uart(int idx, int port)
+{
+       if (idx >= NR_PORTS) {
+               printk(KERN_ERR "%s: bad index number %d\n", __func__, idx);
+               return;
+       }
+
+       switch (port) {
+       case 1:
+               sa1100_ports[idx].port.membase = (void __iomem *)&Ser1UTCR0;
+               sa1100_ports[idx].port.mapbase = _Ser1UTCR0;
+               sa1100_ports[idx].port.irq     = IRQ_Ser1UART;
+               sa1100_ports[idx].port.flags   = UPF_BOOT_AUTOCONF;
+               break;
+
+       case 2:
+               sa1100_ports[idx].port.membase = (void __iomem *)&Ser2UTCR0;
+               sa1100_ports[idx].port.mapbase = _Ser2UTCR0;
+               sa1100_ports[idx].port.irq     = IRQ_Ser2ICP;
+               sa1100_ports[idx].port.flags   = UPF_BOOT_AUTOCONF;
+               break;
+
+       case 3:
+               sa1100_ports[idx].port.membase = (void __iomem *)&Ser3UTCR0;
+               sa1100_ports[idx].port.mapbase = _Ser3UTCR0;
+               sa1100_ports[idx].port.irq     = IRQ_Ser3UART;
+               sa1100_ports[idx].port.flags   = UPF_BOOT_AUTOCONF;
+               break;
+
+       default:
+               printk(KERN_ERR "%s: bad port number %d\n", __func__, port);
+       }
+}
+
+
+#ifdef CONFIG_SERIAL_SA1100_CONSOLE
+static void sa1100_console_putchar(struct uart_port *port, int ch)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+
+       while (!(UART_GET_UTSR1(sport) & UTSR1_TNF))
+               barrier();
+       UART_PUT_CHAR(sport, ch);
+}
+
+/*
+ * Interrupts are disabled on entering
+ */
+static void
+sa1100_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct sa1100_port *sport = &sa1100_ports[co->index];
+       unsigned int old_utcr3, status;
+
+       /*
+        *      First, save UTCR3 and then disable interrupts
+        */
+       old_utcr3 = UART_GET_UTCR3(sport);
+       UART_PUT_UTCR3(sport, (old_utcr3 & ~(UTCR3_RIE | UTCR3_TIE)) |
+                               UTCR3_TXE);
+
+       uart_console_write(&sport->port, s, count, sa1100_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore UTCR3
+        */
+       do {
+               status = UART_GET_UTSR1(sport);
+       } while (status & UTSR1_TBY);
+       UART_PUT_UTCR3(sport, old_utcr3);
+}
+
+/*
+ * If the port was already initialised (eg, by a boot loader),
+ * try to determine the current setup.
+ */
+static void __init
+sa1100_console_get_options(struct sa1100_port *sport, int *baud,
+                          int *parity, int *bits)
+{
+       unsigned int utcr3;
+
+       utcr3 = UART_GET_UTCR3(sport) & (UTCR3_RXE | UTCR3_TXE);
+       if (utcr3 == (UTCR3_RXE | UTCR3_TXE)) {
+               /* ok, the port was enabled */
+               unsigned int utcr0, quot;
+
+               utcr0 = UART_GET_UTCR0(sport);
+
+               *parity = 'n';
+               if (utcr0 & UTCR0_PE) {
+                       if (utcr0 & UTCR0_OES)
+                               *parity = 'e';
+                       else
+                               *parity = 'o';
+               }
+
+               if (utcr0 & UTCR0_DSS)
+                       *bits = 8;
+               else
+                       *bits = 7;
+
+               quot = UART_GET_UTCR2(sport) | UART_GET_UTCR1(sport) << 8;
+               quot &= 0xfff;
+               *baud = sport->port.uartclk / (16 * (quot + 1));
+       }
+}
+
+static int __init
+sa1100_console_setup(struct console *co, char *options)
+{
+       struct sa1100_port *sport;
+       int baud = 9600;
+       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.
+        */
+       if (co->index == -1 || co->index >= NR_PORTS)
+               co->index = 0;
+       sport = &sa1100_ports[co->index];
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               sa1100_console_get_options(sport, &baud, &parity, &bits);
+
+       return uart_set_options(&sport->port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver sa1100_reg;
+static struct console sa1100_console = {
+       .name           = "ttySA",
+       .write          = sa1100_console_write,
+       .device         = uart_console_device,
+       .setup          = sa1100_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &sa1100_reg,
+};
+
+static int __init sa1100_rs_console_init(void)
+{
+       sa1100_init_ports();
+       register_console(&sa1100_console);
+       return 0;
+}
+console_initcall(sa1100_rs_console_init);
+
+#define SA1100_CONSOLE &sa1100_console
+#else
+#define SA1100_CONSOLE NULL
+#endif
+
+static struct uart_driver sa1100_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "ttySA",
+       .dev_name               = "ttySA",
+       .major                  = SERIAL_SA1100_MAJOR,
+       .minor                  = MINOR_START,
+       .nr                     = NR_PORTS,
+       .cons                   = SA1100_CONSOLE,
+};
+
+static int sa1100_serial_suspend(struct platform_device *dev, pm_message_t state)
+{
+       struct sa1100_port *sport = platform_get_drvdata(dev);
+
+       if (sport)
+               uart_suspend_port(&sa1100_reg, &sport->port);
+
+       return 0;
+}
+
+static int sa1100_serial_resume(struct platform_device *dev)
+{
+       struct sa1100_port *sport = platform_get_drvdata(dev);
+
+       if (sport)
+               uart_resume_port(&sa1100_reg, &sport->port);
+
+       return 0;
+}
+
+static int sa1100_serial_probe(struct platform_device *dev)
+{
+       struct resource *res = dev->resource;
+       int i;
+
+       for (i = 0; i < dev->num_resources; i++, res++)
+               if (res->flags & IORESOURCE_MEM)
+                       break;
+
+       if (i < dev->num_resources) {
+               for (i = 0; i < NR_PORTS; i++) {
+                       if (sa1100_ports[i].port.mapbase != res->start)
+                               continue;
+
+                       sa1100_ports[i].port.dev = &dev->dev;
+                       uart_add_one_port(&sa1100_reg, &sa1100_ports[i].port);
+                       platform_set_drvdata(dev, &sa1100_ports[i]);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static int sa1100_serial_remove(struct platform_device *pdev)
+{
+       struct sa1100_port *sport = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+
+       if (sport)
+               uart_remove_one_port(&sa1100_reg, &sport->port);
+
+       return 0;
+}
+
+static struct platform_driver sa11x0_serial_driver = {
+       .probe          = sa1100_serial_probe,
+       .remove         = sa1100_serial_remove,
+       .suspend        = sa1100_serial_suspend,
+       .resume         = sa1100_serial_resume,
+       .driver         = {
+               .name   = "sa11x0-uart",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init sa1100_serial_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "Serial: SA11x0 driver\n");
+
+       sa1100_init_ports();
+
+       ret = uart_register_driver(&sa1100_reg);
+       if (ret == 0) {
+               ret = platform_driver_register(&sa11x0_serial_driver);
+               if (ret)
+                       uart_unregister_driver(&sa1100_reg);
+       }
+       return ret;
+}
+
+static void __exit sa1100_serial_exit(void)
+{
+       platform_driver_unregister(&sa11x0_serial_driver);
+       uart_unregister_driver(&sa1100_reg);
+}
+
+module_init(sa1100_serial_init);
+module_exit(sa1100_serial_exit);
+
+MODULE_AUTHOR("Deep Blue Solutions Ltd");
+MODULE_DESCRIPTION("SA1100 generic serial port driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_SA1100_MAJOR);
+MODULE_ALIAS("platform:sa11x0-uart");
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
new file mode 100644 (file)
index 0000000..7ac2bf5
--- /dev/null
@@ -0,0 +1,1487 @@
+/* linux/drivers/serial/samsuing.c
+ *
+ * Driver core for Samsung SoC onboard UARTs.
+ *
+ * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+/* Hote on 2410 error handling
+ *
+ * The s3c2410 manual has a love/hate affair with the contents of the
+ * UERSTAT register in the UART blocks, and keeps marking some of the
+ * error bits as reserved. Having checked with the s3c2410x01,
+ * it copes with BREAKs properly, so I am happy to ignore the RESERVED
+ * feature from the latter versions of the manual.
+ *
+ * If it becomes aparrent that latter versions of the 2410 remove these
+ * bits, then action will have to be taken to differentiate the versions
+ * and change the policy on BREAK
+ *
+ * BJD, 04-Nov-2004
+*/
+
+#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+
+#include <asm/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/map.h>
+
+#include <plat/regs-serial.h>
+
+#include "samsung.h"
+
+/* UART name and device definitions */
+
+#define S3C24XX_SERIAL_NAME    "ttySAC"
+#define S3C24XX_SERIAL_MAJOR   204
+#define S3C24XX_SERIAL_MINOR   64
+
+/* macros to change one thing to another */
+
+#define tx_enabled(port) ((port)->unused[0])
+#define rx_enabled(port) ((port)->unused[1])
+
+/* flag to ignore all characters comming in */
+#define RXSTAT_DUMMY_READ (0x10000000)
+
+static inline struct s3c24xx_uart_port *to_ourport(struct uart_port *port)
+{
+       return container_of(port, struct s3c24xx_uart_port, port);
+}
+
+/* translate a port to the device name */
+
+static inline const char *s3c24xx_serial_portname(struct uart_port *port)
+{
+       return to_platform_device(port->dev)->name;
+}
+
+static int s3c24xx_serial_txempty_nofifo(struct uart_port *port)
+{
+       return (rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE);
+}
+
+static void s3c24xx_serial_rx_enable(struct uart_port *port)
+{
+       unsigned long flags;
+       unsigned int ucon, ufcon;
+       int count = 10000;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       while (--count && !s3c24xx_serial_txempty_nofifo(port))
+               udelay(100);
+
+       ufcon = rd_regl(port, S3C2410_UFCON);
+       ufcon |= S3C2410_UFCON_RESETRX;
+       wr_regl(port, S3C2410_UFCON, ufcon);
+
+       ucon = rd_regl(port, S3C2410_UCON);
+       ucon |= S3C2410_UCON_RXIRQMODE;
+       wr_regl(port, S3C2410_UCON, ucon);
+
+       rx_enabled(port) = 1;
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void s3c24xx_serial_rx_disable(struct uart_port *port)
+{
+       unsigned long flags;
+       unsigned int ucon;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       ucon = rd_regl(port, S3C2410_UCON);
+       ucon &= ~S3C2410_UCON_RXIRQMODE;
+       wr_regl(port, S3C2410_UCON, ucon);
+
+       rx_enabled(port) = 0;
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void s3c24xx_serial_stop_tx(struct uart_port *port)
+{
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+       if (tx_enabled(port)) {
+               disable_irq_nosync(ourport->tx_irq);
+               tx_enabled(port) = 0;
+               if (port->flags & UPF_CONS_FLOW)
+                       s3c24xx_serial_rx_enable(port);
+       }
+}
+
+static void s3c24xx_serial_start_tx(struct uart_port *port)
+{
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+       if (!tx_enabled(port)) {
+               if (port->flags & UPF_CONS_FLOW)
+                       s3c24xx_serial_rx_disable(port);
+
+               enable_irq(ourport->tx_irq);
+               tx_enabled(port) = 1;
+       }
+}
+
+
+static void s3c24xx_serial_stop_rx(struct uart_port *port)
+{
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+       if (rx_enabled(port)) {
+               dbg("s3c24xx_serial_stop_rx: port=%p\n", port);
+               disable_irq_nosync(ourport->rx_irq);
+               rx_enabled(port) = 0;
+       }
+}
+
+static void s3c24xx_serial_enable_ms(struct uart_port *port)
+{
+}
+
+static inline struct s3c24xx_uart_info *s3c24xx_port_to_info(struct uart_port *port)
+{
+       return to_ourport(port)->info;
+}
+
+static inline struct s3c2410_uartcfg *s3c24xx_port_to_cfg(struct uart_port *port)
+{
+       if (port->dev == NULL)
+               return NULL;
+
+       return (struct s3c2410_uartcfg *)port->dev->platform_data;
+}
+
+static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
+                                    unsigned long ufstat)
+{
+       struct s3c24xx_uart_info *info = ourport->info;
+
+       if (ufstat & info->rx_fifofull)
+               return info->fifosize;
+
+       return (ufstat & info->rx_fifomask) >> info->rx_fifoshift;
+}
+
+
+/* ? - where has parity gone?? */
+#define S3C2410_UERSTAT_PARITY (0x1000)
+
+static irqreturn_t
+s3c24xx_serial_rx_chars(int irq, void *dev_id)
+{
+       struct s3c24xx_uart_port *ourport = dev_id;
+       struct uart_port *port = &ourport->port;
+       struct tty_struct *tty = port->state->port.tty;
+       unsigned int ufcon, ch, flag, ufstat, uerstat;
+       int max_count = 64;
+
+       while (max_count-- > 0) {
+               ufcon = rd_regl(port, S3C2410_UFCON);
+               ufstat = rd_regl(port, S3C2410_UFSTAT);
+
+               if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)
+                       break;
+
+               uerstat = rd_regl(port, S3C2410_UERSTAT);
+               ch = rd_regb(port, S3C2410_URXH);
+
+               if (port->flags & UPF_CONS_FLOW) {
+                       int txe = s3c24xx_serial_txempty_nofifo(port);
+
+                       if (rx_enabled(port)) {
+                               if (!txe) {
+                                       rx_enabled(port) = 0;
+                                       continue;
+                               }
+                       } else {
+                               if (txe) {
+                                       ufcon |= S3C2410_UFCON_RESETRX;
+                                       wr_regl(port, S3C2410_UFCON, ufcon);
+                                       rx_enabled(port) = 1;
+                                       goto out;
+                               }
+                               continue;
+                       }
+               }
+
+               /* insert the character into the buffer */
+
+               flag = TTY_NORMAL;
+               port->icount.rx++;
+
+               if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) {
+                       dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n",
+                           ch, uerstat);
+
+                       /* check for break */
+                       if (uerstat & S3C2410_UERSTAT_BREAK) {
+                               dbg("break!\n");
+                               port->icount.brk++;
+                               if (uart_handle_break(port))
+                                   goto ignore_char;
+                       }
+
+                       if (uerstat & S3C2410_UERSTAT_FRAME)
+                               port->icount.frame++;
+                       if (uerstat & S3C2410_UERSTAT_OVERRUN)
+                               port->icount.overrun++;
+
+                       uerstat &= port->read_status_mask;
+
+                       if (uerstat & S3C2410_UERSTAT_BREAK)
+                               flag = TTY_BREAK;
+                       else if (uerstat & S3C2410_UERSTAT_PARITY)
+                               flag = TTY_PARITY;
+                       else if (uerstat & (S3C2410_UERSTAT_FRAME |
+                                           S3C2410_UERSTAT_OVERRUN))
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(port, ch))
+                       goto ignore_char;
+
+               uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN,
+                                ch, flag);
+
+ ignore_char:
+               continue;
+       }
+       tty_flip_buffer_push(tty);
+
+ out:
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
+{
+       struct s3c24xx_uart_port *ourport = id;
+       struct uart_port *port = &ourport->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       int count = 256;
+
+       if (port->x_char) {
+               wr_regb(port, S3C2410_UTXH, port->x_char);
+               port->icount.tx++;
+               port->x_char = 0;
+               goto out;
+       }
+
+       /* if there isnt anything more to transmit, or the uart is now
+        * stopped, disable the uart and exit
+       */
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               s3c24xx_serial_stop_tx(port);
+               goto out;
+       }
+
+       /* try and drain the buffer... */
+
+       while (!uart_circ_empty(xmit) && count-- > 0) {
+               if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
+                       break;
+
+               wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit))
+               s3c24xx_serial_stop_tx(port);
+
+ out:
+       return IRQ_HANDLED;
+}
+
+static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port)
+{
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+       unsigned long ufstat = rd_regl(port, S3C2410_UFSTAT);
+       unsigned long ufcon = rd_regl(port, S3C2410_UFCON);
+
+       if (ufcon & S3C2410_UFCON_FIFOMODE) {
+               if ((ufstat & info->tx_fifomask) != 0 ||
+                   (ufstat & info->tx_fifofull))
+                       return 0;
+
+               return 1;
+       }
+
+       return s3c24xx_serial_txempty_nofifo(port);
+}
+
+/* no modem control lines */
+static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port)
+{
+       unsigned int umstat = rd_regb(port, S3C2410_UMSTAT);
+
+       if (umstat & S3C2410_UMSTAT_CTS)
+               return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+       else
+               return TIOCM_CAR | TIOCM_DSR;
+}
+
+static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       /* todo - possibly remove AFC and do manual CTS */
+}
+
+static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
+{
+       unsigned long flags;
+       unsigned int ucon;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       ucon = rd_regl(port, S3C2410_UCON);
+
+       if (break_state)
+               ucon |= S3C2410_UCON_SBREAK;
+       else
+               ucon &= ~S3C2410_UCON_SBREAK;
+
+       wr_regl(port, S3C2410_UCON, ucon);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void s3c24xx_serial_shutdown(struct uart_port *port)
+{
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+       if (ourport->tx_claimed) {
+               free_irq(ourport->tx_irq, ourport);
+               tx_enabled(port) = 0;
+               ourport->tx_claimed = 0;
+       }
+
+       if (ourport->rx_claimed) {
+               free_irq(ourport->rx_irq, ourport);
+               ourport->rx_claimed = 0;
+               rx_enabled(port) = 0;
+       }
+}
+
+
+static int s3c24xx_serial_startup(struct uart_port *port)
+{
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       int ret;
+
+       dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n",
+           port->mapbase, port->membase);
+
+       rx_enabled(port) = 1;
+
+       ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0,
+                         s3c24xx_serial_portname(port), ourport);
+
+       if (ret != 0) {
+               printk(KERN_ERR "cannot get irq %d\n", ourport->rx_irq);
+               return ret;
+       }
+
+       ourport->rx_claimed = 1;
+
+       dbg("requesting tx irq...\n");
+
+       tx_enabled(port) = 1;
+
+       ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0,
+                         s3c24xx_serial_portname(port), ourport);
+
+       if (ret) {
+               printk(KERN_ERR "cannot get irq %d\n", ourport->tx_irq);
+               goto err;
+       }
+
+       ourport->tx_claimed = 1;
+
+       dbg("s3c24xx_serial_startup ok\n");
+
+       /* the port reset code should have done the correct
+        * register setup for the port controls */
+
+       return ret;
+
+ err:
+       s3c24xx_serial_shutdown(port);
+       return ret;
+}
+
+/* power power management control */
+
+static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
+                             unsigned int old)
+{
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+       ourport->pm_level = level;
+
+       switch (level) {
+       case 3:
+               if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
+                       clk_disable(ourport->baudclk);
+
+               clk_disable(ourport->clk);
+               break;
+
+       case 0:
+               clk_enable(ourport->clk);
+
+               if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
+                       clk_enable(ourport->baudclk);
+
+               break;
+       default:
+               printk(KERN_ERR "s3c24xx_serial: unknown pm %d\n", level);
+       }
+}
+
+/* baud rate calculation
+ *
+ * The UARTs on the S3C2410/S3C2440 can take their clocks from a number
+ * of different sources, including the peripheral clock ("pclk") and an
+ * external clock ("uclk"). The S3C2440 also adds the core clock ("fclk")
+ * with a programmable extra divisor.
+ *
+ * The following code goes through the clock sources, and calculates the
+ * baud clocks (and the resultant actual baud rates) and then tries to
+ * pick the closest one and select that.
+ *
+*/
+
+
+#define MAX_CLKS (8)
+
+static struct s3c24xx_uart_clksrc tmp_clksrc = {
+       .name           = "pclk",
+       .min_baud       = 0,
+       .max_baud       = 0,
+       .divisor        = 1,
+};
+
+static inline int
+s3c24xx_serial_getsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
+{
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+
+       return (info->get_clksrc)(port, c);
+}
+
+static inline int
+s3c24xx_serial_setsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
+{
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+
+       return (info->set_clksrc)(port, c);
+}
+
+struct baud_calc {
+       struct s3c24xx_uart_clksrc      *clksrc;
+       unsigned int                     calc;
+       unsigned int                     divslot;
+       unsigned int                     quot;
+       struct clk                      *src;
+};
+
+static int s3c24xx_serial_calcbaud(struct baud_calc *calc,
+                                  struct uart_port *port,
+                                  struct s3c24xx_uart_clksrc *clksrc,
+                                  unsigned int baud)
+{
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       unsigned long rate;
+
+       calc->src = clk_get(port->dev, clksrc->name);
+       if (calc->src == NULL || IS_ERR(calc->src))
+               return 0;
+
+       rate = clk_get_rate(calc->src);
+       rate /= clksrc->divisor;
+
+       calc->clksrc = clksrc;
+
+       if (ourport->info->has_divslot) {
+               unsigned long div = rate / baud;
+
+               /* The UDIVSLOT register on the newer UARTs allows us to
+                * get a divisor adjustment of 1/16th on the baud clock.
+                *
+                * We don't keep the UDIVSLOT value (the 16ths we calculated
+                * by not multiplying the baud by 16) as it is easy enough
+                * to recalculate.
+                */
+
+               calc->quot = div / 16;
+               calc->calc = rate / div;
+       } else {
+               calc->quot = (rate + (8 * baud)) / (16 * baud);
+               calc->calc = (rate / (calc->quot * 16));
+       }
+
+       calc->quot--;
+       return 1;
+}
+
+static unsigned int s3c24xx_serial_getclk(struct uart_port *port,
+                                         struct s3c24xx_uart_clksrc **clksrc,
+                                         struct clk **clk,
+                                         unsigned int baud)
+{
+       struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
+       struct s3c24xx_uart_clksrc *clkp;
+       struct baud_calc res[MAX_CLKS];
+       struct baud_calc *resptr, *best, *sptr;
+       int i;
+
+       clkp = cfg->clocks;
+       best = NULL;
+
+       if (cfg->clocks_size < 2) {
+               if (cfg->clocks_size == 0)
+                       clkp = &tmp_clksrc;
+
+               /* check to see if we're sourcing fclk, and if so we're
+                * going to have to update the clock source
+                */
+
+               if (strcmp(clkp->name, "fclk") == 0) {
+                       struct s3c24xx_uart_clksrc src;
+
+                       s3c24xx_serial_getsource(port, &src);
+
+                       /* check that the port already using fclk, and if
+                        * not, then re-select fclk
+                        */
+
+                       if (strcmp(src.name, clkp->name) == 0) {
+                               s3c24xx_serial_setsource(port, clkp);
+                               s3c24xx_serial_getsource(port, &src);
+                       }
+
+                       clkp->divisor = src.divisor;
+               }
+
+               s3c24xx_serial_calcbaud(res, port, clkp, baud);
+               best = res;
+               resptr = best + 1;
+       } else {
+               resptr = res;
+
+               for (i = 0; i < cfg->clocks_size; i++, clkp++) {
+                       if (s3c24xx_serial_calcbaud(resptr, port, clkp, baud))
+                               resptr++;
+               }
+       }
+
+       /* ok, we now need to select the best clock we found */
+
+       if (!best) {
+               unsigned int deviation = (1<<30)|((1<<30)-1);
+               int calc_deviation;
+
+               for (sptr = res; sptr < resptr; sptr++) {
+                       calc_deviation = baud - sptr->calc;
+                       if (calc_deviation < 0)
+                               calc_deviation = -calc_deviation;
+
+                       if (calc_deviation < deviation) {
+                               best = sptr;
+                               deviation = calc_deviation;
+                       }
+               }
+       }
+
+       /* store results to pass back */
+
+       *clksrc = best->clksrc;
+       *clk    = best->src;
+
+       return best->quot;
+}
+
+/* udivslot_table[]
+ *
+ * This table takes the fractional value of the baud divisor and gives
+ * the recommended setting for the UDIVSLOT register.
+ */
+static u16 udivslot_table[16] = {
+       [0] = 0x0000,
+       [1] = 0x0080,
+       [2] = 0x0808,
+       [3] = 0x0888,
+       [4] = 0x2222,
+       [5] = 0x4924,
+       [6] = 0x4A52,
+       [7] = 0x54AA,
+       [8] = 0x5555,
+       [9] = 0xD555,
+       [10] = 0xD5D5,
+       [11] = 0xDDD5,
+       [12] = 0xDDDD,
+       [13] = 0xDFDD,
+       [14] = 0xDFDF,
+       [15] = 0xFFDF,
+};
+
+static void s3c24xx_serial_set_termios(struct uart_port *port,
+                                      struct ktermios *termios,
+                                      struct ktermios *old)
+{
+       struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       struct s3c24xx_uart_clksrc *clksrc = NULL;
+       struct clk *clk = NULL;
+       unsigned long flags;
+       unsigned int baud, quot;
+       unsigned int ulcon;
+       unsigned int umcon;
+       unsigned int udivslot = 0;
+
+       /*
+        * We don't support modem control lines.
+        */
+       termios->c_cflag &= ~(HUPCL | CMSPAR);
+       termios->c_cflag |= CLOCAL;
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+
+       baud = uart_get_baud_rate(port, termios, old, 0, 115200*8);
+
+       if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
+               quot = port->custom_divisor;
+       else
+               quot = s3c24xx_serial_getclk(port, &clksrc, &clk, baud);
+
+       /* check to see if we need  to change clock source */
+
+       if (ourport->clksrc != clksrc || ourport->baudclk != clk) {
+               dbg("selecting clock %p\n", clk);
+               s3c24xx_serial_setsource(port, clksrc);
+
+               if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) {
+                       clk_disable(ourport->baudclk);
+                       ourport->baudclk  = NULL;
+               }
+
+               clk_enable(clk);
+
+               ourport->clksrc = clksrc;
+               ourport->baudclk = clk;
+               ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;
+       }
+
+       if (ourport->info->has_divslot) {
+               unsigned int div = ourport->baudclk_rate / baud;
+
+               if (cfg->has_fracval) {
+                       udivslot = (div & 15);
+                       dbg("fracval = %04x\n", udivslot);
+               } else {
+                       udivslot = udivslot_table[div & 15];
+                       dbg("udivslot = %04x (div %d)\n", udivslot, div & 15);
+               }
+       }
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               dbg("config: 5bits/char\n");
+               ulcon = S3C2410_LCON_CS5;
+               break;
+       case CS6:
+               dbg("config: 6bits/char\n");
+               ulcon = S3C2410_LCON_CS6;
+               break;
+       case CS7:
+               dbg("config: 7bits/char\n");
+               ulcon = S3C2410_LCON_CS7;
+               break;
+       case CS8:
+       default:
+               dbg("config: 8bits/char\n");
+               ulcon = S3C2410_LCON_CS8;
+               break;
+       }
+
+       /* preserve original lcon IR settings */
+       ulcon |= (cfg->ulcon & S3C2410_LCON_IRM);
+
+       if (termios->c_cflag & CSTOPB)
+               ulcon |= S3C2410_LCON_STOPB;
+
+       umcon = (termios->c_cflag & CRTSCTS) ? S3C2410_UMCOM_AFC : 0;
+
+       if (termios->c_cflag & PARENB) {
+               if (termios->c_cflag & PARODD)
+                       ulcon |= S3C2410_LCON_PODD;
+               else
+                       ulcon |= S3C2410_LCON_PEVEN;
+       } else {
+               ulcon |= S3C2410_LCON_PNONE;
+       }
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       dbg("setting ulcon to %08x, brddiv to %d, udivslot %08x\n",
+           ulcon, quot, udivslot);
+
+       wr_regl(port, S3C2410_ULCON, ulcon);
+       wr_regl(port, S3C2410_UBRDIV, quot);
+       wr_regl(port, S3C2410_UMCON, umcon);
+
+       if (ourport->info->has_divslot)
+               wr_regl(port, S3C2443_DIVSLOT, udivslot);
+
+       dbg("uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n",
+           rd_regl(port, S3C2410_ULCON),
+           rd_regl(port, S3C2410_UCON),
+           rd_regl(port, S3C2410_UFCON));
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       /*
+        * Which character status flags are we interested in?
+        */
+       port->read_status_mask = S3C2410_UERSTAT_OVERRUN;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_PARITY;
+
+       /*
+        * Which character status flags should we ignore?
+        */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= S3C2410_UERSTAT_OVERRUN;
+       if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= S3C2410_UERSTAT_FRAME;
+
+       /*
+        * Ignore all characters if CREAD is not set.
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               port->ignore_status_mask |= RXSTAT_DUMMY_READ;
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *s3c24xx_serial_type(struct uart_port *port)
+{
+       switch (port->type) {
+       case PORT_S3C2410:
+               return "S3C2410";
+       case PORT_S3C2440:
+               return "S3C2440";
+       case PORT_S3C2412:
+               return "S3C2412";
+       case PORT_S3C6400:
+               return "S3C6400/10";
+       default:
+               return NULL;
+       }
+}
+
+#define MAP_SIZE (0x100)
+
+static void s3c24xx_serial_release_port(struct uart_port *port)
+{
+       release_mem_region(port->mapbase, MAP_SIZE);
+}
+
+static int s3c24xx_serial_request_port(struct uart_port *port)
+{
+       const char *name = s3c24xx_serial_portname(port);
+       return request_mem_region(port->mapbase, MAP_SIZE, name) ? 0 : -EBUSY;
+}
+
+static void s3c24xx_serial_config_port(struct uart_port *port, int flags)
+{
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+
+       if (flags & UART_CONFIG_TYPE &&
+           s3c24xx_serial_request_port(port) == 0)
+               port->type = info->type;
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int
+s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+
+       if (ser->type != PORT_UNKNOWN && ser->type != info->type)
+               return -EINVAL;
+
+       return 0;
+}
+
+
+#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
+
+static struct console s3c24xx_serial_console;
+
+#define S3C24XX_SERIAL_CONSOLE &s3c24xx_serial_console
+#else
+#define S3C24XX_SERIAL_CONSOLE NULL
+#endif
+
+static struct uart_ops s3c24xx_serial_ops = {
+       .pm             = s3c24xx_serial_pm,
+       .tx_empty       = s3c24xx_serial_tx_empty,
+       .get_mctrl      = s3c24xx_serial_get_mctrl,
+       .set_mctrl      = s3c24xx_serial_set_mctrl,
+       .stop_tx        = s3c24xx_serial_stop_tx,
+       .start_tx       = s3c24xx_serial_start_tx,
+       .stop_rx        = s3c24xx_serial_stop_rx,
+       .enable_ms      = s3c24xx_serial_enable_ms,
+       .break_ctl      = s3c24xx_serial_break_ctl,
+       .startup        = s3c24xx_serial_startup,
+       .shutdown       = s3c24xx_serial_shutdown,
+       .set_termios    = s3c24xx_serial_set_termios,
+       .type           = s3c24xx_serial_type,
+       .release_port   = s3c24xx_serial_release_port,
+       .request_port   = s3c24xx_serial_request_port,
+       .config_port    = s3c24xx_serial_config_port,
+       .verify_port    = s3c24xx_serial_verify_port,
+};
+
+
+static struct uart_driver s3c24xx_uart_drv = {
+       .owner          = THIS_MODULE,
+       .dev_name       = "s3c2410_serial",
+       .nr             = CONFIG_SERIAL_SAMSUNG_UARTS,
+       .cons           = S3C24XX_SERIAL_CONSOLE,
+       .driver_name    = S3C24XX_SERIAL_NAME,
+       .major          = S3C24XX_SERIAL_MAJOR,
+       .minor          = S3C24XX_SERIAL_MINOR,
+};
+
+static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
+       [0] = {
+               .port = {
+                       .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),
+                       .iotype         = UPIO_MEM,
+                       .irq            = IRQ_S3CUART_RX0,
+                       .uartclk        = 0,
+                       .fifosize       = 16,
+                       .ops            = &s3c24xx_serial_ops,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 0,
+               }
+       },
+       [1] = {
+               .port = {
+                       .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock),
+                       .iotype         = UPIO_MEM,
+                       .irq            = IRQ_S3CUART_RX1,
+                       .uartclk        = 0,
+                       .fifosize       = 16,
+                       .ops            = &s3c24xx_serial_ops,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 1,
+               }
+       },
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 2
+
+       [2] = {
+               .port = {
+                       .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock),
+                       .iotype         = UPIO_MEM,
+                       .irq            = IRQ_S3CUART_RX2,
+                       .uartclk        = 0,
+                       .fifosize       = 16,
+                       .ops            = &s3c24xx_serial_ops,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 2,
+               }
+       },
+#endif
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 3
+       [3] = {
+               .port = {
+                       .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock),
+                       .iotype         = UPIO_MEM,
+                       .irq            = IRQ_S3CUART_RX3,
+                       .uartclk        = 0,
+                       .fifosize       = 16,
+                       .ops            = &s3c24xx_serial_ops,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 3,
+               }
+       }
+#endif
+};
+
+/* s3c24xx_serial_resetport
+ *
+ * wrapper to call the specific reset for this port (reset the fifos
+ * and the settings)
+*/
+
+static inline int s3c24xx_serial_resetport(struct uart_port *port,
+                                          struct s3c2410_uartcfg *cfg)
+{
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+
+       return (info->reset_port)(port, cfg);
+}
+
+
+#ifdef CONFIG_CPU_FREQ
+
+static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb,
+                                            unsigned long val, void *data)
+{
+       struct s3c24xx_uart_port *port;
+       struct uart_port *uport;
+
+       port = container_of(nb, struct s3c24xx_uart_port, freq_transition);
+       uport = &port->port;
+
+       /* check to see if port is enabled */
+
+       if (port->pm_level != 0)
+               return 0;
+
+       /* try and work out if the baudrate is changing, we can detect
+        * a change in rate, but we do not have support for detecting
+        * a disturbance in the clock-rate over the change.
+        */
+
+       if (IS_ERR(port->clk))
+               goto exit;
+
+       if (port->baudclk_rate == clk_get_rate(port->clk))
+               goto exit;
+
+       if (val == CPUFREQ_PRECHANGE) {
+               /* we should really shut the port down whilst the
+                * frequency change is in progress. */
+
+       } else if (val == CPUFREQ_POSTCHANGE) {
+               struct ktermios *termios;
+               struct tty_struct *tty;
+
+               if (uport->state == NULL)
+                       goto exit;
+
+               tty = uport->state->port.tty;
+
+               if (tty == NULL)
+                       goto exit;
+
+               termios = tty->termios;
+
+               if (termios == NULL) {
+                       printk(KERN_WARNING "%s: no termios?\n", __func__);
+                       goto exit;
+               }
+
+               s3c24xx_serial_set_termios(uport, termios, NULL);
+       }
+
+ exit:
+       return 0;
+}
+
+static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
+{
+       port->freq_transition.notifier_call = s3c24xx_serial_cpufreq_transition;
+
+       return cpufreq_register_notifier(&port->freq_transition,
+                                        CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
+{
+       cpufreq_unregister_notifier(&port->freq_transition,
+                                   CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+#else
+static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
+{
+       return 0;
+}
+
+static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
+{
+}
+#endif
+
+/* s3c24xx_serial_init_port
+ *
+ * initialise a single serial port from the platform device given
+ */
+
+static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
+                                   struct s3c24xx_uart_info *info,
+                                   struct platform_device *platdev)
+{
+       struct uart_port *port = &ourport->port;
+       struct s3c2410_uartcfg *cfg;
+       struct resource *res;
+       int ret;
+
+       dbg("s3c24xx_serial_init_port: port=%p, platdev=%p\n", port, platdev);
+
+       if (platdev == NULL)
+               return -ENODEV;
+
+       cfg = s3c24xx_dev_to_cfg(&platdev->dev);
+
+       if (port->mapbase != 0)
+               return 0;
+
+       if (cfg->hwport > CONFIG_SERIAL_SAMSUNG_UARTS) {
+               printk(KERN_ERR "%s: port %d bigger than %d\n", __func__,
+                      cfg->hwport, CONFIG_SERIAL_SAMSUNG_UARTS);
+               return -ERANGE;
+       }
+
+       /* setup info for port */
+       port->dev       = &platdev->dev;
+       ourport->info   = info;
+
+       /* copy the info in from provided structure */
+       ourport->port.fifosize = info->fifosize;
+
+       dbg("s3c24xx_serial_init_port: %p (hw %d)...\n", port, cfg->hwport);
+
+       port->uartclk = 1;
+
+       if (cfg->uart_flags & UPF_CONS_FLOW) {
+               dbg("s3c24xx_serial_init_port: enabling flow control\n");
+               port->flags |= UPF_CONS_FLOW;
+       }
+
+       /* sort our the physical and virtual addresses for each UART */
+
+       res = platform_get_resource(platdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               printk(KERN_ERR "failed to find memory resource for uart\n");
+               return -EINVAL;
+       }
+
+       dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);
+
+       port->mapbase = res->start;
+       port->membase = S3C_VA_UART + (res->start & 0xfffff);
+       ret = platform_get_irq(platdev, 0);
+       if (ret < 0)
+               port->irq = 0;
+       else {
+               port->irq = ret;
+               ourport->rx_irq = ret;
+               ourport->tx_irq = ret + 1;
+       }
+       
+       ret = platform_get_irq(platdev, 1);
+       if (ret > 0)
+               ourport->tx_irq = ret;
+
+       ourport->clk    = clk_get(&platdev->dev, "uart");
+
+       dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n",
+           port->mapbase, port->membase, port->irq,
+           ourport->rx_irq, ourport->tx_irq, port->uartclk);
+
+       /* reset the fifos (and setup the uart) */
+       s3c24xx_serial_resetport(port, cfg);
+       return 0;
+}
+
+static ssize_t s3c24xx_serial_show_clksrc(struct device *dev,
+                                         struct device_attribute *attr,
+                                         char *buf)
+{
+       struct uart_port *port = s3c24xx_dev_to_port(dev);
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+       return snprintf(buf, PAGE_SIZE, "* %s\n", ourport->clksrc->name);
+}
+
+static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL);
+
+/* Device driver serial port probe */
+
+static int probe_index;
+
+int s3c24xx_serial_probe(struct platform_device *dev,
+                        struct s3c24xx_uart_info *info)
+{
+       struct s3c24xx_uart_port *ourport;
+       int ret;
+
+       dbg("s3c24xx_serial_probe(%p, %p) %d\n", dev, info, probe_index);
+
+       ourport = &s3c24xx_serial_ports[probe_index];
+       probe_index++;
+
+       dbg("%s: initialising port %p...\n", __func__, ourport);
+
+       ret = s3c24xx_serial_init_port(ourport, info, dev);
+       if (ret < 0)
+               goto probe_err;
+
+       dbg("%s: adding port\n", __func__);
+       uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
+       platform_set_drvdata(dev, &ourport->port);
+
+       ret = device_create_file(&dev->dev, &dev_attr_clock_source);
+       if (ret < 0)
+               printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__);
+
+       ret = s3c24xx_serial_cpufreq_register(ourport);
+       if (ret < 0)
+               dev_err(&dev->dev, "failed to add cpufreq notifier\n");
+
+       return 0;
+
+ probe_err:
+       return ret;
+}
+
+EXPORT_SYMBOL_GPL(s3c24xx_serial_probe);
+
+int __devexit s3c24xx_serial_remove(struct platform_device *dev)
+{
+       struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
+
+       if (port) {
+               s3c24xx_serial_cpufreq_deregister(to_ourport(port));
+               device_remove_file(&dev->dev, &dev_attr_clock_source);
+               uart_remove_one_port(&s3c24xx_uart_drv, port);
+       }
+
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(s3c24xx_serial_remove);
+
+/* UART power management code */
+
+#ifdef CONFIG_PM
+
+static int s3c24xx_serial_suspend(struct platform_device *dev, pm_message_t state)
+{
+       struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
+
+       if (port)
+               uart_suspend_port(&s3c24xx_uart_drv, port);
+
+       return 0;
+}
+
+static int s3c24xx_serial_resume(struct platform_device *dev)
+{
+       struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+       if (port) {
+               clk_enable(ourport->clk);
+               s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port));
+               clk_disable(ourport->clk);
+
+               uart_resume_port(&s3c24xx_uart_drv, port);
+       }
+
+       return 0;
+}
+#endif
+
+int s3c24xx_serial_init(struct platform_driver *drv,
+                       struct s3c24xx_uart_info *info)
+{
+       dbg("s3c24xx_serial_init(%p,%p)\n", drv, info);
+
+#ifdef CONFIG_PM
+       drv->suspend = s3c24xx_serial_suspend;
+       drv->resume = s3c24xx_serial_resume;
+#endif
+
+       return platform_driver_register(drv);
+}
+
+EXPORT_SYMBOL_GPL(s3c24xx_serial_init);
+
+/* module initialisation code */
+
+static int __init s3c24xx_serial_modinit(void)
+{
+       int ret;
+
+       ret = uart_register_driver(&s3c24xx_uart_drv);
+       if (ret < 0) {
+               printk(KERN_ERR "failed to register UART driver\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static void __exit s3c24xx_serial_modexit(void)
+{
+       uart_unregister_driver(&s3c24xx_uart_drv);
+}
+
+module_init(s3c24xx_serial_modinit);
+module_exit(s3c24xx_serial_modexit);
+
+/* Console code */
+
+#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
+
+static struct uart_port *cons_uart;
+
+static int
+s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon)
+{
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+       unsigned long ufstat, utrstat;
+
+       if (ufcon & S3C2410_UFCON_FIFOMODE) {
+               /* fifo mode - check amount of data in fifo registers... */
+
+               ufstat = rd_regl(port, S3C2410_UFSTAT);
+               return (ufstat & info->tx_fifofull) ? 0 : 1;
+       }
+
+       /* in non-fifo mode, we go and use the tx buffer empty */
+
+       utrstat = rd_regl(port, S3C2410_UTRSTAT);
+       return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0;
+}
+
+static void
+s3c24xx_serial_console_putchar(struct uart_port *port, int ch)
+{
+       unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
+       while (!s3c24xx_serial_console_txrdy(port, ufcon))
+               barrier();
+       wr_regb(cons_uart, S3C2410_UTXH, ch);
+}
+
+static void
+s3c24xx_serial_console_write(struct console *co, const char *s,
+                            unsigned int count)
+{
+       uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar);
+}
+
+static void __init
+s3c24xx_serial_get_options(struct uart_port *port, int *baud,
+                          int *parity, int *bits)
+{
+       struct s3c24xx_uart_clksrc clksrc;
+       struct clk *clk;
+       unsigned int ulcon;
+       unsigned int ucon;
+       unsigned int ubrdiv;
+       unsigned long rate;
+
+       ulcon  = rd_regl(port, S3C2410_ULCON);
+       ucon   = rd_regl(port, S3C2410_UCON);
+       ubrdiv = rd_regl(port, S3C2410_UBRDIV);
+
+       dbg("s3c24xx_serial_get_options: port=%p\n"
+           "registers: ulcon=%08x, ucon=%08x, ubdriv=%08x\n",
+           port, ulcon, ucon, ubrdiv);
+
+       if ((ucon & 0xf) != 0) {
+               /* consider the serial port configured if the tx/rx mode set */
+
+               switch (ulcon & S3C2410_LCON_CSMASK) {
+               case S3C2410_LCON_CS5:
+                       *bits = 5;
+                       break;
+               case S3C2410_LCON_CS6:
+                       *bits = 6;
+                       break;
+               case S3C2410_LCON_CS7:
+                       *bits = 7;
+                       break;
+               default:
+               case S3C2410_LCON_CS8:
+                       *bits = 8;
+                       break;
+               }
+
+               switch (ulcon & S3C2410_LCON_PMASK) {
+               case S3C2410_LCON_PEVEN:
+                       *parity = 'e';
+                       break;
+
+               case S3C2410_LCON_PODD:
+                       *parity = 'o';
+                       break;
+
+               case S3C2410_LCON_PNONE:
+               default:
+                       *parity = 'n';
+               }
+
+               /* now calculate the baud rate */
+
+               s3c24xx_serial_getsource(port, &clksrc);
+
+               clk = clk_get(port->dev, clksrc.name);
+               if (!IS_ERR(clk) && clk != NULL)
+                       rate = clk_get_rate(clk) / clksrc.divisor;
+               else
+                       rate = 1;
+
+
+               *baud = rate / (16 * (ubrdiv + 1));
+               dbg("calculated baud %d\n", *baud);
+       }
+
+}
+
+/* s3c24xx_serial_init_ports
+ *
+ * initialise the serial ports from the machine provided initialisation
+ * data.
+*/
+
+static int s3c24xx_serial_init_ports(struct s3c24xx_uart_info **info)
+{
+       struct s3c24xx_uart_port *ptr = s3c24xx_serial_ports;
+       struct platform_device **platdev_ptr;
+       int i;
+
+       dbg("s3c24xx_serial_init_ports: initialising ports...\n");
+
+       platdev_ptr = s3c24xx_uart_devs;
+
+       for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++, ptr++, platdev_ptr++) {
+               s3c24xx_serial_init_port(ptr, info[i], *platdev_ptr);
+       }
+
+       return 0;
+}
+
+static int __init
+s3c24xx_serial_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       dbg("s3c24xx_serial_console_setup: co=%p (%d), %s\n",
+           co, co->index, options);
+
+       /* is this a valid port */
+
+       if (co->index == -1 || co->index >= CONFIG_SERIAL_SAMSUNG_UARTS)
+               co->index = 0;
+
+       port = &s3c24xx_serial_ports[co->index].port;
+
+       /* is the port configured? */
+
+       if (port->mapbase == 0x0) {
+               co->index = 0;
+               port = &s3c24xx_serial_ports[co->index].port;
+       }
+
+       cons_uart = port;
+
+       dbg("s3c24xx_serial_console_setup: port=%p (%d)\n", port, co->index);
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               s3c24xx_serial_get_options(port, &baud, &parity, &bits);
+
+       dbg("s3c24xx_serial_console_setup: baud %d\n", baud);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+/* s3c24xx_serial_initconsole
+ *
+ * initialise the console from one of the uart drivers
+*/
+
+static struct console s3c24xx_serial_console = {
+       .name           = S3C24XX_SERIAL_NAME,
+       .device         = uart_console_device,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .write          = s3c24xx_serial_console_write,
+       .setup          = s3c24xx_serial_console_setup
+};
+
+int s3c24xx_serial_initconsole(struct platform_driver *drv,
+                              struct s3c24xx_uart_info **info)
+
+{
+       struct platform_device *dev = s3c24xx_uart_devs[0];
+
+       dbg("s3c24xx_serial_initconsole\n");
+
+       /* select driver based on the cpu */
+
+       if (dev == NULL) {
+               printk(KERN_ERR "s3c24xx: no devices for console init\n");
+               return 0;
+       }
+
+       if (strcmp(dev->name, drv->driver.name) != 0)
+               return 0;
+
+       s3c24xx_serial_console.data = &s3c24xx_uart_drv;
+       s3c24xx_serial_init_ports(info);
+
+       register_console(&s3c24xx_serial_console);
+       return 0;
+}
+
+#endif /* CONFIG_SERIAL_SAMSUNG_CONSOLE */
+
+MODULE_DESCRIPTION("Samsung SoC Serial port driver");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/samsung.h b/drivers/tty/serial/samsung.h
new file mode 100644 (file)
index 0000000..0ac06a0
--- /dev/null
@@ -0,0 +1,120 @@
+/* linux/drivers/serial/samsung.h
+ *
+ * Driver for Samsung SoC onboard UARTs.
+ *
+ * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+struct s3c24xx_uart_info {
+       char                    *name;
+       unsigned int            type;
+       unsigned int            fifosize;
+       unsigned long           rx_fifomask;
+       unsigned long           rx_fifoshift;
+       unsigned long           rx_fifofull;
+       unsigned long           tx_fifomask;
+       unsigned long           tx_fifoshift;
+       unsigned long           tx_fifofull;
+
+       /* uart port features */
+
+       unsigned int            has_divslot:1;
+
+       /* clock source control */
+
+       int (*get_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk);
+       int (*set_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk);
+
+       /* uart controls */
+       int (*reset_port)(struct uart_port *, struct s3c2410_uartcfg *);
+};
+
+struct s3c24xx_uart_port {
+       unsigned char                   rx_claimed;
+       unsigned char                   tx_claimed;
+       unsigned int                    pm_level;
+       unsigned long                   baudclk_rate;
+
+       unsigned int                    rx_irq;
+       unsigned int                    tx_irq;
+
+       struct s3c24xx_uart_info        *info;
+       struct s3c24xx_uart_clksrc      *clksrc;
+       struct clk                      *clk;
+       struct clk                      *baudclk;
+       struct uart_port                port;
+
+#ifdef CONFIG_CPU_FREQ
+       struct notifier_block           freq_transition;
+#endif
+};
+
+/* conversion functions */
+
+#define s3c24xx_dev_to_port(__dev) (struct uart_port *)dev_get_drvdata(__dev)
+#define s3c24xx_dev_to_cfg(__dev) (struct s3c2410_uartcfg *)((__dev)->platform_data)
+
+/* register access controls */
+
+#define portaddr(port, reg) ((port)->membase + (reg))
+
+#define rd_regb(port, reg) (__raw_readb(portaddr(port, reg)))
+#define rd_regl(port, reg) (__raw_readl(portaddr(port, reg)))
+
+#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg))
+#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg))
+
+extern int s3c24xx_serial_probe(struct platform_device *dev,
+                               struct s3c24xx_uart_info *uart);
+
+extern int __devexit s3c24xx_serial_remove(struct platform_device *dev);
+
+extern int s3c24xx_serial_initconsole(struct platform_driver *drv,
+                                     struct s3c24xx_uart_info **uart);
+
+extern int s3c24xx_serial_init(struct platform_driver *drv,
+                              struct s3c24xx_uart_info *info);
+
+#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
+
+#define s3c24xx_console_init(__drv, __inf)                             \
+static int __init s3c_serial_console_init(void)                                \
+{                                                                      \
+       struct s3c24xx_uart_info *uinfo[CONFIG_SERIAL_SAMSUNG_UARTS];   \
+       int i;                                                          \
+                                                                       \
+       for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++)               \
+               uinfo[i] = __inf;                                       \
+       return s3c24xx_serial_initconsole(__drv, uinfo);                \
+}                                                                      \
+                                                                       \
+console_initcall(s3c_serial_console_init)
+
+#else
+#define s3c24xx_console_init(drv, inf) extern void no_console(void)
+#endif
+
+#ifdef CONFIG_SERIAL_SAMSUNG_DEBUG
+
+extern void printascii(const char *);
+
+static void dbg(const char *fmt, ...)
+{
+       va_list va;
+       char buff[256];
+
+       va_start(va, fmt);
+       vsprintf(buff, fmt, va);
+       va_end(va);
+
+       printascii(buff);
+}
+
+#else
+#define dbg(x...) do { } while (0)
+#endif
diff --git a/drivers/tty/serial/sb1250-duart.c b/drivers/tty/serial/sb1250-duart.c
new file mode 100644 (file)
index 0000000..a2f2b32
--- /dev/null
@@ -0,0 +1,976 @@
+/*
+ *     drivers/serial/sb1250-duart.c
+ *
+ *     Support for the asynchronous serial interface (DUART) included
+ *     in the BCM1250 and derived System-On-a-Chip (SOC) devices.
+ *
+ *     Copyright (c) 2007  Maciej W. Rozycki
+ *
+ *     Derived from drivers/char/sb1250_duart.c for which the following
+ *     copyright applies:
+ *
+ *     Copyright (c) 2000, 2001, 2002, 2003, 2004  Broadcom Corporation
+ *
+ *     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.
+ *
+ *     References:
+ *
+ *     "BCM1250/BCM1125/BCM1125H User Manual", Broadcom Corporation
+ */
+
+#if defined(CONFIG_SERIAL_SB1250_DUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/compiler.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/spinlock.h>
+#include <linux/sysrq.h>
+#include <linux/tty.h>
+#include <linux/types.h>
+
+#include <asm/atomic.h>
+#include <asm/io.h>
+#include <asm/war.h>
+
+#include <asm/sibyte/sb1250.h>
+#include <asm/sibyte/sb1250_uart.h>
+#include <asm/sibyte/swarm.h>
+
+
+#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
+#include <asm/sibyte/bcm1480_regs.h>
+#include <asm/sibyte/bcm1480_int.h>
+
+#define SBD_CHANREGS(line)     A_BCM1480_DUART_CHANREG((line), 0)
+#define SBD_CTRLREGS(line)     A_BCM1480_DUART_CTRLREG((line), 0)
+#define SBD_INT(line)          (K_BCM1480_INT_UART_0 + (line))
+
+#define DUART_CHANREG_SPACING  BCM1480_DUART_CHANREG_SPACING
+
+#define R_DUART_IMRREG(line)   R_BCM1480_DUART_IMRREG(line)
+#define R_DUART_INCHREG(line)  R_BCM1480_DUART_INCHREG(line)
+#define R_DUART_ISRREG(line)   R_BCM1480_DUART_ISRREG(line)
+
+#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
+#include <asm/sibyte/sb1250_regs.h>
+#include <asm/sibyte/sb1250_int.h>
+
+#define SBD_CHANREGS(line)     A_DUART_CHANREG((line), 0)
+#define SBD_CTRLREGS(line)     A_DUART_CTRLREG(0)
+#define SBD_INT(line)          (K_INT_UART_0 + (line))
+
+#else
+#error invalid SB1250 UART configuration
+
+#endif
+
+
+MODULE_AUTHOR("Maciej W. Rozycki <macro@linux-mips.org>");
+MODULE_DESCRIPTION("BCM1xxx on-chip DUART serial driver");
+MODULE_LICENSE("GPL");
+
+
+#define DUART_MAX_CHIP 2
+#define DUART_MAX_SIDE 2
+
+/*
+ * Per-port state.
+ */
+struct sbd_port {
+       struct sbd_duart        *duart;
+       struct uart_port        port;
+       unsigned char __iomem   *memctrl;
+       int                     tx_stopped;
+       int                     initialised;
+};
+
+/*
+ * Per-DUART state for the shared register space.
+ */
+struct sbd_duart {
+       struct sbd_port         sport[2];
+       unsigned long           mapctrl;
+       atomic_t                map_guard;
+};
+
+#define to_sport(uport) container_of(uport, struct sbd_port, port)
+
+static struct sbd_duart sbd_duarts[DUART_MAX_CHIP];
+
+
+/*
+ * Reading and writing SB1250 DUART registers.
+ *
+ * There are three register spaces: two per-channel ones and
+ * a shared one.  We have to define accessors appropriately.
+ * All registers are 64-bit and all but the Baud Rate Clock
+ * registers only define 8 least significant bits.  There is
+ * also a workaround to take into account.  Raw accessors use
+ * the full register width, but cooked ones truncate it
+ * intentionally so that the rest of the driver does not care.
+ */
+static u64 __read_sbdchn(struct sbd_port *sport, int reg)
+{
+       void __iomem *csr = sport->port.membase + reg;
+
+       return __raw_readq(csr);
+}
+
+static u64 __read_sbdshr(struct sbd_port *sport, int reg)
+{
+       void __iomem *csr = sport->memctrl + reg;
+
+       return __raw_readq(csr);
+}
+
+static void __write_sbdchn(struct sbd_port *sport, int reg, u64 value)
+{
+       void __iomem *csr = sport->port.membase + reg;
+
+       __raw_writeq(value, csr);
+}
+
+static void __write_sbdshr(struct sbd_port *sport, int reg, u64 value)
+{
+       void __iomem *csr = sport->memctrl + reg;
+
+       __raw_writeq(value, csr);
+}
+
+/*
+ * In bug 1956, we get glitches that can mess up uart registers.  This
+ * "read-mode-reg after any register access" is an accepted workaround.
+ */
+static void __war_sbd1956(struct sbd_port *sport)
+{
+       __read_sbdchn(sport, R_DUART_MODE_REG_1);
+       __read_sbdchn(sport, R_DUART_MODE_REG_2);
+}
+
+static unsigned char read_sbdchn(struct sbd_port *sport, int reg)
+{
+       unsigned char retval;
+
+       retval = __read_sbdchn(sport, reg);
+       if (SIBYTE_1956_WAR)
+               __war_sbd1956(sport);
+       return retval;
+}
+
+static unsigned char read_sbdshr(struct sbd_port *sport, int reg)
+{
+       unsigned char retval;
+
+       retval = __read_sbdshr(sport, reg);
+       if (SIBYTE_1956_WAR)
+               __war_sbd1956(sport);
+       return retval;
+}
+
+static void write_sbdchn(struct sbd_port *sport, int reg, unsigned int value)
+{
+       __write_sbdchn(sport, reg, value);
+       if (SIBYTE_1956_WAR)
+               __war_sbd1956(sport);
+}
+
+static void write_sbdshr(struct sbd_port *sport, int reg, unsigned int value)
+{
+       __write_sbdshr(sport, reg, value);
+       if (SIBYTE_1956_WAR)
+               __war_sbd1956(sport);
+}
+
+
+static int sbd_receive_ready(struct sbd_port *sport)
+{
+       return read_sbdchn(sport, R_DUART_STATUS) & M_DUART_RX_RDY;
+}
+
+static int sbd_receive_drain(struct sbd_port *sport)
+{
+       int loops = 10000;
+
+       while (sbd_receive_ready(sport) && --loops)
+               read_sbdchn(sport, R_DUART_RX_HOLD);
+       return loops;
+}
+
+static int __maybe_unused sbd_transmit_ready(struct sbd_port *sport)
+{
+       return read_sbdchn(sport, R_DUART_STATUS) & M_DUART_TX_RDY;
+}
+
+static int __maybe_unused sbd_transmit_drain(struct sbd_port *sport)
+{
+       int loops = 10000;
+
+       while (!sbd_transmit_ready(sport) && --loops)
+               udelay(2);
+       return loops;
+}
+
+static int sbd_transmit_empty(struct sbd_port *sport)
+{
+       return read_sbdchn(sport, R_DUART_STATUS) & M_DUART_TX_EMT;
+}
+
+static int sbd_line_drain(struct sbd_port *sport)
+{
+       int loops = 10000;
+
+       while (!sbd_transmit_empty(sport) && --loops)
+               udelay(2);
+       return loops;
+}
+
+
+static unsigned int sbd_tx_empty(struct uart_port *uport)
+{
+       struct sbd_port *sport = to_sport(uport);
+
+       return sbd_transmit_empty(sport) ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int sbd_get_mctrl(struct uart_port *uport)
+{
+       struct sbd_port *sport = to_sport(uport);
+       unsigned int mctrl, status;
+
+       status = read_sbdshr(sport, R_DUART_IN_PORT);
+       status >>= (uport->line) % 2;
+       mctrl = (!(status & M_DUART_IN_PIN0_VAL) ? TIOCM_CTS : 0) |
+               (!(status & M_DUART_IN_PIN4_VAL) ? TIOCM_CAR : 0) |
+               (!(status & M_DUART_RIN0_PIN) ? TIOCM_RNG : 0) |
+               (!(status & M_DUART_IN_PIN2_VAL) ? TIOCM_DSR : 0);
+       return mctrl;
+}
+
+static void sbd_set_mctrl(struct uart_port *uport, unsigned int mctrl)
+{
+       struct sbd_port *sport = to_sport(uport);
+       unsigned int clr = 0, set = 0, mode2;
+
+       if (mctrl & TIOCM_DTR)
+               set |= M_DUART_SET_OPR2;
+       else
+               clr |= M_DUART_CLR_OPR2;
+       if (mctrl & TIOCM_RTS)
+               set |= M_DUART_SET_OPR0;
+       else
+               clr |= M_DUART_CLR_OPR0;
+       clr <<= (uport->line) % 2;
+       set <<= (uport->line) % 2;
+
+       mode2 = read_sbdchn(sport, R_DUART_MODE_REG_2);
+       mode2 &= ~M_DUART_CHAN_MODE;
+       if (mctrl & TIOCM_LOOP)
+               mode2 |= V_DUART_CHAN_MODE_LCL_LOOP;
+       else
+               mode2 |= V_DUART_CHAN_MODE_NORMAL;
+
+       write_sbdshr(sport, R_DUART_CLEAR_OPR, clr);
+       write_sbdshr(sport, R_DUART_SET_OPR, set);
+       write_sbdchn(sport, R_DUART_MODE_REG_2, mode2);
+}
+
+static void sbd_stop_tx(struct uart_port *uport)
+{
+       struct sbd_port *sport = to_sport(uport);
+
+       write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS);
+       sport->tx_stopped = 1;
+};
+
+static void sbd_start_tx(struct uart_port *uport)
+{
+       struct sbd_port *sport = to_sport(uport);
+       unsigned int mask;
+
+       /* Enable tx interrupts.  */
+       mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2));
+       mask |= M_DUART_IMR_TX;
+       write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), mask);
+
+       /* Go!, go!, go!...  */
+       write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_EN);
+       sport->tx_stopped = 0;
+};
+
+static void sbd_stop_rx(struct uart_port *uport)
+{
+       struct sbd_port *sport = to_sport(uport);
+
+       write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), 0);
+};
+
+static void sbd_enable_ms(struct uart_port *uport)
+{
+       struct sbd_port *sport = to_sport(uport);
+
+       write_sbdchn(sport, R_DUART_AUXCTL_X,
+                    M_DUART_CIN_CHNG_ENA | M_DUART_CTS_CHNG_ENA);
+}
+
+static void sbd_break_ctl(struct uart_port *uport, int break_state)
+{
+       struct sbd_port *sport = to_sport(uport);
+
+       if (break_state == -1)
+               write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_START_BREAK);
+       else
+               write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_STOP_BREAK);
+}
+
+
+static void sbd_receive_chars(struct sbd_port *sport)
+{
+       struct uart_port *uport = &sport->port;
+       struct uart_icount *icount;
+       unsigned int status, ch, flag;
+       int count;
+
+       for (count = 16; count; count--) {
+               status = read_sbdchn(sport, R_DUART_STATUS);
+               if (!(status & M_DUART_RX_RDY))
+                       break;
+
+               ch = read_sbdchn(sport, R_DUART_RX_HOLD);
+
+               flag = TTY_NORMAL;
+
+               icount = &uport->icount;
+               icount->rx++;
+
+               if (unlikely(status &
+                            (M_DUART_RCVD_BRK | M_DUART_FRM_ERR |
+                             M_DUART_PARITY_ERR | M_DUART_OVRUN_ERR))) {
+                       if (status & M_DUART_RCVD_BRK) {
+                               icount->brk++;
+                               if (uart_handle_break(uport))
+                                       continue;
+                       } else if (status & M_DUART_FRM_ERR)
+                               icount->frame++;
+                       else if (status & M_DUART_PARITY_ERR)
+                               icount->parity++;
+                       if (status & M_DUART_OVRUN_ERR)
+                               icount->overrun++;
+
+                       status &= uport->read_status_mask;
+                       if (status & M_DUART_RCVD_BRK)
+                               flag = TTY_BREAK;
+                       else if (status & M_DUART_FRM_ERR)
+                               flag = TTY_FRAME;
+                       else if (status & M_DUART_PARITY_ERR)
+                               flag = TTY_PARITY;
+               }
+
+               if (uart_handle_sysrq_char(uport, ch))
+                       continue;
+
+               uart_insert_char(uport, status, M_DUART_OVRUN_ERR, ch, flag);
+       }
+
+       tty_flip_buffer_push(uport->state->port.tty);
+}
+
+static void sbd_transmit_chars(struct sbd_port *sport)
+{
+       struct uart_port *uport = &sport->port;
+       struct circ_buf *xmit = &sport->port.state->xmit;
+       unsigned int mask;
+       int stop_tx;
+
+       /* XON/XOFF chars.  */
+       if (sport->port.x_char) {
+               write_sbdchn(sport, R_DUART_TX_HOLD, sport->port.x_char);
+               sport->port.icount.tx++;
+               sport->port.x_char = 0;
+               return;
+       }
+
+       /* If nothing to do or stopped or hardware stopped.  */
+       stop_tx = (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port));
+
+       /* Send char.  */
+       if (!stop_tx) {
+               write_sbdchn(sport, R_DUART_TX_HOLD, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               sport->port.icount.tx++;
+
+               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+                       uart_write_wakeup(&sport->port);
+       }
+
+       /* Are we are done?  */
+       if (stop_tx || uart_circ_empty(xmit)) {
+               /* Disable tx interrupts.  */
+               mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2));
+               mask &= ~M_DUART_IMR_TX;
+               write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), mask);
+       }
+}
+
+static void sbd_status_handle(struct sbd_port *sport)
+{
+       struct uart_port *uport = &sport->port;
+       unsigned int delta;
+
+       delta = read_sbdshr(sport, R_DUART_INCHREG((uport->line) % 2));
+       delta >>= (uport->line) % 2;
+
+       if (delta & (M_DUART_IN_PIN0_VAL << S_DUART_IN_PIN_CHNG))
+               uart_handle_cts_change(uport, !(delta & M_DUART_IN_PIN0_VAL));
+
+       if (delta & (M_DUART_IN_PIN2_VAL << S_DUART_IN_PIN_CHNG))
+               uport->icount.dsr++;
+
+       if (delta & ((M_DUART_IN_PIN2_VAL | M_DUART_IN_PIN0_VAL) <<
+                    S_DUART_IN_PIN_CHNG))
+               wake_up_interruptible(&uport->state->port.delta_msr_wait);
+}
+
+static irqreturn_t sbd_interrupt(int irq, void *dev_id)
+{
+       struct sbd_port *sport = dev_id;
+       struct uart_port *uport = &sport->port;
+       irqreturn_t status = IRQ_NONE;
+       unsigned int intstat;
+       int count;
+
+       for (count = 16; count; count--) {
+               intstat = read_sbdshr(sport,
+                                     R_DUART_ISRREG((uport->line) % 2));
+               intstat &= read_sbdshr(sport,
+                                      R_DUART_IMRREG((uport->line) % 2));
+               intstat &= M_DUART_ISR_ALL;
+               if (!intstat)
+                       break;
+
+               if (intstat & M_DUART_ISR_RX)
+                       sbd_receive_chars(sport);
+               if (intstat & M_DUART_ISR_IN)
+                       sbd_status_handle(sport);
+               if (intstat & M_DUART_ISR_TX)
+                       sbd_transmit_chars(sport);
+
+               status = IRQ_HANDLED;
+       }
+
+       return status;
+}
+
+
+static int sbd_startup(struct uart_port *uport)
+{
+       struct sbd_port *sport = to_sport(uport);
+       unsigned int mode1;
+       int ret;
+
+       ret = request_irq(sport->port.irq, sbd_interrupt,
+                         IRQF_SHARED, "sb1250-duart", sport);
+       if (ret)
+               return ret;
+
+       /* Clear the receive FIFO.  */
+       sbd_receive_drain(sport);
+
+       /* Clear the interrupt registers.  */
+       write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT);
+       read_sbdshr(sport, R_DUART_INCHREG((uport->line) % 2));
+
+       /* Set rx/tx interrupt to FIFO available.  */
+       mode1 = read_sbdchn(sport, R_DUART_MODE_REG_1);
+       mode1 &= ~(M_DUART_RX_IRQ_SEL_RXFULL | M_DUART_TX_IRQ_SEL_TXEMPT);
+       write_sbdchn(sport, R_DUART_MODE_REG_1, mode1);
+
+       /* Disable tx, enable rx.  */
+       write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS | M_DUART_RX_EN);
+       sport->tx_stopped = 1;
+
+       /* Enable interrupts.  */
+       write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2),
+                    M_DUART_IMR_IN | M_DUART_IMR_RX);
+
+       return 0;
+}
+
+static void sbd_shutdown(struct uart_port *uport)
+{
+       struct sbd_port *sport = to_sport(uport);
+
+       write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS | M_DUART_RX_DIS);
+       sport->tx_stopped = 1;
+       free_irq(sport->port.irq, sport);
+}
+
+
+static void sbd_init_port(struct sbd_port *sport)
+{
+       struct uart_port *uport = &sport->port;
+
+       if (sport->initialised)
+               return;
+
+       /* There is no DUART reset feature, so just set some sane defaults.  */
+       write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_TX);
+       write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_RX);
+       write_sbdchn(sport, R_DUART_MODE_REG_1, V_DUART_BITS_PER_CHAR_8);
+       write_sbdchn(sport, R_DUART_MODE_REG_2, 0);
+       write_sbdchn(sport, R_DUART_FULL_CTL,
+                    V_DUART_INT_TIME(0) | V_DUART_SIG_FULL(15));
+       write_sbdchn(sport, R_DUART_OPCR_X, 0);
+       write_sbdchn(sport, R_DUART_AUXCTL_X, 0);
+       write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), 0);
+
+       sport->initialised = 1;
+}
+
+static void sbd_set_termios(struct uart_port *uport, struct ktermios *termios,
+                           struct ktermios *old_termios)
+{
+       struct sbd_port *sport = to_sport(uport);
+       unsigned int mode1 = 0, mode2 = 0, aux = 0;
+       unsigned int mode1mask = 0, mode2mask = 0, auxmask = 0;
+       unsigned int oldmode1, oldmode2, oldaux;
+       unsigned int baud, brg;
+       unsigned int command;
+
+       mode1mask |= ~(M_DUART_PARITY_MODE | M_DUART_PARITY_TYPE_ODD |
+                      M_DUART_BITS_PER_CHAR);
+       mode2mask |= ~M_DUART_STOP_BIT_LEN_2;
+       auxmask |= ~M_DUART_CTS_CHNG_ENA;
+
+       /* Byte size.  */
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+       case CS6:
+               /* Unsupported, leave unchanged.  */
+               mode1mask |= M_DUART_PARITY_MODE;
+               break;
+       case CS7:
+               mode1 |= V_DUART_BITS_PER_CHAR_7;
+               break;
+       case CS8:
+       default:
+               mode1 |= V_DUART_BITS_PER_CHAR_8;
+               break;
+       }
+
+       /* Parity and stop bits.  */
+       if (termios->c_cflag & CSTOPB)
+               mode2 |= M_DUART_STOP_BIT_LEN_2;
+       else
+               mode2 |= M_DUART_STOP_BIT_LEN_1;
+       if (termios->c_cflag & PARENB)
+               mode1 |= V_DUART_PARITY_MODE_ADD;
+       else
+               mode1 |= V_DUART_PARITY_MODE_NONE;
+       if (termios->c_cflag & PARODD)
+               mode1 |= M_DUART_PARITY_TYPE_ODD;
+       else
+               mode1 |= M_DUART_PARITY_TYPE_EVEN;
+
+       baud = uart_get_baud_rate(uport, termios, old_termios, 1200, 5000000);
+       brg = V_DUART_BAUD_RATE(baud);
+       /* The actual lower bound is 1221bps, so compensate.  */
+       if (brg > M_DUART_CLK_COUNTER)
+               brg = M_DUART_CLK_COUNTER;
+
+       uart_update_timeout(uport, termios->c_cflag, baud);
+
+       uport->read_status_mask = M_DUART_OVRUN_ERR;
+       if (termios->c_iflag & INPCK)
+               uport->read_status_mask |= M_DUART_FRM_ERR |
+                                          M_DUART_PARITY_ERR;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               uport->read_status_mask |= M_DUART_RCVD_BRK;
+
+       uport->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               uport->ignore_status_mask |= M_DUART_FRM_ERR |
+                                            M_DUART_PARITY_ERR;
+       if (termios->c_iflag & IGNBRK) {
+               uport->ignore_status_mask |= M_DUART_RCVD_BRK;
+               if (termios->c_iflag & IGNPAR)
+                       uport->ignore_status_mask |= M_DUART_OVRUN_ERR;
+       }
+
+       if (termios->c_cflag & CREAD)
+               command = M_DUART_RX_EN;
+       else
+               command = M_DUART_RX_DIS;
+
+       if (termios->c_cflag & CRTSCTS)
+               aux |= M_DUART_CTS_CHNG_ENA;
+       else
+               aux &= ~M_DUART_CTS_CHNG_ENA;
+
+       spin_lock(&uport->lock);
+
+       if (sport->tx_stopped)
+               command |= M_DUART_TX_DIS;
+       else
+               command |= M_DUART_TX_EN;
+
+       oldmode1 = read_sbdchn(sport, R_DUART_MODE_REG_1) & mode1mask;
+       oldmode2 = read_sbdchn(sport, R_DUART_MODE_REG_2) & mode2mask;
+       oldaux = read_sbdchn(sport, R_DUART_AUXCTL_X) & auxmask;
+
+       if (!sport->tx_stopped)
+               sbd_line_drain(sport);
+       write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS | M_DUART_RX_DIS);
+
+       write_sbdchn(sport, R_DUART_MODE_REG_1, mode1 | oldmode1);
+       write_sbdchn(sport, R_DUART_MODE_REG_2, mode2 | oldmode2);
+       write_sbdchn(sport, R_DUART_CLK_SEL, brg);
+       write_sbdchn(sport, R_DUART_AUXCTL_X, aux | oldaux);
+
+       write_sbdchn(sport, R_DUART_CMD, command);
+
+       spin_unlock(&uport->lock);
+}
+
+
+static const char *sbd_type(struct uart_port *uport)
+{
+       return "SB1250 DUART";
+}
+
+static void sbd_release_port(struct uart_port *uport)
+{
+       struct sbd_port *sport = to_sport(uport);
+       struct sbd_duart *duart = sport->duart;
+       int map_guard;
+
+       iounmap(sport->memctrl);
+       sport->memctrl = NULL;
+       iounmap(uport->membase);
+       uport->membase = NULL;
+
+       map_guard = atomic_add_return(-1, &duart->map_guard);
+       if (!map_guard)
+               release_mem_region(duart->mapctrl, DUART_CHANREG_SPACING);
+       release_mem_region(uport->mapbase, DUART_CHANREG_SPACING);
+}
+
+static int sbd_map_port(struct uart_port *uport)
+{
+       const char *err = KERN_ERR "sbd: Cannot map MMIO\n";
+       struct sbd_port *sport = to_sport(uport);
+       struct sbd_duart *duart = sport->duart;
+
+       if (!uport->membase)
+               uport->membase = ioremap_nocache(uport->mapbase,
+                                                DUART_CHANREG_SPACING);
+       if (!uport->membase) {
+               printk(err);
+               return -ENOMEM;
+       }
+
+       if (!sport->memctrl)
+               sport->memctrl = ioremap_nocache(duart->mapctrl,
+                                                DUART_CHANREG_SPACING);
+       if (!sport->memctrl) {
+               printk(err);
+               iounmap(uport->membase);
+               uport->membase = NULL;
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static int sbd_request_port(struct uart_port *uport)
+{
+       const char *err = KERN_ERR "sbd: Unable to reserve MMIO resource\n";
+       struct sbd_duart *duart = to_sport(uport)->duart;
+       int map_guard;
+       int ret = 0;
+
+       if (!request_mem_region(uport->mapbase, DUART_CHANREG_SPACING,
+                               "sb1250-duart")) {
+               printk(err);
+               return -EBUSY;
+       }
+       map_guard = atomic_add_return(1, &duart->map_guard);
+       if (map_guard == 1) {
+               if (!request_mem_region(duart->mapctrl, DUART_CHANREG_SPACING,
+                                       "sb1250-duart")) {
+                       atomic_add(-1, &duart->map_guard);
+                       printk(err);
+                       ret = -EBUSY;
+               }
+       }
+       if (!ret) {
+               ret = sbd_map_port(uport);
+               if (ret) {
+                       map_guard = atomic_add_return(-1, &duart->map_guard);
+                       if (!map_guard)
+                               release_mem_region(duart->mapctrl,
+                                                  DUART_CHANREG_SPACING);
+               }
+       }
+       if (ret) {
+               release_mem_region(uport->mapbase, DUART_CHANREG_SPACING);
+               return ret;
+       }
+       return 0;
+}
+
+static void sbd_config_port(struct uart_port *uport, int flags)
+{
+       struct sbd_port *sport = to_sport(uport);
+
+       if (flags & UART_CONFIG_TYPE) {
+               if (sbd_request_port(uport))
+                       return;
+
+               uport->type = PORT_SB1250_DUART;
+
+               sbd_init_port(sport);
+       }
+}
+
+static int sbd_verify_port(struct uart_port *uport, struct serial_struct *ser)
+{
+       int ret = 0;
+
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_SB1250_DUART)
+               ret = -EINVAL;
+       if (ser->irq != uport->irq)
+               ret = -EINVAL;
+       if (ser->baud_base != uport->uartclk / 16)
+               ret = -EINVAL;
+       return ret;
+}
+
+
+static const struct uart_ops sbd_ops = {
+       .tx_empty       = sbd_tx_empty,
+       .set_mctrl      = sbd_set_mctrl,
+       .get_mctrl      = sbd_get_mctrl,
+       .stop_tx        = sbd_stop_tx,
+       .start_tx       = sbd_start_tx,
+       .stop_rx        = sbd_stop_rx,
+       .enable_ms      = sbd_enable_ms,
+       .break_ctl      = sbd_break_ctl,
+       .startup        = sbd_startup,
+       .shutdown       = sbd_shutdown,
+       .set_termios    = sbd_set_termios,
+       .type           = sbd_type,
+       .release_port   = sbd_release_port,
+       .request_port   = sbd_request_port,
+       .config_port    = sbd_config_port,
+       .verify_port    = sbd_verify_port,
+};
+
+/* Initialize SB1250 DUART port structures.  */
+static void __init sbd_probe_duarts(void)
+{
+       static int probed;
+       int chip, side;
+       int max_lines, line;
+
+       if (probed)
+               return;
+
+       /* Set the number of available units based on the SOC type.  */
+       switch (soc_type) {
+       case K_SYS_SOC_TYPE_BCM1x55:
+       case K_SYS_SOC_TYPE_BCM1x80:
+               max_lines = 4;
+               break;
+       default:
+               /* Assume at least two serial ports at the normal address.  */
+               max_lines = 2;
+               break;
+       }
+
+       probed = 1;
+
+       for (chip = 0, line = 0; chip < DUART_MAX_CHIP && line < max_lines;
+            chip++) {
+               sbd_duarts[chip].mapctrl = SBD_CTRLREGS(line);
+
+               for (side = 0; side < DUART_MAX_SIDE && line < max_lines;
+                    side++, line++) {
+                       struct sbd_port *sport = &sbd_duarts[chip].sport[side];
+                       struct uart_port *uport = &sport->port;
+
+                       sport->duart    = &sbd_duarts[chip];
+
+                       uport->irq      = SBD_INT(line);
+                       uport->uartclk  = 100000000 / 20 * 16;
+                       uport->fifosize = 16;
+                       uport->iotype   = UPIO_MEM;
+                       uport->flags    = UPF_BOOT_AUTOCONF;
+                       uport->ops      = &sbd_ops;
+                       uport->line     = line;
+                       uport->mapbase  = SBD_CHANREGS(line);
+               }
+       }
+}
+
+
+#ifdef CONFIG_SERIAL_SB1250_DUART_CONSOLE
+/*
+ * Serial console stuff.  Very basic, polling driver for doing serial
+ * console output.  The console_sem is held by the caller, so we
+ * shouldn't be interrupted for more console activity.
+ */
+static void sbd_console_putchar(struct uart_port *uport, int ch)
+{
+       struct sbd_port *sport = to_sport(uport);
+
+       sbd_transmit_drain(sport);
+       write_sbdchn(sport, R_DUART_TX_HOLD, ch);
+}
+
+static void sbd_console_write(struct console *co, const char *s,
+                             unsigned int count)
+{
+       int chip = co->index / DUART_MAX_SIDE;
+       int side = co->index % DUART_MAX_SIDE;
+       struct sbd_port *sport = &sbd_duarts[chip].sport[side];
+       struct uart_port *uport = &sport->port;
+       unsigned long flags;
+       unsigned int mask;
+
+       /* Disable transmit interrupts and enable the transmitter. */
+       spin_lock_irqsave(&uport->lock, flags);
+       mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2));
+       write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2),
+                    mask & ~M_DUART_IMR_TX);
+       write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_EN);
+       spin_unlock_irqrestore(&uport->lock, flags);
+
+       uart_console_write(&sport->port, s, count, sbd_console_putchar);
+
+       /* Restore transmit interrupts and the transmitter enable. */
+       spin_lock_irqsave(&uport->lock, flags);
+       sbd_line_drain(sport);
+       if (sport->tx_stopped)
+               write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS);
+       write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), mask);
+       spin_unlock_irqrestore(&uport->lock, flags);
+}
+
+static int __init sbd_console_setup(struct console *co, char *options)
+{
+       int chip = co->index / DUART_MAX_SIDE;
+       int side = co->index % DUART_MAX_SIDE;
+       struct sbd_port *sport = &sbd_duarts[chip].sport[side];
+       struct uart_port *uport = &sport->port;
+       int baud = 115200;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+       int ret;
+
+       if (!sport->duart)
+               return -ENXIO;
+
+       ret = sbd_map_port(uport);
+       if (ret)
+               return ret;
+
+       sbd_init_port(sport);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       return uart_set_options(uport, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver sbd_reg;
+static struct console sbd_console = {
+       .name   = "duart",
+       .write  = sbd_console_write,
+       .device = uart_console_device,
+       .setup  = sbd_console_setup,
+       .flags  = CON_PRINTBUFFER,
+       .index  = -1,
+       .data   = &sbd_reg
+};
+
+static int __init sbd_serial_console_init(void)
+{
+       sbd_probe_duarts();
+       register_console(&sbd_console);
+
+       return 0;
+}
+
+console_initcall(sbd_serial_console_init);
+
+#define SERIAL_SB1250_DUART_CONSOLE    &sbd_console
+#else
+#define SERIAL_SB1250_DUART_CONSOLE    NULL
+#endif /* CONFIG_SERIAL_SB1250_DUART_CONSOLE */
+
+
+static struct uart_driver sbd_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "sb1250_duart",
+       .dev_name       = "duart",
+       .major          = TTY_MAJOR,
+       .minor          = SB1250_DUART_MINOR_BASE,
+       .nr             = DUART_MAX_CHIP * DUART_MAX_SIDE,
+       .cons           = SERIAL_SB1250_DUART_CONSOLE,
+};
+
+/* Set up the driver and register it.  */
+static int __init sbd_init(void)
+{
+       int i, ret;
+
+       sbd_probe_duarts();
+
+       ret = uart_register_driver(&sbd_reg);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < DUART_MAX_CHIP * DUART_MAX_SIDE; i++) {
+               struct sbd_duart *duart = &sbd_duarts[i / DUART_MAX_SIDE];
+               struct sbd_port *sport = &duart->sport[i % DUART_MAX_SIDE];
+               struct uart_port *uport = &sport->port;
+
+               if (sport->duart)
+                       uart_add_one_port(&sbd_reg, uport);
+       }
+
+       return 0;
+}
+
+/* Unload the driver.  Unregister stuff, get ready to go away.  */
+static void __exit sbd_exit(void)
+{
+       int i;
+
+       for (i = DUART_MAX_CHIP * DUART_MAX_SIDE - 1; i >= 0; i--) {
+               struct sbd_duart *duart = &sbd_duarts[i / DUART_MAX_SIDE];
+               struct sbd_port *sport = &duart->sport[i % DUART_MAX_SIDE];
+               struct uart_port *uport = &sport->port;
+
+               if (sport->duart)
+                       uart_remove_one_port(&sbd_reg, uport);
+       }
+
+       uart_unregister_driver(&sbd_reg);
+}
+
+module_init(sbd_init);
+module_exit(sbd_exit);
diff --git a/drivers/tty/serial/sc26xx.c b/drivers/tty/serial/sc26xx.c
new file mode 100644 (file)
index 0000000..75038ad
--- /dev/null
@@ -0,0 +1,757 @@
+/*
+ * SC268xx.c: Serial driver for Philiphs SC2681/SC2692 devices.
+ *
+ * Copyright (C) 2006,2007 Thomas Bogendörfer (tsbogend@alpha.franken.de)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+
+#if defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#define SC26XX_MAJOR         204
+#define SC26XX_MINOR_START   205
+#define SC26XX_NR            2
+
+struct uart_sc26xx_port {
+       struct uart_port      port[2];
+       u8     dsr_mask[2];
+       u8     cts_mask[2];
+       u8     dcd_mask[2];
+       u8     ri_mask[2];
+       u8     dtr_mask[2];
+       u8     rts_mask[2];
+       u8     imr;
+};
+
+/* register common to both ports */
+#define RD_ISR      0x14
+#define RD_IPR      0x34
+
+#define WR_ACR      0x10
+#define WR_IMR      0x14
+#define WR_OPCR     0x34
+#define WR_OPR_SET  0x38
+#define WR_OPR_CLR  0x3C
+
+/* access common register */
+#define READ_SC(p, r)        readb((p)->membase + RD_##r)
+#define WRITE_SC(p, r, v)    writeb((v), (p)->membase + WR_##r)
+
+/* register per port */
+#define RD_PORT_MRx 0x00
+#define RD_PORT_SR  0x04
+#define RD_PORT_RHR 0x0c
+
+#define WR_PORT_MRx 0x00
+#define WR_PORT_CSR 0x04
+#define WR_PORT_CR  0x08
+#define WR_PORT_THR 0x0c
+
+/* SR bits */
+#define SR_BREAK    (1 << 7)
+#define SR_FRAME    (1 << 6)
+#define SR_PARITY   (1 << 5)
+#define SR_OVERRUN  (1 << 4)
+#define SR_TXRDY    (1 << 2)
+#define SR_RXRDY    (1 << 0)
+
+#define CR_RES_MR   (1 << 4)
+#define CR_RES_RX   (2 << 4)
+#define CR_RES_TX   (3 << 4)
+#define CR_STRT_BRK (6 << 4)
+#define CR_STOP_BRK (7 << 4)
+#define CR_DIS_TX   (1 << 3)
+#define CR_ENA_TX   (1 << 2)
+#define CR_DIS_RX   (1 << 1)
+#define CR_ENA_RX   (1 << 0)
+
+/* ISR bits */
+#define ISR_RXRDYB  (1 << 5)
+#define ISR_TXRDYB  (1 << 4)
+#define ISR_RXRDYA  (1 << 1)
+#define ISR_TXRDYA  (1 << 0)
+
+/* IMR bits */
+#define IMR_RXRDY   (1 << 1)
+#define IMR_TXRDY   (1 << 0)
+
+/* access port register */
+static inline u8 read_sc_port(struct uart_port *p, u8 reg)
+{
+       return readb(p->membase + p->line * 0x20 + reg);
+}
+
+static inline void write_sc_port(struct uart_port *p, u8 reg, u8 val)
+{
+       writeb(val, p->membase + p->line * 0x20 + reg);
+}
+
+#define READ_SC_PORT(p, r)     read_sc_port(p, RD_PORT_##r)
+#define WRITE_SC_PORT(p, r, v) write_sc_port(p, WR_PORT_##r, v)
+
+static void sc26xx_enable_irq(struct uart_port *port, int mask)
+{
+       struct uart_sc26xx_port *up;
+       int line = port->line;
+
+       port -= line;
+       up = container_of(port, struct uart_sc26xx_port, port[0]);
+
+       up->imr |= mask << (line * 4);
+       WRITE_SC(port, IMR, up->imr);
+}
+
+static void sc26xx_disable_irq(struct uart_port *port, int mask)
+{
+       struct uart_sc26xx_port *up;
+       int line = port->line;
+
+       port -= line;
+       up = container_of(port, struct uart_sc26xx_port, port[0]);
+
+       up->imr &= ~(mask << (line * 4));
+       WRITE_SC(port, IMR, up->imr);
+}
+
+static struct tty_struct *receive_chars(struct uart_port *port)
+{
+       struct tty_struct *tty = NULL;
+       int limit = 10000;
+       unsigned char ch;
+       char flag;
+       u8 status;
+
+       if (port->state != NULL)                /* Unopened serial console */
+               tty = port->state->port.tty;
+
+       while (limit-- > 0) {
+               status = READ_SC_PORT(port, SR);
+               if (!(status & SR_RXRDY))
+                       break;
+               ch = READ_SC_PORT(port, RHR);
+
+               flag = TTY_NORMAL;
+               port->icount.rx++;
+
+               if (unlikely(status & (SR_BREAK | SR_FRAME |
+                                      SR_PARITY | SR_OVERRUN))) {
+                       if (status & SR_BREAK) {
+                               status &= ~(SR_PARITY | SR_FRAME);
+                               port->icount.brk++;
+                               if (uart_handle_break(port))
+                                       continue;
+                       } else if (status & SR_PARITY)
+                               port->icount.parity++;
+                       else if (status & SR_FRAME)
+                               port->icount.frame++;
+                       if (status & SR_OVERRUN)
+                               port->icount.overrun++;
+
+                       status &= port->read_status_mask;
+                       if (status & SR_BREAK)
+                               flag = TTY_BREAK;
+                       else if (status & SR_PARITY)
+                               flag = TTY_PARITY;
+                       else if (status & SR_FRAME)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(port, ch))
+                       continue;
+
+               if (status & port->ignore_status_mask)
+                       continue;
+
+               tty_insert_flip_char(tty, ch, flag);
+       }
+       return tty;
+}
+
+static void transmit_chars(struct uart_port *port)
+{
+       struct circ_buf *xmit;
+
+       if (!port->state)
+               return;
+
+       xmit = &port->state->xmit;
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               sc26xx_disable_irq(port, IMR_TXRDY);
+               return;
+       }
+       while (!uart_circ_empty(xmit)) {
+               if (!(READ_SC_PORT(port, SR) & SR_TXRDY))
+                       break;
+
+               WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+       }
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+}
+
+static irqreturn_t sc26xx_interrupt(int irq, void *dev_id)
+{
+       struct uart_sc26xx_port *up = dev_id;
+       struct tty_struct *tty;
+       unsigned long flags;
+       u8 isr;
+
+       spin_lock_irqsave(&up->port[0].lock, flags);
+
+       tty = NULL;
+       isr = READ_SC(&up->port[0], ISR);
+       if (isr & ISR_TXRDYA)
+           transmit_chars(&up->port[0]);
+       if (isr & ISR_RXRDYA)
+           tty = receive_chars(&up->port[0]);
+
+       spin_unlock(&up->port[0].lock);
+
+       if (tty)
+               tty_flip_buffer_push(tty);
+
+       spin_lock(&up->port[1].lock);
+
+       tty = NULL;
+       if (isr & ISR_TXRDYB)
+           transmit_chars(&up->port[1]);
+       if (isr & ISR_RXRDYB)
+           tty = receive_chars(&up->port[1]);
+
+       spin_unlock_irqrestore(&up->port[1].lock, flags);
+
+       if (tty)
+               tty_flip_buffer_push(tty);
+
+       return IRQ_HANDLED;
+}
+
+/* port->lock is not held.  */
+static unsigned int sc26xx_tx_empty(struct uart_port *port)
+{
+       return (READ_SC_PORT(port, SR) & SR_TXRDY) ? TIOCSER_TEMT : 0;
+}
+
+/* port->lock held by caller.  */
+static void sc26xx_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_sc26xx_port *up;
+       int line = port->line;
+
+       port -= line;
+       up = container_of(port, struct uart_sc26xx_port, port[0]);
+
+       if (up->dtr_mask[line]) {
+               if (mctrl & TIOCM_DTR)
+                       WRITE_SC(port, OPR_SET, up->dtr_mask[line]);
+               else
+                       WRITE_SC(port, OPR_CLR, up->dtr_mask[line]);
+       }
+       if (up->rts_mask[line]) {
+               if (mctrl & TIOCM_RTS)
+                       WRITE_SC(port, OPR_SET, up->rts_mask[line]);
+               else
+                       WRITE_SC(port, OPR_CLR, up->rts_mask[line]);
+       }
+}
+
+/* port->lock is held by caller and interrupts are disabled.  */
+static unsigned int sc26xx_get_mctrl(struct uart_port *port)
+{
+       struct uart_sc26xx_port *up;
+       int line = port->line;
+       unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR;
+       u8 ipr;
+
+       port -= line;
+       up = container_of(port, struct uart_sc26xx_port, port[0]);
+       ipr = READ_SC(port, IPR) ^ 0xff;
+
+       if (up->dsr_mask[line]) {
+               mctrl &= ~TIOCM_DSR;
+               mctrl |= ipr & up->dsr_mask[line] ? TIOCM_DSR : 0;
+       }
+       if (up->cts_mask[line]) {
+               mctrl &= ~TIOCM_CTS;
+               mctrl |= ipr & up->cts_mask[line] ? TIOCM_CTS : 0;
+       }
+       if (up->dcd_mask[line]) {
+               mctrl &= ~TIOCM_CAR;
+               mctrl |= ipr & up->dcd_mask[line] ? TIOCM_CAR : 0;
+       }
+       if (up->ri_mask[line]) {
+               mctrl &= ~TIOCM_RNG;
+               mctrl |= ipr & up->ri_mask[line] ? TIOCM_RNG : 0;
+       }
+       return mctrl;
+}
+
+/* port->lock held by caller.  */
+static void sc26xx_stop_tx(struct uart_port *port)
+{
+       return;
+}
+
+/* port->lock held by caller.  */
+static void sc26xx_start_tx(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->state->xmit;
+
+       while (!uart_circ_empty(xmit)) {
+               if (!(READ_SC_PORT(port, SR) & SR_TXRDY)) {
+                       sc26xx_enable_irq(port, IMR_TXRDY);
+                       break;
+               }
+               WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+       }
+}
+
+/* port->lock held by caller.  */
+static void sc26xx_stop_rx(struct uart_port *port)
+{
+}
+
+/* port->lock held by caller.  */
+static void sc26xx_enable_ms(struct uart_port *port)
+{
+}
+
+/* port->lock is not held.  */
+static void sc26xx_break_ctl(struct uart_port *port, int break_state)
+{
+       if (break_state == -1)
+               WRITE_SC_PORT(port, CR, CR_STRT_BRK);
+       else
+               WRITE_SC_PORT(port, CR, CR_STOP_BRK);
+}
+
+/* port->lock is not held.  */
+static int sc26xx_startup(struct uart_port *port)
+{
+       sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY);
+       WRITE_SC(port, OPCR, 0);
+
+       /* reset tx and rx */
+       WRITE_SC_PORT(port, CR, CR_RES_RX);
+       WRITE_SC_PORT(port, CR, CR_RES_TX);
+
+       /* start rx/tx */
+       WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX);
+
+       /* enable irqs */
+       sc26xx_enable_irq(port, IMR_RXRDY);
+       return 0;
+}
+
+/* port->lock is not held.  */
+static void sc26xx_shutdown(struct uart_port *port)
+{
+       /* disable interrupst */
+       sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY);
+
+       /* stop tx/rx */
+       WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX);
+}
+
+/* port->lock is not held.  */
+static void sc26xx_set_termios(struct uart_port *port, struct ktermios *termios,
+                             struct ktermios *old)
+{
+       unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
+       unsigned int quot = uart_get_divisor(port, baud);
+       unsigned int iflag, cflag;
+       unsigned long flags;
+       u8 mr1, mr2, csr;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc)
+               udelay(2);
+
+       WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX);
+
+       iflag = termios->c_iflag;
+       cflag = termios->c_cflag;
+
+       port->read_status_mask = SR_OVERRUN;
+       if (iflag & INPCK)
+               port->read_status_mask |= SR_PARITY | SR_FRAME;
+       if (iflag & (BRKINT | PARMRK))
+               port->read_status_mask |= SR_BREAK;
+
+       port->ignore_status_mask = 0;
+       if (iflag & IGNBRK)
+               port->ignore_status_mask |= SR_BREAK;
+       if ((cflag & CREAD) == 0)
+               port->ignore_status_mask |= SR_BREAK | SR_FRAME |
+                                           SR_PARITY | SR_OVERRUN;
+
+       switch (cflag & CSIZE) {
+       case CS5:
+               mr1 = 0x00;
+               break;
+       case CS6:
+               mr1 = 0x01;
+               break;
+       case CS7:
+               mr1 = 0x02;
+               break;
+       default:
+       case CS8:
+               mr1 = 0x03;
+               break;
+       }
+       mr2 = 0x07;
+       if (cflag & CSTOPB)
+               mr2 = 0x0f;
+       if (cflag & PARENB) {
+               if (cflag & PARODD)
+                       mr1 |= (1 << 2);
+       } else
+               mr1 |= (2 << 3);
+
+       switch (baud) {
+       case 50:
+               csr = 0x00;
+               break;
+       case 110:
+               csr = 0x11;
+               break;
+       case 134:
+               csr = 0x22;
+               break;
+       case 200:
+               csr = 0x33;
+               break;
+       case 300:
+               csr = 0x44;
+               break;
+       case 600:
+               csr = 0x55;
+               break;
+       case 1200:
+               csr = 0x66;
+               break;
+       case 2400:
+               csr = 0x88;
+               break;
+       case 4800:
+               csr = 0x99;
+               break;
+       default:
+       case 9600:
+               csr = 0xbb;
+               break;
+       case 19200:
+               csr = 0xcc;
+               break;
+       }
+
+       WRITE_SC_PORT(port, CR, CR_RES_MR);
+       WRITE_SC_PORT(port, MRx, mr1);
+       WRITE_SC_PORT(port, MRx, mr2);
+
+       WRITE_SC(port, ACR, 0x80);
+       WRITE_SC_PORT(port, CSR, csr);
+
+       /* reset tx and rx */
+       WRITE_SC_PORT(port, CR, CR_RES_RX);
+       WRITE_SC_PORT(port, CR, CR_RES_TX);
+
+       WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX);
+       while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc)
+               udelay(2);
+
+       /* XXX */
+       uart_update_timeout(port, cflag,
+                           (port->uartclk / (16 * quot)));
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *sc26xx_type(struct uart_port *port)
+{
+       return "SC26XX";
+}
+
+static void sc26xx_release_port(struct uart_port *port)
+{
+}
+
+static int sc26xx_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static void sc26xx_config_port(struct uart_port *port, int flags)
+{
+}
+
+static int sc26xx_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       return -EINVAL;
+}
+
+static struct uart_ops sc26xx_ops = {
+       .tx_empty       = sc26xx_tx_empty,
+       .set_mctrl      = sc26xx_set_mctrl,
+       .get_mctrl      = sc26xx_get_mctrl,
+       .stop_tx        = sc26xx_stop_tx,
+       .start_tx       = sc26xx_start_tx,
+       .stop_rx        = sc26xx_stop_rx,
+       .enable_ms      = sc26xx_enable_ms,
+       .break_ctl      = sc26xx_break_ctl,
+       .startup        = sc26xx_startup,
+       .shutdown       = sc26xx_shutdown,
+       .set_termios    = sc26xx_set_termios,
+       .type           = sc26xx_type,
+       .release_port   = sc26xx_release_port,
+       .request_port   = sc26xx_request_port,
+       .config_port    = sc26xx_config_port,
+       .verify_port    = sc26xx_verify_port,
+};
+
+static struct uart_port *sc26xx_port;
+
+#ifdef CONFIG_SERIAL_SC26XX_CONSOLE
+static void sc26xx_console_putchar(struct uart_port *port, char c)
+{
+       unsigned long flags;
+       int limit = 1000000;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       while (limit-- > 0) {
+               if (READ_SC_PORT(port, SR) & SR_TXRDY) {
+                       WRITE_SC_PORT(port, THR, c);
+                       break;
+               }
+               udelay(2);
+       }
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void sc26xx_console_write(struct console *con, const char *s, unsigned n)
+{
+       struct uart_port *port = sc26xx_port;
+       int i;
+
+       for (i = 0; i < n; i++) {
+               if (*s == '\n')
+                       sc26xx_console_putchar(port, '\r');
+               sc26xx_console_putchar(port, *s++);
+       }
+}
+
+static int __init sc26xx_console_setup(struct console *con, char *options)
+{
+       struct uart_port *port = sc26xx_port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (port->type != PORT_SC26XX)
+               return -1;
+
+       printk(KERN_INFO "Console: ttySC%d (SC26XX)\n", con->index);
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, con, baud, parity, bits, flow);
+}
+
+static struct uart_driver sc26xx_reg;
+static struct console sc26xx_console = {
+       .name   =       "ttySC",
+       .write  =       sc26xx_console_write,
+       .device =       uart_console_device,
+       .setup  =       sc26xx_console_setup,
+       .flags  =       CON_PRINTBUFFER,
+       .index  =       -1,
+       .data   =       &sc26xx_reg,
+};
+#define SC26XX_CONSOLE   &sc26xx_console
+#else
+#define SC26XX_CONSOLE   NULL
+#endif
+
+static struct uart_driver sc26xx_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "SC26xx",
+       .dev_name               = "ttySC",
+       .major                  = SC26XX_MAJOR,
+       .minor                  = SC26XX_MINOR_START,
+       .nr                     = SC26XX_NR,
+       .cons                   = SC26XX_CONSOLE,
+};
+
+static u8 sc26xx_flags2mask(unsigned int flags, unsigned int bitpos)
+{
+       unsigned int bit = (flags >> bitpos) & 15;
+
+       return bit ? (1 << (bit - 1)) : 0;
+}
+
+static void __devinit sc26xx_init_masks(struct uart_sc26xx_port *up,
+                                       int line, unsigned int data)
+{
+       up->dtr_mask[line] = sc26xx_flags2mask(data,  0);
+       up->rts_mask[line] = sc26xx_flags2mask(data,  4);
+       up->dsr_mask[line] = sc26xx_flags2mask(data,  8);
+       up->cts_mask[line] = sc26xx_flags2mask(data, 12);
+       up->dcd_mask[line] = sc26xx_flags2mask(data, 16);
+       up->ri_mask[line]  = sc26xx_flags2mask(data, 20);
+}
+
+static int __devinit sc26xx_probe(struct platform_device *dev)
+{
+       struct resource *res;
+       struct uart_sc26xx_port *up;
+       unsigned int *sc26xx_data = dev->dev.platform_data;
+       int err;
+
+       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+
+       up = kzalloc(sizeof *up, GFP_KERNEL);
+       if (unlikely(!up))
+               return -ENOMEM;
+
+       up->port[0].line = 0;
+       up->port[0].ops = &sc26xx_ops;
+       up->port[0].type = PORT_SC26XX;
+       up->port[0].uartclk = (29491200 / 16); /* arbitrary */
+
+       up->port[0].mapbase = res->start;
+       up->port[0].membase = ioremap_nocache(up->port[0].mapbase, 0x40);
+       up->port[0].iotype = UPIO_MEM;
+       up->port[0].irq = platform_get_irq(dev, 0);
+
+       up->port[0].dev = &dev->dev;
+
+       sc26xx_init_masks(up, 0, sc26xx_data[0]);
+
+       sc26xx_port = &up->port[0];
+
+       up->port[1].line = 1;
+       up->port[1].ops = &sc26xx_ops;
+       up->port[1].type = PORT_SC26XX;
+       up->port[1].uartclk = (29491200 / 16); /* arbitrary */
+
+       up->port[1].mapbase = up->port[0].mapbase;
+       up->port[1].membase = up->port[0].membase;
+       up->port[1].iotype = UPIO_MEM;
+       up->port[1].irq = up->port[0].irq;
+
+       up->port[1].dev = &dev->dev;
+
+       sc26xx_init_masks(up, 1, sc26xx_data[1]);
+
+       err = uart_register_driver(&sc26xx_reg);
+       if (err)
+               goto out_free_port;
+
+       sc26xx_reg.tty_driver->name_base = sc26xx_reg.minor;
+
+       err = uart_add_one_port(&sc26xx_reg, &up->port[0]);
+       if (err)
+               goto out_unregister_driver;
+
+       err = uart_add_one_port(&sc26xx_reg, &up->port[1]);
+       if (err)
+               goto out_remove_port0;
+
+       err = request_irq(up->port[0].irq, sc26xx_interrupt, 0, "sc26xx", up);
+       if (err)
+               goto out_remove_ports;
+
+       dev_set_drvdata(&dev->dev, up);
+       return 0;
+
+out_remove_ports:
+       uart_remove_one_port(&sc26xx_reg, &up->port[1]);
+out_remove_port0:
+       uart_remove_one_port(&sc26xx_reg, &up->port[0]);
+
+out_unregister_driver:
+       uart_unregister_driver(&sc26xx_reg);
+
+out_free_port:
+       kfree(up);
+       sc26xx_port = NULL;
+       return err;
+}
+
+
+static int __exit sc26xx_driver_remove(struct platform_device *dev)
+{
+       struct uart_sc26xx_port *up = dev_get_drvdata(&dev->dev);
+
+       free_irq(up->port[0].irq, up);
+
+       uart_remove_one_port(&sc26xx_reg, &up->port[0]);
+       uart_remove_one_port(&sc26xx_reg, &up->port[1]);
+
+       uart_unregister_driver(&sc26xx_reg);
+
+       kfree(up);
+       sc26xx_port = NULL;
+
+       dev_set_drvdata(&dev->dev, NULL);
+       return 0;
+}
+
+static struct platform_driver sc26xx_driver = {
+       .probe  = sc26xx_probe,
+       .remove = __devexit_p(sc26xx_driver_remove),
+       .driver = {
+               .name   = "SC26xx",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init sc26xx_init(void)
+{
+       return platform_driver_register(&sc26xx_driver);
+}
+
+static void __exit sc26xx_exit(void)
+{
+       platform_driver_unregister(&sc26xx_driver);
+}
+
+module_init(sc26xx_init);
+module_exit(sc26xx_exit);
+
+
+MODULE_AUTHOR("Thomas Bogendörfer");
+MODULE_DESCRIPTION("SC681/SC2692 serial driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:SC26xx");
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
new file mode 100644 (file)
index 0000000..460a72d
--- /dev/null
@@ -0,0 +1,2578 @@
+/*
+ *  linux/drivers/char/core.c
+ *
+ *  Driver core for serial ports
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ *  Copyright 1999 ARM Limited
+ *  Copyright (C) 2000-2001 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/module.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/device.h>
+#include <linux/serial.h> /* for serial_state and serial_icounter_struct */
+#include <linux/serial_core.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+/*
+ * This is used to lock changes in serial line configuration.
+ */
+static DEFINE_MUTEX(port_mutex);
+
+/*
+ * lockdep: port->lock is initialized in two places, but we
+ *          want only one lock-class:
+ */
+static struct lock_class_key port_lock_key;
+
+#define HIGH_BITS_OFFSET       ((sizeof(long)-sizeof(int))*8)
+
+#ifdef CONFIG_SERIAL_CORE_CONSOLE
+#define uart_console(port)     ((port)->cons && (port)->cons->index == (port)->line)
+#else
+#define uart_console(port)     (0)
+#endif
+
+static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
+                                       struct ktermios *old_termios);
+static void __uart_wait_until_sent(struct uart_port *port, int timeout);
+static void uart_change_pm(struct uart_state *state, int pm_state);
+
+/*
+ * This routine is used by the interrupt handler to schedule processing in
+ * the software interrupt portion of the driver.
+ */
+void uart_write_wakeup(struct uart_port *port)
+{
+       struct uart_state *state = port->state;
+       /*
+        * This means you called this function _after_ the port was
+        * closed.  No cookie for you.
+        */
+       BUG_ON(!state);
+       tasklet_schedule(&state->tlet);
+}
+
+static void uart_stop(struct tty_struct *tty)
+{
+       struct uart_state *state = tty->driver_data;
+       struct uart_port *port = state->uart_port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       port->ops->stop_tx(port);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void __uart_start(struct tty_struct *tty)
+{
+       struct uart_state *state = tty->driver_data;
+       struct uart_port *port = state->uart_port;
+
+       if (!uart_circ_empty(&state->xmit) && state->xmit.buf &&
+           !tty->stopped && !tty->hw_stopped)
+               port->ops->start_tx(port);
+}
+
+static void uart_start(struct tty_struct *tty)
+{
+       struct uart_state *state = tty->driver_data;
+       struct uart_port *port = state->uart_port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       __uart_start(tty);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void uart_tasklet_action(unsigned long data)
+{
+       struct uart_state *state = (struct uart_state *)data;
+       tty_wakeup(state->port.tty);
+}
+
+static inline void
+uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
+{
+       unsigned long flags;
+       unsigned int old;
+
+       spin_lock_irqsave(&port->lock, flags);
+       old = port->mctrl;
+       port->mctrl = (old & ~clear) | set;
+       if (old != port->mctrl)
+               port->ops->set_mctrl(port, port->mctrl);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+#define uart_set_mctrl(port, set)      uart_update_mctrl(port, set, 0)
+#define uart_clear_mctrl(port, clear)  uart_update_mctrl(port, 0, clear)
+
+/*
+ * Startup the port.  This will be called once per open.  All calls
+ * will be serialised by the per-port mutex.
+ */
+static int uart_startup(struct tty_struct *tty, struct uart_state *state, int init_hw)
+{
+       struct uart_port *uport = state->uart_port;
+       struct tty_port *port = &state->port;
+       unsigned long page;
+       int retval = 0;
+
+       if (port->flags & ASYNC_INITIALIZED)
+               return 0;
+
+       /*
+        * Set the TTY IO error marker - we will only clear this
+        * once we have successfully opened the port.  Also set
+        * up the tty->alt_speed kludge
+        */
+       set_bit(TTY_IO_ERROR, &tty->flags);
+
+       if (uport->type == PORT_UNKNOWN)
+               return 0;
+
+       /*
+        * Initialise and allocate the transmit and temporary
+        * buffer.
+        */
+       if (!state->xmit.buf) {
+               /* This is protected by the per port mutex */
+               page = get_zeroed_page(GFP_KERNEL);
+               if (!page)
+                       return -ENOMEM;
+
+               state->xmit.buf = (unsigned char *) page;
+               uart_circ_clear(&state->xmit);
+       }
+
+       retval = uport->ops->startup(uport);
+       if (retval == 0) {
+               if (init_hw) {
+                       /*
+                        * Initialise the hardware port settings.
+                        */
+                       uart_change_speed(tty, state, NULL);
+
+                       /*
+                        * Setup the RTS and DTR signals once the
+                        * port is open and ready to respond.
+                        */
+                       if (tty->termios->c_cflag & CBAUD)
+                               uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
+               }
+
+               if (port->flags & ASYNC_CTS_FLOW) {
+                       spin_lock_irq(&uport->lock);
+                       if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS))
+                               tty->hw_stopped = 1;
+                       spin_unlock_irq(&uport->lock);
+               }
+
+               set_bit(ASYNCB_INITIALIZED, &port->flags);
+
+               clear_bit(TTY_IO_ERROR, &tty->flags);
+       }
+
+       if (retval && capable(CAP_SYS_ADMIN))
+               retval = 0;
+
+       return retval;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.  Calls to
+ * uart_shutdown are serialised by the per-port semaphore.
+ */
+static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
+{
+       struct uart_port *uport = state->uart_port;
+       struct tty_port *port = &state->port;
+
+       /*
+        * Set the TTY IO error marker
+        */
+       if (tty)
+               set_bit(TTY_IO_ERROR, &tty->flags);
+
+       if (test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) {
+               /*
+                * Turn off DTR and RTS early.
+                */
+               if (!tty || (tty->termios->c_cflag & HUPCL))
+                       uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
+
+               /*
+                * clear delta_msr_wait queue to avoid mem leaks: we may free
+                * the irq here so the queue might never be woken up.  Note
+                * that we won't end up waiting on delta_msr_wait again since
+                * any outstanding file descriptors should be pointing at
+                * hung_up_tty_fops now.
+                */
+               wake_up_interruptible(&port->delta_msr_wait);
+
+               /*
+                * Free the IRQ and disable the port.
+                */
+               uport->ops->shutdown(uport);
+
+               /*
+                * Ensure that the IRQ handler isn't running on another CPU.
+                */
+               synchronize_irq(uport->irq);
+       }
+
+       /*
+        * kill off our tasklet
+        */
+       tasklet_kill(&state->tlet);
+
+       /*
+        * Free the transmit buffer page.
+        */
+       if (state->xmit.buf) {
+               free_page((unsigned long)state->xmit.buf);
+               state->xmit.buf = NULL;
+       }
+}
+
+/**
+ *     uart_update_timeout - update per-port FIFO timeout.
+ *     @port:  uart_port structure describing the port
+ *     @cflag: termios cflag value
+ *     @baud:  speed of the port
+ *
+ *     Set the port FIFO timeout value.  The @cflag value should
+ *     reflect the actual hardware settings.
+ */
+void
+uart_update_timeout(struct uart_port *port, unsigned int cflag,
+                   unsigned int baud)
+{
+       unsigned int bits;
+
+       /* byte size and parity */
+       switch (cflag & CSIZE) {
+       case CS5:
+               bits = 7;
+               break;
+       case CS6:
+               bits = 8;
+               break;
+       case CS7:
+               bits = 9;
+               break;
+       default:
+               bits = 10;
+               break; /* CS8 */
+       }
+
+       if (cflag & CSTOPB)
+               bits++;
+       if (cflag & PARENB)
+               bits++;
+
+       /*
+        * The total number of bits to be transmitted in the fifo.
+        */
+       bits = bits * port->fifosize;
+
+       /*
+        * Figure the timeout to send the above number of bits.
+        * Add .02 seconds of slop
+        */
+       port->timeout = (HZ * bits) / baud + HZ/50;
+}
+
+EXPORT_SYMBOL(uart_update_timeout);
+
+/**
+ *     uart_get_baud_rate - return baud rate for a particular port
+ *     @port: uart_port structure describing the port in question.
+ *     @termios: desired termios settings.
+ *     @old: old termios (or NULL)
+ *     @min: minimum acceptable baud rate
+ *     @max: maximum acceptable baud rate
+ *
+ *     Decode the termios structure into a numeric baud rate,
+ *     taking account of the magic 38400 baud rate (with spd_*
+ *     flags), and mapping the %B0 rate to 9600 baud.
+ *
+ *     If the new baud rate is invalid, try the old termios setting.
+ *     If it's still invalid, we try 9600 baud.
+ *
+ *     Update the @termios structure to reflect the baud rate
+ *     we're actually going to be using. Don't do this for the case
+ *     where B0 is requested ("hang up").
+ */
+unsigned int
+uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
+                  struct ktermios *old, unsigned int min, unsigned int max)
+{
+       unsigned int try, baud, altbaud = 38400;
+       int hung_up = 0;
+       upf_t flags = port->flags & UPF_SPD_MASK;
+
+       if (flags == UPF_SPD_HI)
+               altbaud = 57600;
+       else if (flags == UPF_SPD_VHI)
+               altbaud = 115200;
+       else if (flags == UPF_SPD_SHI)
+               altbaud = 230400;
+       else if (flags == UPF_SPD_WARP)
+               altbaud = 460800;
+
+       for (try = 0; try < 2; try++) {
+               baud = tty_termios_baud_rate(termios);
+
+               /*
+                * The spd_hi, spd_vhi, spd_shi, spd_warp kludge...
+                * Die! Die! Die!
+                */
+               if (baud == 38400)
+                       baud = altbaud;
+
+               /*
+                * Special case: B0 rate.
+                */
+               if (baud == 0) {
+                       hung_up = 1;
+                       baud = 9600;
+               }
+
+               if (baud >= min && baud <= max)
+                       return baud;
+
+               /*
+                * Oops, the quotient was zero.  Try again with
+                * the old baud rate if possible.
+                */
+               termios->c_cflag &= ~CBAUD;
+               if (old) {
+                       baud = tty_termios_baud_rate(old);
+                       if (!hung_up)
+                               tty_termios_encode_baud_rate(termios,
+                                                               baud, baud);
+                       old = NULL;
+                       continue;
+               }
+
+               /*
+                * As a last resort, if the range cannot be met then clip to
+                * the nearest chip supported rate.
+                */
+               if (!hung_up) {
+                       if (baud <= min)
+                               tty_termios_encode_baud_rate(termios,
+                                                       min + 1, min + 1);
+                       else
+                               tty_termios_encode_baud_rate(termios,
+                                                       max - 1, max - 1);
+               }
+       }
+       /* Should never happen */
+       WARN_ON(1);
+       return 0;
+}
+
+EXPORT_SYMBOL(uart_get_baud_rate);
+
+/**
+ *     uart_get_divisor - return uart clock divisor
+ *     @port: uart_port structure describing the port.
+ *     @baud: desired baud rate
+ *
+ *     Calculate the uart clock divisor for the port.
+ */
+unsigned int
+uart_get_divisor(struct uart_port *port, unsigned int baud)
+{
+       unsigned int quot;
+
+       /*
+        * Old custom speed handling.
+        */
+       if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
+               quot = port->custom_divisor;
+       else
+               quot = (port->uartclk + (8 * baud)) / (16 * baud);
+
+       return quot;
+}
+
+EXPORT_SYMBOL(uart_get_divisor);
+
+/* FIXME: Consistent locking policy */
+static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
+                                       struct ktermios *old_termios)
+{
+       struct tty_port *port = &state->port;
+       struct uart_port *uport = state->uart_port;
+       struct ktermios *termios;
+
+       /*
+        * If we have no tty, termios, or the port does not exist,
+        * then we can't set the parameters for this port.
+        */
+       if (!tty || !tty->termios || uport->type == PORT_UNKNOWN)
+               return;
+
+       termios = tty->termios;
+
+       /*
+        * Set flags based on termios cflag
+        */
+       if (termios->c_cflag & CRTSCTS)
+               set_bit(ASYNCB_CTS_FLOW, &port->flags);
+       else
+               clear_bit(ASYNCB_CTS_FLOW, &port->flags);
+
+       if (termios->c_cflag & CLOCAL)
+               clear_bit(ASYNCB_CHECK_CD, &port->flags);
+       else
+               set_bit(ASYNCB_CHECK_CD, &port->flags);
+
+       uport->ops->set_termios(uport, termios, old_termios);
+}
+
+static inline int __uart_put_char(struct uart_port *port,
+                               struct circ_buf *circ, unsigned char c)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       if (!circ->buf)
+               return 0;
+
+       spin_lock_irqsave(&port->lock, flags);
+       if (uart_circ_chars_free(circ) != 0) {
+               circ->buf[circ->head] = c;
+               circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1);
+               ret = 1;
+       }
+       spin_unlock_irqrestore(&port->lock, flags);
+       return ret;
+}
+
+static int uart_put_char(struct tty_struct *tty, unsigned char ch)
+{
+       struct uart_state *state = tty->driver_data;
+
+       return __uart_put_char(state->uart_port, &state->xmit, ch);
+}
+
+static void uart_flush_chars(struct tty_struct *tty)
+{
+       uart_start(tty);
+}
+
+static int uart_write(struct tty_struct *tty,
+                                       const unsigned char *buf, int count)
+{
+       struct uart_state *state = tty->driver_data;
+       struct uart_port *port;
+       struct circ_buf *circ;
+       unsigned long flags;
+       int c, ret = 0;
+
+       /*
+        * This means you called this function _after_ the port was
+        * closed.  No cookie for you.
+        */
+       if (!state) {
+               WARN_ON(1);
+               return -EL3HLT;
+       }
+
+       port = state->uart_port;
+       circ = &state->xmit;
+
+       if (!circ->buf)
+               return 0;
+
+       spin_lock_irqsave(&port->lock, flags);
+       while (1) {
+               c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
+               if (count < c)
+                       c = count;
+               if (c <= 0)
+                       break;
+               memcpy(circ->buf + circ->head, buf, c);
+               circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
+               buf += c;
+               count -= c;
+               ret += c;
+       }
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       uart_start(tty);
+       return ret;
+}
+
+static int uart_write_room(struct tty_struct *tty)
+{
+       struct uart_state *state = tty->driver_data;
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&state->uart_port->lock, flags);
+       ret = uart_circ_chars_free(&state->xmit);
+       spin_unlock_irqrestore(&state->uart_port->lock, flags);
+       return ret;
+}
+
+static int uart_chars_in_buffer(struct tty_struct *tty)
+{
+       struct uart_state *state = tty->driver_data;
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&state->uart_port->lock, flags);
+       ret = uart_circ_chars_pending(&state->xmit);
+       spin_unlock_irqrestore(&state->uart_port->lock, flags);
+       return ret;
+}
+
+static void uart_flush_buffer(struct tty_struct *tty)
+{
+       struct uart_state *state = tty->driver_data;
+       struct uart_port *port;
+       unsigned long flags;
+
+       /*
+        * This means you called this function _after_ the port was
+        * closed.  No cookie for you.
+        */
+       if (!state) {
+               WARN_ON(1);
+               return;
+       }
+
+       port = state->uart_port;
+       pr_debug("uart_flush_buffer(%d) called\n", tty->index);
+
+       spin_lock_irqsave(&port->lock, flags);
+       uart_circ_clear(&state->xmit);
+       if (port->ops->flush_buffer)
+               port->ops->flush_buffer(port);
+       spin_unlock_irqrestore(&port->lock, flags);
+       tty_wakeup(tty);
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ */
+static void uart_send_xchar(struct tty_struct *tty, char ch)
+{
+       struct uart_state *state = tty->driver_data;
+       struct uart_port *port = state->uart_port;
+       unsigned long flags;
+
+       if (port->ops->send_xchar)
+               port->ops->send_xchar(port, ch);
+       else {
+               port->x_char = ch;
+               if (ch) {
+                       spin_lock_irqsave(&port->lock, flags);
+                       port->ops->start_tx(port);
+                       spin_unlock_irqrestore(&port->lock, flags);
+               }
+       }
+}
+
+static void uart_throttle(struct tty_struct *tty)
+{
+       struct uart_state *state = tty->driver_data;
+
+       if (I_IXOFF(tty))
+               uart_send_xchar(tty, STOP_CHAR(tty));
+
+       if (tty->termios->c_cflag & CRTSCTS)
+               uart_clear_mctrl(state->uart_port, TIOCM_RTS);
+}
+
+static void uart_unthrottle(struct tty_struct *tty)
+{
+       struct uart_state *state = tty->driver_data;
+       struct uart_port *port = state->uart_port;
+
+       if (I_IXOFF(tty)) {
+               if (port->x_char)
+                       port->x_char = 0;
+               else
+                       uart_send_xchar(tty, START_CHAR(tty));
+       }
+
+       if (tty->termios->c_cflag & CRTSCTS)
+               uart_set_mctrl(port, TIOCM_RTS);
+}
+
+static int uart_get_info(struct uart_state *state,
+                        struct serial_struct __user *retinfo)
+{
+       struct uart_port *uport = state->uart_port;
+       struct tty_port *port = &state->port;
+       struct serial_struct tmp;
+
+       memset(&tmp, 0, sizeof(tmp));
+
+       /* Ensure the state we copy is consistent and no hardware changes
+          occur as we go */
+       mutex_lock(&port->mutex);
+
+       tmp.type            = uport->type;
+       tmp.line            = uport->line;
+       tmp.port            = uport->iobase;
+       if (HIGH_BITS_OFFSET)
+               tmp.port_high = (long) uport->iobase >> HIGH_BITS_OFFSET;
+       tmp.irq             = uport->irq;
+       tmp.flags           = uport->flags;
+       tmp.xmit_fifo_size  = uport->fifosize;
+       tmp.baud_base       = uport->uartclk / 16;
+       tmp.close_delay     = port->close_delay / 10;
+       tmp.closing_wait    = port->closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+                               ASYNC_CLOSING_WAIT_NONE :
+                               port->closing_wait / 10;
+       tmp.custom_divisor  = uport->custom_divisor;
+       tmp.hub6            = uport->hub6;
+       tmp.io_type         = uport->iotype;
+       tmp.iomem_reg_shift = uport->regshift;
+       tmp.iomem_base      = (void *)(unsigned long)uport->mapbase;
+
+       mutex_unlock(&port->mutex);
+
+       if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+               return -EFAULT;
+       return 0;
+}
+
+static int uart_set_info(struct tty_struct *tty, struct uart_state *state,
+                        struct serial_struct __user *newinfo)
+{
+       struct serial_struct new_serial;
+       struct uart_port *uport = state->uart_port;
+       struct tty_port *port = &state->port;
+       unsigned long new_port;
+       unsigned int change_irq, change_port, closing_wait;
+       unsigned int old_custom_divisor, close_delay;
+       upf_t old_flags, new_flags;
+       int retval = 0;
+
+       if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
+               return -EFAULT;
+
+       new_port = new_serial.port;
+       if (HIGH_BITS_OFFSET)
+               new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET;
+
+       new_serial.irq = irq_canonicalize(new_serial.irq);
+       close_delay = new_serial.close_delay * 10;
+       closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+                       ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
+
+       /*
+        * This semaphore protects port->count.  It is also
+        * very useful to prevent opens.  Also, take the
+        * port configuration semaphore to make sure that a
+        * module insertion/removal doesn't change anything
+        * under us.
+        */
+       mutex_lock(&port->mutex);
+
+       change_irq  = !(uport->flags & UPF_FIXED_PORT)
+               && new_serial.irq != uport->irq;
+
+       /*
+        * Since changing the 'type' of the port changes its resource
+        * allocations, we should treat type changes the same as
+        * IO port changes.
+        */
+       change_port = !(uport->flags & UPF_FIXED_PORT)
+               && (new_port != uport->iobase ||
+                   (unsigned long)new_serial.iomem_base != uport->mapbase ||
+                   new_serial.hub6 != uport->hub6 ||
+                   new_serial.io_type != uport->iotype ||
+                   new_serial.iomem_reg_shift != uport->regshift ||
+                   new_serial.type != uport->type);
+
+       old_flags = uport->flags;
+       new_flags = new_serial.flags;
+       old_custom_divisor = uport->custom_divisor;
+
+       if (!capable(CAP_SYS_ADMIN)) {
+               retval = -EPERM;
+               if (change_irq || change_port ||
+                   (new_serial.baud_base != uport->uartclk / 16) ||
+                   (close_delay != port->close_delay) ||
+                   (closing_wait != port->closing_wait) ||
+                   (new_serial.xmit_fifo_size &&
+                    new_serial.xmit_fifo_size != uport->fifosize) ||
+                   (((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0))
+                       goto exit;
+               uport->flags = ((uport->flags & ~UPF_USR_MASK) |
+                              (new_flags & UPF_USR_MASK));
+               uport->custom_divisor = new_serial.custom_divisor;
+               goto check_and_exit;
+       }
+
+       /*
+        * Ask the low level driver to verify the settings.
+        */
+       if (uport->ops->verify_port)
+               retval = uport->ops->verify_port(uport, &new_serial);
+
+       if ((new_serial.irq >= nr_irqs) || (new_serial.irq < 0) ||
+           (new_serial.baud_base < 9600))
+               retval = -EINVAL;
+
+       if (retval)
+               goto exit;
+
+       if (change_port || change_irq) {
+               retval = -EBUSY;
+
+               /*
+                * Make sure that we are the sole user of this port.
+                */
+               if (tty_port_users(port) > 1)
+                       goto exit;
+
+               /*
+                * We need to shutdown the serial port at the old
+                * port/type/irq combination.
+                */
+               uart_shutdown(tty, state);
+       }
+
+       if (change_port) {
+               unsigned long old_iobase, old_mapbase;
+               unsigned int old_type, old_iotype, old_hub6, old_shift;
+
+               old_iobase = uport->iobase;
+               old_mapbase = uport->mapbase;
+               old_type = uport->type;
+               old_hub6 = uport->hub6;
+               old_iotype = uport->iotype;
+               old_shift = uport->regshift;
+
+               /*
+                * Free and release old regions
+                */
+               if (old_type != PORT_UNKNOWN)
+                       uport->ops->release_port(uport);
+
+               uport->iobase = new_port;
+               uport->type = new_serial.type;
+               uport->hub6 = new_serial.hub6;
+               uport->iotype = new_serial.io_type;
+               uport->regshift = new_serial.iomem_reg_shift;
+               uport->mapbase = (unsigned long)new_serial.iomem_base;
+
+               /*
+                * Claim and map the new regions
+                */
+               if (uport->type != PORT_UNKNOWN) {
+                       retval = uport->ops->request_port(uport);
+               } else {
+                       /* Always success - Jean II */
+                       retval = 0;
+               }
+
+               /*
+                * If we fail to request resources for the
+                * new port, try to restore the old settings.
+                */
+               if (retval && old_type != PORT_UNKNOWN) {
+                       uport->iobase = old_iobase;
+                       uport->type = old_type;
+                       uport->hub6 = old_hub6;
+                       uport->iotype = old_iotype;
+                       uport->regshift = old_shift;
+                       uport->mapbase = old_mapbase;
+                       retval = uport->ops->request_port(uport);
+                       /*
+                        * If we failed to restore the old settings,
+                        * we fail like this.
+                        */
+                       if (retval)
+                               uport->type = PORT_UNKNOWN;
+
+                       /*
+                        * We failed anyway.
+                        */
+                       retval = -EBUSY;
+                       /* Added to return the correct error -Ram Gupta */
+                       goto exit;
+               }
+       }
+
+       if (change_irq)
+               uport->irq      = new_serial.irq;
+       if (!(uport->flags & UPF_FIXED_PORT))
+               uport->uartclk  = new_serial.baud_base * 16;
+       uport->flags            = (uport->flags & ~UPF_CHANGE_MASK) |
+                                (new_flags & UPF_CHANGE_MASK);
+       uport->custom_divisor   = new_serial.custom_divisor;
+       port->close_delay     = close_delay;
+       port->closing_wait    = closing_wait;
+       if (new_serial.xmit_fifo_size)
+               uport->fifosize = new_serial.xmit_fifo_size;
+       if (port->tty)
+               port->tty->low_latency =
+                       (uport->flags & UPF_LOW_LATENCY) ? 1 : 0;
+
+ check_and_exit:
+       retval = 0;
+       if (uport->type == PORT_UNKNOWN)
+               goto exit;
+       if (port->flags & ASYNC_INITIALIZED) {
+               if (((old_flags ^ uport->flags) & UPF_SPD_MASK) ||
+                   old_custom_divisor != uport->custom_divisor) {
+                       /*
+                        * If they're setting up a custom divisor or speed,
+                        * instead of clearing it, then bitch about it. No
+                        * need to rate-limit; it's CAP_SYS_ADMIN only.
+                        */
+                       if (uport->flags & UPF_SPD_MASK) {
+                               char buf[64];
+                               printk(KERN_NOTICE
+                                      "%s sets custom speed on %s. This "
+                                      "is deprecated.\n", current->comm,
+                                      tty_name(port->tty, buf));
+                       }
+                       uart_change_speed(tty, state, NULL);
+               }
+       } else
+               retval = uart_startup(tty, state, 1);
+ exit:
+       mutex_unlock(&port->mutex);
+       return retval;
+}
+
+/**
+ *     uart_get_lsr_info       -       get line status register info
+ *     @tty: tty associated with the UART
+ *     @state: UART being queried
+ *     @value: returned modem value
+ *
+ *     Note: uart_ioctl protects us against hangups.
+ */
+static int uart_get_lsr_info(struct tty_struct *tty,
+                       struct uart_state *state, unsigned int __user *value)
+{
+       struct uart_port *uport = state->uart_port;
+       unsigned int result;
+
+       result = uport->ops->tx_empty(uport);
+
+       /*
+        * If we're about to load something into the transmit
+        * register, we'll pretend the transmitter isn't empty to
+        * avoid a race condition (depending on when the transmit
+        * interrupt happens).
+        */
+       if (uport->x_char ||
+           ((uart_circ_chars_pending(&state->xmit) > 0) &&
+            !tty->stopped && !tty->hw_stopped))
+               result &= ~TIOCSER_TEMT;
+
+       return put_user(result, value);
+}
+
+static int uart_tiocmget(struct tty_struct *tty, struct file *file)
+{
+       struct uart_state *state = tty->driver_data;
+       struct tty_port *port = &state->port;
+       struct uart_port *uport = state->uart_port;
+       int result = -EIO;
+
+       mutex_lock(&port->mutex);
+       if ((!file || !tty_hung_up_p(file)) &&
+           !(tty->flags & (1 << TTY_IO_ERROR))) {
+               result = uport->mctrl;
+
+               spin_lock_irq(&uport->lock);
+               result |= uport->ops->get_mctrl(uport);
+               spin_unlock_irq(&uport->lock);
+       }
+       mutex_unlock(&port->mutex);
+
+       return result;
+}
+
+static int
+uart_tiocmset(struct tty_struct *tty, struct file *file,
+             unsigned int set, unsigned int clear)
+{
+       struct uart_state *state = tty->driver_data;
+       struct uart_port *uport = state->uart_port;
+       struct tty_port *port = &state->port;
+       int ret = -EIO;
+
+       mutex_lock(&port->mutex);
+       if ((!file || !tty_hung_up_p(file)) &&
+           !(tty->flags & (1 << TTY_IO_ERROR))) {
+               uart_update_mctrl(uport, set, clear);
+               ret = 0;
+       }
+       mutex_unlock(&port->mutex);
+       return ret;
+}
+
+static int uart_break_ctl(struct tty_struct *tty, int break_state)
+{
+       struct uart_state *state = tty->driver_data;
+       struct tty_port *port = &state->port;
+       struct uart_port *uport = state->uart_port;
+
+       mutex_lock(&port->mutex);
+
+       if (uport->type != PORT_UNKNOWN)
+               uport->ops->break_ctl(uport, break_state);
+
+       mutex_unlock(&port->mutex);
+       return 0;
+}
+
+static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state)
+{
+       struct uart_port *uport = state->uart_port;
+       struct tty_port *port = &state->port;
+       int flags, ret;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       /*
+        * Take the per-port semaphore.  This prevents count from
+        * changing, and hence any extra opens of the port while
+        * we're auto-configuring.
+        */
+       if (mutex_lock_interruptible(&port->mutex))
+               return -ERESTARTSYS;
+
+       ret = -EBUSY;
+       if (tty_port_users(port) == 1) {
+               uart_shutdown(tty, state);
+
+               /*
+                * If we already have a port type configured,
+                * we must release its resources.
+                */
+               if (uport->type != PORT_UNKNOWN)
+                       uport->ops->release_port(uport);
+
+               flags = UART_CONFIG_TYPE;
+               if (uport->flags & UPF_AUTO_IRQ)
+                       flags |= UART_CONFIG_IRQ;
+
+               /*
+                * This will claim the ports resources if
+                * a port is found.
+                */
+               uport->ops->config_port(uport, flags);
+
+               ret = uart_startup(tty, state, 1);
+       }
+       mutex_unlock(&port->mutex);
+       return ret;
+}
+
+/*
+ * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+ * - mask passed in arg for lines of interest
+ *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+ * Caller should use TIOCGICOUNT to see which one it was
+ *
+ * FIXME: This wants extracting into a common all driver implementation
+ * of TIOCMWAIT using tty_port.
+ */
+static int
+uart_wait_modem_status(struct uart_state *state, unsigned long arg)
+{
+       struct uart_port *uport = state->uart_port;
+       struct tty_port *port = &state->port;
+       DECLARE_WAITQUEUE(wait, current);
+       struct uart_icount cprev, cnow;
+       int ret;
+
+       /*
+        * note the counters on entry
+        */
+       spin_lock_irq(&uport->lock);
+       memcpy(&cprev, &uport->icount, sizeof(struct uart_icount));
+
+       /*
+        * Force modem status interrupts on
+        */
+       uport->ops->enable_ms(uport);
+       spin_unlock_irq(&uport->lock);
+
+       add_wait_queue(&port->delta_msr_wait, &wait);
+       for (;;) {
+               spin_lock_irq(&uport->lock);
+               memcpy(&cnow, &uport->icount, sizeof(struct uart_icount));
+               spin_unlock_irq(&uport->lock);
+
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+                   ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+                   ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
+                   ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
+                       ret = 0;
+                       break;
+               }
+
+               schedule();
+
+               /* see if a signal did it */
+               if (signal_pending(current)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+
+               cprev = cnow;
+       }
+
+       current->state = TASK_RUNNING;
+       remove_wait_queue(&port->delta_msr_wait, &wait);
+
+       return ret;
+}
+
+/*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * Return: write counters to the user passed counter struct
+ * NB: both 1->0 and 0->1 transitions are counted except for
+ *     RI where only 0->1 is counted.
+ */
+static int uart_get_icount(struct tty_struct *tty,
+                         struct serial_icounter_struct *icount)
+{
+       struct uart_state *state = tty->driver_data;
+       struct uart_icount cnow;
+       struct uart_port *uport = state->uart_port;
+
+       spin_lock_irq(&uport->lock);
+       memcpy(&cnow, &uport->icount, sizeof(struct uart_icount));
+       spin_unlock_irq(&uport->lock);
+
+       icount->cts         = cnow.cts;
+       icount->dsr         = cnow.dsr;
+       icount->rng         = cnow.rng;
+       icount->dcd         = cnow.dcd;
+       icount->rx          = cnow.rx;
+       icount->tx          = cnow.tx;
+       icount->frame       = cnow.frame;
+       icount->overrun     = cnow.overrun;
+       icount->parity      = cnow.parity;
+       icount->brk         = cnow.brk;
+       icount->buf_overrun = cnow.buf_overrun;
+
+       return 0;
+}
+
+/*
+ * Called via sys_ioctl.  We can use spin_lock_irq() here.
+ */
+static int
+uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
+          unsigned long arg)
+{
+       struct uart_state *state = tty->driver_data;
+       struct tty_port *port = &state->port;
+       void __user *uarg = (void __user *)arg;
+       int ret = -ENOIOCTLCMD;
+
+
+       /*
+        * These ioctls don't rely on the hardware to be present.
+        */
+       switch (cmd) {
+       case TIOCGSERIAL:
+               ret = uart_get_info(state, uarg);
+               break;
+
+       case TIOCSSERIAL:
+               ret = uart_set_info(tty, state, uarg);
+               break;
+
+       case TIOCSERCONFIG:
+               ret = uart_do_autoconfig(tty, state);
+               break;
+
+       case TIOCSERGWILD: /* obsolete */
+       case TIOCSERSWILD: /* obsolete */
+               ret = 0;
+               break;
+       }
+
+       if (ret != -ENOIOCTLCMD)
+               goto out;
+
+       if (tty->flags & (1 << TTY_IO_ERROR)) {
+               ret = -EIO;
+               goto out;
+       }
+
+       /*
+        * The following should only be used when hardware is present.
+        */
+       switch (cmd) {
+       case TIOCMIWAIT:
+               ret = uart_wait_modem_status(state, arg);
+               break;
+       }
+
+       if (ret != -ENOIOCTLCMD)
+               goto out;
+
+       mutex_lock(&port->mutex);
+
+       if (tty_hung_up_p(filp)) {
+               ret = -EIO;
+               goto out_up;
+       }
+
+       /*
+        * All these rely on hardware being present and need to be
+        * protected against the tty being hung up.
+        */
+       switch (cmd) {
+       case TIOCSERGETLSR: /* Get line status register */
+               ret = uart_get_lsr_info(tty, state, uarg);
+               break;
+
+       default: {
+               struct uart_port *uport = state->uart_port;
+               if (uport->ops->ioctl)
+                       ret = uport->ops->ioctl(uport, cmd, arg);
+               break;
+       }
+       }
+out_up:
+       mutex_unlock(&port->mutex);
+out:
+       return ret;
+}
+
+static void uart_set_ldisc(struct tty_struct *tty)
+{
+       struct uart_state *state = tty->driver_data;
+       struct uart_port *uport = state->uart_port;
+
+       if (uport->ops->set_ldisc)
+               uport->ops->set_ldisc(uport, tty->termios->c_line);
+}
+
+static void uart_set_termios(struct tty_struct *tty,
+                                               struct ktermios *old_termios)
+{
+       struct uart_state *state = tty->driver_data;
+       unsigned long flags;
+       unsigned int cflag = tty->termios->c_cflag;
+
+
+       /*
+        * These are the bits that are used to setup various
+        * flags in the low level driver. We can ignore the Bfoo
+        * bits in c_cflag; c_[io]speed will always be set
+        * appropriately by set_termios() in tty_ioctl.c
+        */
+#define RELEVANT_IFLAG(iflag)  ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+       if ((cflag ^ old_termios->c_cflag) == 0 &&
+           tty->termios->c_ospeed == old_termios->c_ospeed &&
+           tty->termios->c_ispeed == old_termios->c_ispeed &&
+           RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) {
+               return;
+       }
+
+       uart_change_speed(tty, state, old_termios);
+
+       /* Handle transition to B0 status */
+       if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
+               uart_clear_mctrl(state->uart_port, TIOCM_RTS | TIOCM_DTR);
+       /* Handle transition away from B0 status */
+       else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
+               unsigned int mask = TIOCM_DTR;
+               if (!(cflag & CRTSCTS) ||
+                   !test_bit(TTY_THROTTLED, &tty->flags))
+                       mask |= TIOCM_RTS;
+               uart_set_mctrl(state->uart_port, mask);
+       }
+
+       /* Handle turning off CRTSCTS */
+       if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) {
+               spin_lock_irqsave(&state->uart_port->lock, flags);
+               tty->hw_stopped = 0;
+               __uart_start(tty);
+               spin_unlock_irqrestore(&state->uart_port->lock, flags);
+       }
+       /* Handle turning on CRTSCTS */
+       else if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
+               spin_lock_irqsave(&state->uart_port->lock, flags);
+               if (!(state->uart_port->ops->get_mctrl(state->uart_port) & TIOCM_CTS)) {
+                       tty->hw_stopped = 1;
+                       state->uart_port->ops->stop_tx(state->uart_port);
+               }
+               spin_unlock_irqrestore(&state->uart_port->lock, flags);
+       }
+#if 0
+       /*
+        * No need to wake up processes in open wait, since they
+        * sample the CLOCAL flag once, and don't recheck it.
+        * XXX  It's not clear whether the current behavior is correct
+        * or not.  Hence, this may change.....
+        */
+       if (!(old_termios->c_cflag & CLOCAL) &&
+           (tty->termios->c_cflag & CLOCAL))
+               wake_up_interruptible(&state->uart_port.open_wait);
+#endif
+}
+
+/*
+ * In 2.4.5, calls to this will be serialized via the BKL in
+ *  linux/drivers/char/tty_io.c:tty_release()
+ *  linux/drivers/char/tty_io.c:do_tty_handup()
+ */
+static void uart_close(struct tty_struct *tty, struct file *filp)
+{
+       struct uart_state *state = tty->driver_data;
+       struct tty_port *port;
+       struct uart_port *uport;
+       unsigned long flags;
+
+       BUG_ON(!tty_locked());
+
+       if (!state)
+               return;
+
+       uport = state->uart_port;
+       port = &state->port;
+
+       pr_debug("uart_close(%d) called\n", uport->line);
+
+       mutex_lock(&port->mutex);
+       spin_lock_irqsave(&port->lock, flags);
+
+       if (tty_hung_up_p(filp)) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               goto done;
+       }
+
+       if ((tty->count == 1) && (port->count != 1)) {
+               /*
+                * Uh, oh.  tty->count is 1, which means that the tty
+                * structure will be freed.  port->count should always
+                * be one in these conditions.  If it's greater than
+                * one, we've got real problems, since it means the
+                * serial port won't be shutdown.
+                */
+               printk(KERN_ERR "uart_close: bad serial port count; tty->count is 1, "
+                      "port->count is %d\n", port->count);
+               port->count = 1;
+       }
+       if (--port->count < 0) {
+               printk(KERN_ERR "uart_close: bad serial port count for %s: %d\n",
+                      tty->name, port->count);
+               port->count = 0;
+       }
+       if (port->count) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               goto done;
+       }
+
+       /*
+        * Now we wait for the transmit buffer to clear; and we notify
+        * the line discipline to only process XON/XOFF characters by
+        * setting tty->closing.
+        */
+       tty->closing = 1;
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) {
+               /*
+                * hack: open-coded tty_wait_until_sent to avoid
+                * recursive tty_lock
+                */
+               long timeout = msecs_to_jiffies(port->closing_wait);
+               if (wait_event_interruptible_timeout(tty->write_wait,
+                               !tty_chars_in_buffer(tty), timeout) >= 0)
+                       __uart_wait_until_sent(uport, timeout);
+       }
+
+       /*
+        * At this point, we stop accepting input.  To do this, we
+        * disable the receive line status interrupts.
+        */
+       if (port->flags & ASYNC_INITIALIZED) {
+               unsigned long flags;
+               spin_lock_irqsave(&uport->lock, flags);
+               uport->ops->stop_rx(uport);
+               spin_unlock_irqrestore(&uport->lock, flags);
+               /*
+                * Before we drop DTR, make sure the UART transmitter
+                * has completely drained; this is especially
+                * important if there is a transmit FIFO!
+                */
+               __uart_wait_until_sent(uport, uport->timeout);
+       }
+
+       uart_shutdown(tty, state);
+       uart_flush_buffer(tty);
+
+       tty_ldisc_flush(tty);
+
+       tty_port_tty_set(port, NULL);
+       spin_lock_irqsave(&port->lock, flags);
+       tty->closing = 0;
+
+       if (port->blocked_open) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               if (port->close_delay)
+                       msleep_interruptible(port->close_delay);
+               spin_lock_irqsave(&port->lock, flags);
+       } else if (!uart_console(uport)) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               uart_change_pm(state, 3);
+               spin_lock_irqsave(&port->lock, flags);
+       }
+
+       /*
+        * Wake up anyone trying to open this port.
+        */
+       clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
+       spin_unlock_irqrestore(&port->lock, flags);
+       wake_up_interruptible(&port->open_wait);
+
+done:
+       mutex_unlock(&port->mutex);
+}
+
+static void __uart_wait_until_sent(struct uart_port *port, int timeout)
+{
+       unsigned long char_time, expire;
+
+       if (port->type == PORT_UNKNOWN || port->fifosize == 0)
+               return;
+
+       /*
+        * Set the check interval to be 1/5 of the estimated time to
+        * send a single character, and make it at least 1.  The check
+        * interval should also be less than the timeout.
+        *
+        * Note: we have to use pretty tight timings here to satisfy
+        * the NIST-PCTS.
+        */
+       char_time = (port->timeout - HZ/50) / port->fifosize;
+       char_time = char_time / 5;
+       if (char_time == 0)
+               char_time = 1;
+       if (timeout && timeout < char_time)
+               char_time = timeout;
+
+       /*
+        * If the transmitter hasn't cleared in twice the approximate
+        * amount of time to send the entire FIFO, it probably won't
+        * ever clear.  This assumes the UART isn't doing flow
+        * control, which is currently the case.  Hence, if it ever
+        * takes longer than port->timeout, this is probably due to a
+        * UART bug of some kind.  So, we clamp the timeout parameter at
+        * 2*port->timeout.
+        */
+       if (timeout == 0 || timeout > 2 * port->timeout)
+               timeout = 2 * port->timeout;
+
+       expire = jiffies + timeout;
+
+       pr_debug("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n",
+               port->line, jiffies, expire);
+
+       /*
+        * Check whether the transmitter is empty every 'char_time'.
+        * 'timeout' / 'expire' give us the maximum amount of time
+        * we wait.
+        */
+       while (!port->ops->tx_empty(port)) {
+               msleep_interruptible(jiffies_to_msecs(char_time));
+               if (signal_pending(current))
+                       break;
+               if (time_after(jiffies, expire))
+                       break;
+       }
+       set_current_state(TASK_RUNNING); /* might not be needed */
+}
+
+static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+       struct uart_state *state = tty->driver_data;
+       struct uart_port *port = state->uart_port;
+
+       tty_lock();
+       __uart_wait_until_sent(port, timeout);
+       tty_unlock();
+}
+
+/*
+ * This is called with the BKL held in
+ *  linux/drivers/char/tty_io.c:do_tty_hangup()
+ * We're called from the eventd thread, so we can sleep for
+ * a _short_ time only.
+ */
+static void uart_hangup(struct tty_struct *tty)
+{
+       struct uart_state *state = tty->driver_data;
+       struct tty_port *port = &state->port;
+       unsigned long flags;
+
+       BUG_ON(!tty_locked());
+       pr_debug("uart_hangup(%d)\n", state->uart_port->line);
+
+       mutex_lock(&port->mutex);
+       if (port->flags & ASYNC_NORMAL_ACTIVE) {
+               uart_flush_buffer(tty);
+               uart_shutdown(tty, state);
+               spin_lock_irqsave(&port->lock, flags);
+               port->count = 0;
+               clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
+               spin_unlock_irqrestore(&port->lock, flags);
+               tty_port_tty_set(port, NULL);
+               wake_up_interruptible(&port->open_wait);
+               wake_up_interruptible(&port->delta_msr_wait);
+       }
+       mutex_unlock(&port->mutex);
+}
+
+/**
+ *     uart_update_termios     -       update the terminal hw settings
+ *     @tty: tty associated with UART
+ *     @state: UART to update
+ *
+ *     Copy across the serial console cflag setting into the termios settings
+ *     for the initial open of the port.  This allows continuity between the
+ *     kernel settings, and the settings init adopts when it opens the port
+ *     for the first time.
+ */
+static void uart_update_termios(struct tty_struct *tty,
+                                               struct uart_state *state)
+{
+       struct uart_port *port = state->uart_port;
+
+       if (uart_console(port) && port->cons->cflag) {
+               tty->termios->c_cflag = port->cons->cflag;
+               port->cons->cflag = 0;
+       }
+
+       /*
+        * If the device failed to grab its irq resources,
+        * or some other error occurred, don't try to talk
+        * to the port hardware.
+        */
+       if (!(tty->flags & (1 << TTY_IO_ERROR))) {
+               /*
+                * Make termios settings take effect.
+                */
+               uart_change_speed(tty, state, NULL);
+
+               /*
+                * And finally enable the RTS and DTR signals.
+                */
+               if (tty->termios->c_cflag & CBAUD)
+                       uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+       }
+}
+
+static int uart_carrier_raised(struct tty_port *port)
+{
+       struct uart_state *state = container_of(port, struct uart_state, port);
+       struct uart_port *uport = state->uart_port;
+       int mctrl;
+       spin_lock_irq(&uport->lock);
+       uport->ops->enable_ms(uport);
+       mctrl = uport->ops->get_mctrl(uport);
+       spin_unlock_irq(&uport->lock);
+       if (mctrl & TIOCM_CAR)
+               return 1;
+       return 0;
+}
+
+static void uart_dtr_rts(struct tty_port *port, int onoff)
+{
+       struct uart_state *state = container_of(port, struct uart_state, port);
+       struct uart_port *uport = state->uart_port;
+
+       if (onoff) {
+               uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
+
+               /*
+                * If this is the first open to succeed,
+                * adjust things to suit.
+                */
+               if (!test_and_set_bit(ASYNCB_NORMAL_ACTIVE, &port->flags))
+                       uart_update_termios(port->tty, state);
+       }
+       else
+               uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
+}
+
+static struct uart_state *uart_get(struct uart_driver *drv, int line)
+{
+       struct uart_state *state;
+       struct tty_port *port;
+       int ret = 0;
+
+       state = drv->state + line;
+       port = &state->port;
+       if (mutex_lock_interruptible(&port->mutex)) {
+               ret = -ERESTARTSYS;
+               goto err;
+       }
+
+       port->count++;
+       if (!state->uart_port || state->uart_port->flags & UPF_DEAD) {
+               ret = -ENXIO;
+               goto err_unlock;
+       }
+       return state;
+
+ err_unlock:
+       port->count--;
+       mutex_unlock(&port->mutex);
+ err:
+       return ERR_PTR(ret);
+}
+
+/*
+ * calls to uart_open are serialised by the BKL in
+ *   fs/char_dev.c:chrdev_open()
+ * Note that if this fails, then uart_close() _will_ be called.
+ *
+ * In time, we want to scrap the "opening nonpresent ports"
+ * behaviour and implement an alternative way for setserial
+ * to set base addresses/ports/types.  This will allow us to
+ * get rid of a certain amount of extra tests.
+ */
+static int uart_open(struct tty_struct *tty, struct file *filp)
+{
+       struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state;
+       struct uart_state *state;
+       struct tty_port *port;
+       int retval, line = tty->index;
+
+       BUG_ON(!tty_locked());
+       pr_debug("uart_open(%d) called\n", line);
+
+       /*
+        * tty->driver->num won't change, so we won't fail here with
+        * tty->driver_data set to something non-NULL (and therefore
+        * we won't get caught by uart_close()).
+        */
+       retval = -ENODEV;
+       if (line >= tty->driver->num)
+               goto fail;
+
+       /*
+        * We take the semaphore inside uart_get to guarantee that we won't
+        * be re-entered while allocating the state structure, or while we
+        * request any IRQs that the driver may need.  This also has the nice
+        * side-effect that it delays the action of uart_hangup, so we can
+        * guarantee that state->port.tty will always contain something
+        * reasonable.
+        */
+       state = uart_get(drv, line);
+       if (IS_ERR(state)) {
+               retval = PTR_ERR(state);
+               goto fail;
+       }
+       port = &state->port;
+
+       /*
+        * Once we set tty->driver_data here, we are guaranteed that
+        * uart_close() will decrement the driver module use count.
+        * Any failures from here onwards should not touch the count.
+        */
+       tty->driver_data = state;
+       state->uart_port->state = state;
+       tty->low_latency = (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0;
+       tty->alt_speed = 0;
+       tty_port_tty_set(port, tty);
+
+       /*
+        * If the port is in the middle of closing, bail out now.
+        */
+       if (tty_hung_up_p(filp)) {
+               retval = -EAGAIN;
+               port->count--;
+               mutex_unlock(&port->mutex);
+               goto fail;
+       }
+
+       /*
+        * Make sure the device is in D0 state.
+        */
+       if (port->count == 1)
+               uart_change_pm(state, 0);
+
+       /*
+        * Start up the serial port.
+        */
+       retval = uart_startup(tty, state, 0);
+
+       /*
+        * If we succeeded, wait until the port is ready.
+        */
+       mutex_unlock(&port->mutex);
+       if (retval == 0)
+               retval = tty_port_block_til_ready(port, tty, filp);
+
+fail:
+       return retval;
+}
+
+static const char *uart_type(struct uart_port *port)
+{
+       const char *str = NULL;
+
+       if (port->ops->type)
+               str = port->ops->type(port);
+
+       if (!str)
+               str = "unknown";
+
+       return str;
+}
+
+#ifdef CONFIG_PROC_FS
+
+static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
+{
+       struct uart_state *state = drv->state + i;
+       struct tty_port *port = &state->port;
+       int pm_state;
+       struct uart_port *uport = state->uart_port;
+       char stat_buf[32];
+       unsigned int status;
+       int mmio;
+
+       if (!uport)
+               return;
+
+       mmio = uport->iotype >= UPIO_MEM;
+       seq_printf(m, "%d: uart:%s %s%08llX irq:%d",
+                       uport->line, uart_type(uport),
+                       mmio ? "mmio:0x" : "port:",
+                       mmio ? (unsigned long long)uport->mapbase
+                            : (unsigned long long)uport->iobase,
+                       uport->irq);
+
+       if (uport->type == PORT_UNKNOWN) {
+               seq_putc(m, '\n');
+               return;
+       }
+
+       if (capable(CAP_SYS_ADMIN)) {
+               mutex_lock(&port->mutex);
+               pm_state = state->pm_state;
+               if (pm_state)
+                       uart_change_pm(state, 0);
+               spin_lock_irq(&uport->lock);
+               status = uport->ops->get_mctrl(uport);
+               spin_unlock_irq(&uport->lock);
+               if (pm_state)
+                       uart_change_pm(state, pm_state);
+               mutex_unlock(&port->mutex);
+
+               seq_printf(m, " tx:%d rx:%d",
+                               uport->icount.tx, uport->icount.rx);
+               if (uport->icount.frame)
+                       seq_printf(m, " fe:%d",
+                               uport->icount.frame);
+               if (uport->icount.parity)
+                       seq_printf(m, " pe:%d",
+                               uport->icount.parity);
+               if (uport->icount.brk)
+                       seq_printf(m, " brk:%d",
+                               uport->icount.brk);
+               if (uport->icount.overrun)
+                       seq_printf(m, " oe:%d",
+                               uport->icount.overrun);
+
+#define INFOBIT(bit, str) \
+       if (uport->mctrl & (bit)) \
+               strncat(stat_buf, (str), sizeof(stat_buf) - \
+                       strlen(stat_buf) - 2)
+#define STATBIT(bit, str) \
+       if (status & (bit)) \
+               strncat(stat_buf, (str), sizeof(stat_buf) - \
+                      strlen(stat_buf) - 2)
+
+               stat_buf[0] = '\0';
+               stat_buf[1] = '\0';
+               INFOBIT(TIOCM_RTS, "|RTS");
+               STATBIT(TIOCM_CTS, "|CTS");
+               INFOBIT(TIOCM_DTR, "|DTR");
+               STATBIT(TIOCM_DSR, "|DSR");
+               STATBIT(TIOCM_CAR, "|CD");
+               STATBIT(TIOCM_RNG, "|RI");
+               if (stat_buf[0])
+                       stat_buf[0] = ' ';
+
+               seq_puts(m, stat_buf);
+       }
+       seq_putc(m, '\n');
+#undef STATBIT
+#undef INFOBIT
+}
+
+static int uart_proc_show(struct seq_file *m, void *v)
+{
+       struct tty_driver *ttydrv = m->private;
+       struct uart_driver *drv = ttydrv->driver_state;
+       int i;
+
+       seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n",
+                       "", "", "");
+       for (i = 0; i < drv->nr; i++)
+               uart_line_info(m, drv, i);
+       return 0;
+}
+
+static int uart_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, uart_proc_show, PDE(inode)->data);
+}
+
+static const struct file_operations uart_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = uart_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+#endif
+
+#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
+/*
+ *     uart_console_write - write a console message to a serial port
+ *     @port: the port to write the message
+ *     @s: array of characters
+ *     @count: number of characters in string to write
+ *     @write: function to write character to port
+ */
+void uart_console_write(struct uart_port *port, const char *s,
+                       unsigned int count,
+                       void (*putchar)(struct uart_port *, int))
+{
+       unsigned int i;
+
+       for (i = 0; i < count; i++, s++) {
+               if (*s == '\n')
+                       putchar(port, '\r');
+               putchar(port, *s);
+       }
+}
+EXPORT_SYMBOL_GPL(uart_console_write);
+
+/*
+ *     Check whether an invalid uart number has been specified, and
+ *     if so, search for the first available port that does have
+ *     console support.
+ */
+struct uart_port * __init
+uart_get_console(struct uart_port *ports, int nr, struct console *co)
+{
+       int idx = co->index;
+
+       if (idx < 0 || idx >= nr || (ports[idx].iobase == 0 &&
+                                    ports[idx].membase == NULL))
+               for (idx = 0; idx < nr; idx++)
+                       if (ports[idx].iobase != 0 ||
+                           ports[idx].membase != NULL)
+                               break;
+
+       co->index = idx;
+
+       return ports + idx;
+}
+
+/**
+ *     uart_parse_options - Parse serial port baud/parity/bits/flow contro.
+ *     @options: pointer to option string
+ *     @baud: pointer to an 'int' variable for the baud rate.
+ *     @parity: pointer to an 'int' variable for the parity.
+ *     @bits: pointer to an 'int' variable for the number of data bits.
+ *     @flow: pointer to an 'int' variable for the flow control character.
+ *
+ *     uart_parse_options decodes a string containing the serial console
+ *     options.  The format of the string is <baud><parity><bits><flow>,
+ *     eg: 115200n8r
+ */
+void
+uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow)
+{
+       char *s = options;
+
+       *baud = simple_strtoul(s, NULL, 10);
+       while (*s >= '0' && *s <= '9')
+               s++;
+       if (*s)
+               *parity = *s++;
+       if (*s)
+               *bits = *s++ - '0';
+       if (*s)
+               *flow = *s;
+}
+EXPORT_SYMBOL_GPL(uart_parse_options);
+
+struct baud_rates {
+       unsigned int rate;
+       unsigned int cflag;
+};
+
+static const struct baud_rates baud_rates[] = {
+       { 921600, B921600 },
+       { 460800, B460800 },
+       { 230400, B230400 },
+       { 115200, B115200 },
+       {  57600, B57600  },
+       {  38400, B38400  },
+       {  19200, B19200  },
+       {   9600, B9600   },
+       {   4800, B4800   },
+       {   2400, B2400   },
+       {   1200, B1200   },
+       {      0, B38400  }
+};
+
+/**
+ *     uart_set_options - setup the serial console parameters
+ *     @port: pointer to the serial ports uart_port structure
+ *     @co: console pointer
+ *     @baud: baud rate
+ *     @parity: parity character - 'n' (none), 'o' (odd), 'e' (even)
+ *     @bits: number of data bits
+ *     @flow: flow control character - 'r' (rts)
+ */
+int
+uart_set_options(struct uart_port *port, struct console *co,
+                int baud, int parity, int bits, int flow)
+{
+       struct ktermios termios;
+       static struct ktermios dummy;
+       int i;
+
+       /*
+        * Ensure that the serial console lock is initialised
+        * early.
+        */
+       spin_lock_init(&port->lock);
+       lockdep_set_class(&port->lock, &port_lock_key);
+
+       memset(&termios, 0, sizeof(struct ktermios));
+
+       termios.c_cflag = CREAD | HUPCL | CLOCAL;
+
+       /*
+        * Construct a cflag setting.
+        */
+       for (i = 0; baud_rates[i].rate; i++)
+               if (baud_rates[i].rate <= baud)
+                       break;
+
+       termios.c_cflag |= baud_rates[i].cflag;
+
+       if (bits == 7)
+               termios.c_cflag |= CS7;
+       else
+               termios.c_cflag |= CS8;
+
+       switch (parity) {
+       case 'o': case 'O':
+               termios.c_cflag |= PARODD;
+               /*fall through*/
+       case 'e': case 'E':
+               termios.c_cflag |= PARENB;
+               break;
+       }
+
+       if (flow == 'r')
+               termios.c_cflag |= CRTSCTS;
+
+       /*
+        * some uarts on other side don't support no flow control.
+        * So we set * DTR in host uart to make them happy
+        */
+       port->mctrl |= TIOCM_DTR;
+
+       port->ops->set_termios(port, &termios, &dummy);
+       /*
+        * Allow the setting of the UART parameters with a NULL console
+        * too:
+        */
+       if (co)
+               co->cflag = termios.c_cflag;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(uart_set_options);
+#endif /* CONFIG_SERIAL_CORE_CONSOLE */
+
+static void uart_change_pm(struct uart_state *state, int pm_state)
+{
+       struct uart_port *port = state->uart_port;
+
+       if (state->pm_state != pm_state) {
+               if (port->ops->pm)
+                       port->ops->pm(port, pm_state, state->pm_state);
+               state->pm_state = pm_state;
+       }
+}
+
+struct uart_match {
+       struct uart_port *port;
+       struct uart_driver *driver;
+};
+
+static int serial_match_port(struct device *dev, void *data)
+{
+       struct uart_match *match = data;
+       struct tty_driver *tty_drv = match->driver->tty_driver;
+       dev_t devt = MKDEV(tty_drv->major, tty_drv->minor_start) +
+               match->port->line;
+
+       return dev->devt == devt; /* Actually, only one tty per port */
+}
+
+int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
+{
+       struct uart_state *state = drv->state + uport->line;
+       struct tty_port *port = &state->port;
+       struct device *tty_dev;
+       struct uart_match match = {uport, drv};
+       struct tty_struct *tty;
+
+       mutex_lock(&port->mutex);
+
+       /* Must be inside the mutex lock until we convert to tty_port */
+       tty = port->tty;
+
+       tty_dev = device_find_child(uport->dev, &match, serial_match_port);
+       if (device_may_wakeup(tty_dev)) {
+               if (!enable_irq_wake(uport->irq))
+                       uport->irq_wake = 1;
+               put_device(tty_dev);
+               mutex_unlock(&port->mutex);
+               return 0;
+       }
+       if (console_suspend_enabled || !uart_console(uport))
+               uport->suspended = 1;
+
+       if (port->flags & ASYNC_INITIALIZED) {
+               const struct uart_ops *ops = uport->ops;
+               int tries;
+
+               if (console_suspend_enabled || !uart_console(uport)) {
+                       set_bit(ASYNCB_SUSPENDED, &port->flags);
+                       clear_bit(ASYNCB_INITIALIZED, &port->flags);
+
+                       spin_lock_irq(&uport->lock);
+                       ops->stop_tx(uport);
+                       ops->set_mctrl(uport, 0);
+                       ops->stop_rx(uport);
+                       spin_unlock_irq(&uport->lock);
+               }
+
+               /*
+                * Wait for the transmitter to empty.
+                */
+               for (tries = 3; !ops->tx_empty(uport) && tries; tries--)
+                       msleep(10);
+               if (!tries)
+                       printk(KERN_ERR "%s%s%s%d: Unable to drain "
+                                       "transmitter\n",
+                              uport->dev ? dev_name(uport->dev) : "",
+                              uport->dev ? ": " : "",
+                              drv->dev_name,
+                              drv->tty_driver->name_base + uport->line);
+
+               if (console_suspend_enabled || !uart_console(uport))
+                       ops->shutdown(uport);
+       }
+
+       /*
+        * Disable the console device before suspending.
+        */
+       if (console_suspend_enabled && uart_console(uport))
+               console_stop(uport->cons);
+
+       if (console_suspend_enabled || !uart_console(uport))
+               uart_change_pm(state, 3);
+
+       mutex_unlock(&port->mutex);
+
+       return 0;
+}
+
+int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
+{
+       struct uart_state *state = drv->state + uport->line;
+       struct tty_port *port = &state->port;
+       struct device *tty_dev;
+       struct uart_match match = {uport, drv};
+       struct ktermios termios;
+
+       mutex_lock(&port->mutex);
+
+       tty_dev = device_find_child(uport->dev, &match, serial_match_port);
+       if (!uport->suspended && device_may_wakeup(tty_dev)) {
+               if (uport->irq_wake) {
+                       disable_irq_wake(uport->irq);
+                       uport->irq_wake = 0;
+               }
+               mutex_unlock(&port->mutex);
+               return 0;
+       }
+       uport->suspended = 0;
+
+       /*
+        * Re-enable the console device after suspending.
+        */
+       if (console_suspend_enabled && uart_console(uport)) {
+               /*
+                * First try to use the console cflag setting.
+                */
+               memset(&termios, 0, sizeof(struct ktermios));
+               termios.c_cflag = uport->cons->cflag;
+
+               /*
+                * If that's unset, use the tty termios setting.
+                */
+               if (port->tty && port->tty->termios && termios.c_cflag == 0)
+                       termios = *(port->tty->termios);
+
+               uart_change_pm(state, 0);
+               uport->ops->set_termios(uport, &termios, NULL);
+               console_start(uport->cons);
+       }
+
+       if (port->flags & ASYNC_SUSPENDED) {
+               const struct uart_ops *ops = uport->ops;
+               int ret;
+
+               uart_change_pm(state, 0);
+               spin_lock_irq(&uport->lock);
+               ops->set_mctrl(uport, 0);
+               spin_unlock_irq(&uport->lock);
+               if (console_suspend_enabled || !uart_console(uport)) {
+                       /* Protected by port mutex for now */
+                       struct tty_struct *tty = port->tty;
+                       ret = ops->startup(uport);
+                       if (ret == 0) {
+                               if (tty)
+                                       uart_change_speed(tty, state, NULL);
+                               spin_lock_irq(&uport->lock);
+                               ops->set_mctrl(uport, uport->mctrl);
+                               ops->start_tx(uport);
+                               spin_unlock_irq(&uport->lock);
+                               set_bit(ASYNCB_INITIALIZED, &port->flags);
+                       } else {
+                               /*
+                                * Failed to resume - maybe hardware went away?
+                                * Clear the "initialized" flag so we won't try
+                                * to call the low level drivers shutdown method.
+                                */
+                               uart_shutdown(tty, state);
+                       }
+               }
+
+               clear_bit(ASYNCB_SUSPENDED, &port->flags);
+       }
+
+       mutex_unlock(&port->mutex);
+
+       return 0;
+}
+
+static inline void
+uart_report_port(struct uart_driver *drv, struct uart_port *port)
+{
+       char address[64];
+
+       switch (port->iotype) {
+       case UPIO_PORT:
+               snprintf(address, sizeof(address), "I/O 0x%lx", port->iobase);
+               break;
+       case UPIO_HUB6:
+               snprintf(address, sizeof(address),
+                        "I/O 0x%lx offset 0x%x", port->iobase, port->hub6);
+               break;
+       case UPIO_MEM:
+       case UPIO_MEM32:
+       case UPIO_AU:
+       case UPIO_TSI:
+       case UPIO_DWAPB:
+       case UPIO_DWAPB32:
+               snprintf(address, sizeof(address),
+                        "MMIO 0x%llx", (unsigned long long)port->mapbase);
+               break;
+       default:
+               strlcpy(address, "*unknown*", sizeof(address));
+               break;
+       }
+
+       printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n",
+              port->dev ? dev_name(port->dev) : "",
+              port->dev ? ": " : "",
+              drv->dev_name,
+              drv->tty_driver->name_base + port->line,
+              address, port->irq, uart_type(port));
+}
+
+static void
+uart_configure_port(struct uart_driver *drv, struct uart_state *state,
+                   struct uart_port *port)
+{
+       unsigned int flags;
+
+       /*
+        * If there isn't a port here, don't do anything further.
+        */
+       if (!port->iobase && !port->mapbase && !port->membase)
+               return;
+
+       /*
+        * Now do the auto configuration stuff.  Note that config_port
+        * is expected to claim the resources and map the port for us.
+        */
+       flags = 0;
+       if (port->flags & UPF_AUTO_IRQ)
+               flags |= UART_CONFIG_IRQ;
+       if (port->flags & UPF_BOOT_AUTOCONF) {
+               if (!(port->flags & UPF_FIXED_TYPE)) {
+                       port->type = PORT_UNKNOWN;
+                       flags |= UART_CONFIG_TYPE;
+               }
+               port->ops->config_port(port, flags);
+       }
+
+       if (port->type != PORT_UNKNOWN) {
+               unsigned long flags;
+
+               uart_report_port(drv, port);
+
+               /* Power up port for set_mctrl() */
+               uart_change_pm(state, 0);
+
+               /*
+                * Ensure that the modem control lines are de-activated.
+                * keep the DTR setting that is set in uart_set_options()
+                * We probably don't need a spinlock around this, but
+                */
+               spin_lock_irqsave(&port->lock, flags);
+               port->ops->set_mctrl(port, port->mctrl & TIOCM_DTR);
+               spin_unlock_irqrestore(&port->lock, flags);
+
+               /*
+                * If this driver supports console, and it hasn't been
+                * successfully registered yet, try to re-register it.
+                * It may be that the port was not available.
+                */
+               if (port->cons && !(port->cons->flags & CON_ENABLED))
+                       register_console(port->cons);
+
+               /*
+                * Power down all ports by default, except the
+                * console if we have one.
+                */
+               if (!uart_console(port))
+                       uart_change_pm(state, 3);
+       }
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+
+static int uart_poll_init(struct tty_driver *driver, int line, char *options)
+{
+       struct uart_driver *drv = driver->driver_state;
+       struct uart_state *state = drv->state + line;
+       struct uart_port *port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (!state || !state->uart_port)
+               return -1;
+
+       port = state->uart_port;
+       if (!(port->ops->poll_get_char && port->ops->poll_put_char))
+               return -1;
+
+       if (options) {
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+               return uart_set_options(port, NULL, baud, parity, bits, flow);
+       }
+
+       return 0;
+}
+
+static int uart_poll_get_char(struct tty_driver *driver, int line)
+{
+       struct uart_driver *drv = driver->driver_state;
+       struct uart_state *state = drv->state + line;
+       struct uart_port *port;
+
+       if (!state || !state->uart_port)
+               return -1;
+
+       port = state->uart_port;
+       return port->ops->poll_get_char(port);
+}
+
+static void uart_poll_put_char(struct tty_driver *driver, int line, char ch)
+{
+       struct uart_driver *drv = driver->driver_state;
+       struct uart_state *state = drv->state + line;
+       struct uart_port *port;
+
+       if (!state || !state->uart_port)
+               return;
+
+       port = state->uart_port;
+       port->ops->poll_put_char(port, ch);
+}
+#endif
+
+static const struct tty_operations uart_ops = {
+       .open           = uart_open,
+       .close          = uart_close,
+       .write          = uart_write,
+       .put_char       = uart_put_char,
+       .flush_chars    = uart_flush_chars,
+       .write_room     = uart_write_room,
+       .chars_in_buffer= uart_chars_in_buffer,
+       .flush_buffer   = uart_flush_buffer,
+       .ioctl          = uart_ioctl,
+       .throttle       = uart_throttle,
+       .unthrottle     = uart_unthrottle,
+       .send_xchar     = uart_send_xchar,
+       .set_termios    = uart_set_termios,
+       .set_ldisc      = uart_set_ldisc,
+       .stop           = uart_stop,
+       .start          = uart_start,
+       .hangup         = uart_hangup,
+       .break_ctl      = uart_break_ctl,
+       .wait_until_sent= uart_wait_until_sent,
+#ifdef CONFIG_PROC_FS
+       .proc_fops      = &uart_proc_fops,
+#endif
+       .tiocmget       = uart_tiocmget,
+       .tiocmset       = uart_tiocmset,
+       .get_icount     = uart_get_icount,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_init      = uart_poll_init,
+       .poll_get_char  = uart_poll_get_char,
+       .poll_put_char  = uart_poll_put_char,
+#endif
+};
+
+static const struct tty_port_operations uart_port_ops = {
+       .carrier_raised = uart_carrier_raised,
+       .dtr_rts        = uart_dtr_rts,
+};
+
+/**
+ *     uart_register_driver - register a driver with the uart core layer
+ *     @drv: low level driver structure
+ *
+ *     Register a uart driver with the core driver.  We in turn register
+ *     with the tty layer, and initialise the core driver per-port state.
+ *
+ *     We have a proc file in /proc/tty/driver which is named after the
+ *     normal driver.
+ *
+ *     drv->port should be NULL, and the per-port structures should be
+ *     registered using uart_add_one_port after this call has succeeded.
+ */
+int uart_register_driver(struct uart_driver *drv)
+{
+       struct tty_driver *normal;
+       int i, retval;
+
+       BUG_ON(drv->state);
+
+       /*
+        * Maybe we should be using a slab cache for this, especially if
+        * we have a large number of ports to handle.
+        */
+       drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
+       if (!drv->state)
+               goto out;
+
+       normal = alloc_tty_driver(drv->nr);
+       if (!normal)
+               goto out_kfree;
+
+       drv->tty_driver = normal;
+
+       normal->owner           = drv->owner;
+       normal->driver_name     = drv->driver_name;
+       normal->name            = drv->dev_name;
+       normal->major           = drv->major;
+       normal->minor_start     = drv->minor;
+       normal->type            = TTY_DRIVER_TYPE_SERIAL;
+       normal->subtype         = SERIAL_TYPE_NORMAL;
+       normal->init_termios    = tty_std_termios;
+       normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+       normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
+       normal->flags           = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+       normal->driver_state    = drv;
+       tty_set_operations(normal, &uart_ops);
+
+       /*
+        * Initialise the UART state(s).
+        */
+       for (i = 0; i < drv->nr; i++) {
+               struct uart_state *state = drv->state + i;
+               struct tty_port *port = &state->port;
+
+               tty_port_init(port);
+               port->ops = &uart_port_ops;
+               port->close_delay     = 500;    /* .5 seconds */
+               port->closing_wait    = 30000;  /* 30 seconds */
+               tasklet_init(&state->tlet, uart_tasklet_action,
+                            (unsigned long)state);
+       }
+
+       retval = tty_register_driver(normal);
+       if (retval >= 0)
+               return retval;
+
+       put_tty_driver(normal);
+out_kfree:
+       kfree(drv->state);
+out:
+       return -ENOMEM;
+}
+
+/**
+ *     uart_unregister_driver - remove a driver from the uart core layer
+ *     @drv: low level driver structure
+ *
+ *     Remove all references to a driver from the core driver.  The low
+ *     level driver must have removed all its ports via the
+ *     uart_remove_one_port() if it registered them with uart_add_one_port().
+ *     (ie, drv->port == NULL)
+ */
+void uart_unregister_driver(struct uart_driver *drv)
+{
+       struct tty_driver *p = drv->tty_driver;
+       tty_unregister_driver(p);
+       put_tty_driver(p);
+       kfree(drv->state);
+       drv->tty_driver = NULL;
+}
+
+struct tty_driver *uart_console_device(struct console *co, int *index)
+{
+       struct uart_driver *p = co->data;
+       *index = co->index;
+       return p->tty_driver;
+}
+
+/**
+ *     uart_add_one_port - attach a driver-defined port structure
+ *     @drv: pointer to the uart low level driver structure for this port
+ *     @uport: uart port structure to use for this port.
+ *
+ *     This allows the driver to register its own uart_port structure
+ *     with the core driver.  The main purpose is to allow the low
+ *     level uart drivers to expand uart_port, rather than having yet
+ *     more levels of structures.
+ */
+int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
+{
+       struct uart_state *state;
+       struct tty_port *port;
+       int ret = 0;
+       struct device *tty_dev;
+
+       BUG_ON(in_interrupt());
+
+       if (uport->line >= drv->nr)
+               return -EINVAL;
+
+       state = drv->state + uport->line;
+       port = &state->port;
+
+       mutex_lock(&port_mutex);
+       mutex_lock(&port->mutex);
+       if (state->uart_port) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       state->uart_port = uport;
+       state->pm_state = -1;
+
+       uport->cons = drv->cons;
+       uport->state = state;
+
+       /*
+        * If this port is a console, then the spinlock is already
+        * initialised.
+        */
+       if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) {
+               spin_lock_init(&uport->lock);
+               lockdep_set_class(&uport->lock, &port_lock_key);
+       }
+
+       uart_configure_port(drv, state, uport);
+
+       /*
+        * Register the port whether it's detected or not.  This allows
+        * setserial to be used to alter this ports parameters.
+        */
+       tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev);
+       if (likely(!IS_ERR(tty_dev))) {
+               device_init_wakeup(tty_dev, 1);
+               device_set_wakeup_enable(tty_dev, 0);
+       } else
+               printk(KERN_ERR "Cannot register tty device on line %d\n",
+                      uport->line);
+
+       /*
+        * Ensure UPF_DEAD is not set.
+        */
+       uport->flags &= ~UPF_DEAD;
+
+ out:
+       mutex_unlock(&port->mutex);
+       mutex_unlock(&port_mutex);
+
+       return ret;
+}
+
+/**
+ *     uart_remove_one_port - detach a driver defined port structure
+ *     @drv: pointer to the uart low level driver structure for this port
+ *     @uport: uart port structure for this port
+ *
+ *     This unhooks (and hangs up) the specified port structure from the
+ *     core driver.  No further calls will be made to the low-level code
+ *     for this port.
+ */
+int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
+{
+       struct uart_state *state = drv->state + uport->line;
+       struct tty_port *port = &state->port;
+
+       BUG_ON(in_interrupt());
+
+       if (state->uart_port != uport)
+               printk(KERN_ALERT "Removing wrong port: %p != %p\n",
+                       state->uart_port, uport);
+
+       mutex_lock(&port_mutex);
+
+       /*
+        * Mark the port "dead" - this prevents any opens from
+        * succeeding while we shut down the port.
+        */
+       mutex_lock(&port->mutex);
+       uport->flags |= UPF_DEAD;
+       mutex_unlock(&port->mutex);
+
+       /*
+        * Remove the devices from the tty layer
+        */
+       tty_unregister_device(drv->tty_driver, uport->line);
+
+       if (port->tty)
+               tty_vhangup(port->tty);
+
+       /*
+        * Free the port IO and memory resources, if any.
+        */
+       if (uport->type != PORT_UNKNOWN)
+               uport->ops->release_port(uport);
+
+       /*
+        * Indicate that there isn't a port here anymore.
+        */
+       uport->type = PORT_UNKNOWN;
+
+       /*
+        * Kill the tasklet, and free resources.
+        */
+       tasklet_kill(&state->tlet);
+
+       state->uart_port = NULL;
+       mutex_unlock(&port_mutex);
+
+       return 0;
+}
+
+/*
+ *     Are the two ports equivalent?
+ */
+int uart_match_port(struct uart_port *port1, struct uart_port *port2)
+{
+       if (port1->iotype != port2->iotype)
+               return 0;
+
+       switch (port1->iotype) {
+       case UPIO_PORT:
+               return (port1->iobase == port2->iobase);
+       case UPIO_HUB6:
+               return (port1->iobase == port2->iobase) &&
+                      (port1->hub6   == port2->hub6);
+       case UPIO_MEM:
+       case UPIO_MEM32:
+       case UPIO_AU:
+       case UPIO_TSI:
+       case UPIO_DWAPB:
+       case UPIO_DWAPB32:
+               return (port1->mapbase == port2->mapbase);
+       }
+       return 0;
+}
+EXPORT_SYMBOL(uart_match_port);
+
+EXPORT_SYMBOL(uart_write_wakeup);
+EXPORT_SYMBOL(uart_register_driver);
+EXPORT_SYMBOL(uart_unregister_driver);
+EXPORT_SYMBOL(uart_suspend_port);
+EXPORT_SYMBOL(uart_resume_port);
+EXPORT_SYMBOL(uart_add_one_port);
+EXPORT_SYMBOL(uart_remove_one_port);
+
+MODULE_DESCRIPTION("Serial driver core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/serial_cs.c b/drivers/tty/serial/serial_cs.c
new file mode 100644 (file)
index 0000000..93760b2
--- /dev/null
@@ -0,0 +1,869 @@
+/*======================================================================
+
+    A driver for PCMCIA serial devices
+
+    serial_cs.c 1.134 2002/05/04 05:48:53
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU General Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/serial_core.h>
+#include <linux/delay.h>
+#include <linux/major.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+
+#include "8250.h"
+
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Enable the speaker? */
+static int do_sound = 1;
+/* Skip strict UART tests? */
+static int buggy_uart;
+
+module_param(do_sound, int, 0444);
+module_param(buggy_uart, int, 0444);
+
+/*====================================================================*/
+
+/* Table of multi-port card ID's */
+
+struct serial_quirk {
+       unsigned int manfid;
+       unsigned int prodid;
+       int multi;              /* 1 = multifunction, > 1 = # ports */
+       void (*config)(struct pcmcia_device *);
+       void (*setup)(struct pcmcia_device *, struct uart_port *);
+       void (*wakeup)(struct pcmcia_device *);
+       int (*post)(struct pcmcia_device *);
+};
+
+struct serial_info {
+       struct pcmcia_device    *p_dev;
+       int                     ndev;
+       int                     multi;
+       int                     slave;
+       int                     manfid;
+       int                     prodid;
+       int                     c950ctrl;
+       int                     line[4];
+       const struct serial_quirk *quirk;
+};
+
+struct serial_cfg_mem {
+       tuple_t tuple;
+       cisparse_t parse;
+       u_char buf[256];
+};
+
+/*
+ * vers_1 5.0, "Brain Boxes", "2-Port RS232 card", "r6"
+ * manfid 0x0160, 0x0104
+ * This card appears to have a 14.7456MHz clock.
+ */
+/* Generic Modem: MD55x (GPRS/EDGE) have
+ * Elan VPU16551 UART with 14.7456MHz oscillator
+ * manfid 0x015D, 0x4C45
+ */
+static void quirk_setup_brainboxes_0104(struct pcmcia_device *link, struct uart_port *port)
+{
+       port->uartclk = 14745600;
+}
+
+static int quirk_post_ibm(struct pcmcia_device *link)
+{
+       u8 val;
+       int ret;
+
+       ret = pcmcia_read_config_byte(link, 0x800, &val);
+       if (ret)
+               goto failed;
+
+       ret = pcmcia_write_config_byte(link, 0x800, val | 1);
+       if (ret)
+               goto failed;
+       return 0;
+
+ failed:
+       return -ENODEV;
+}
+
+/*
+ * Nokia cards are not really multiport cards.  Shouldn't this
+ * be handled by setting the quirk entry .multi = 0 | 1 ?
+ */
+static void quirk_config_nokia(struct pcmcia_device *link)
+{
+       struct serial_info *info = link->priv;
+
+       if (info->multi > 1)
+               info->multi = 1;
+}
+
+static void quirk_wakeup_oxsemi(struct pcmcia_device *link)
+{
+       struct serial_info *info = link->priv;
+
+       if (info->c950ctrl)
+               outb(12, info->c950ctrl + 1);
+}
+
+/* request_region? oxsemi branch does no request_region too... */
+/*
+ * This sequence is needed to properly initialize MC45 attached to OXCF950.
+ * I tried decreasing these msleep()s, but it worked properly (survived
+ * 1000 stop/start operations) with these timeouts (or bigger).
+ */
+static void quirk_wakeup_possio_gcc(struct pcmcia_device *link)
+{
+       struct serial_info *info = link->priv;
+       unsigned int ctrl = info->c950ctrl;
+
+       outb(0xA, ctrl + 1);
+       msleep(100);
+       outb(0xE, ctrl + 1);
+       msleep(300);
+       outb(0xC, ctrl + 1);
+       msleep(100);
+       outb(0xE, ctrl + 1);
+       msleep(200);
+       outb(0xF, ctrl + 1);
+       msleep(100);
+       outb(0xE, ctrl + 1);
+       msleep(100);
+       outb(0xC, ctrl + 1);
+}
+
+/*
+ * Socket Dual IO: this enables irq's for second port
+ */
+static void quirk_config_socket(struct pcmcia_device *link)
+{
+       struct serial_info *info = link->priv;
+
+       if (info->multi)
+               link->config_flags |= CONF_ENABLE_ESR;
+}
+
+static const struct serial_quirk quirks[] = {
+       {
+               .manfid = 0x0160,
+               .prodid = 0x0104,
+               .multi  = -1,
+               .setup  = quirk_setup_brainboxes_0104,
+       }, {
+               .manfid = 0x015D,
+               .prodid = 0x4C45,
+               .multi  = -1,
+               .setup  = quirk_setup_brainboxes_0104,
+       }, {
+               .manfid = MANFID_IBM,
+               .prodid = ~0,
+               .multi  = -1,
+               .post   = quirk_post_ibm,
+       }, {
+               .manfid = MANFID_INTEL,
+               .prodid = PRODID_INTEL_DUAL_RS232,
+               .multi  = 2,
+       }, {
+               .manfid = MANFID_NATINST,
+               .prodid = PRODID_NATINST_QUAD_RS232,
+               .multi  = 4,
+       }, {
+               .manfid = MANFID_NOKIA,
+               .prodid = ~0,
+               .multi  = -1,
+               .config = quirk_config_nokia,
+       }, {
+               .manfid = MANFID_OMEGA,
+               .prodid = PRODID_OMEGA_QSP_100,
+               .multi  = 4,
+       }, {
+               .manfid = MANFID_OXSEMI,
+               .prodid = ~0,
+               .multi  = -1,
+               .wakeup = quirk_wakeup_oxsemi,
+       }, {
+               .manfid = MANFID_POSSIO,
+               .prodid = PRODID_POSSIO_GCC,
+               .multi  = -1,
+               .wakeup = quirk_wakeup_possio_gcc,
+       }, {
+               .manfid = MANFID_QUATECH,
+               .prodid = PRODID_QUATECH_DUAL_RS232,
+               .multi  = 2,
+       }, {
+               .manfid = MANFID_QUATECH,
+               .prodid = PRODID_QUATECH_DUAL_RS232_D1,
+               .multi  = 2,
+       }, {
+               .manfid = MANFID_QUATECH,
+               .prodid = PRODID_QUATECH_DUAL_RS232_G,
+               .multi  = 2,
+       }, {
+               .manfid = MANFID_QUATECH,
+               .prodid = PRODID_QUATECH_QUAD_RS232,
+               .multi  = 4,
+       }, {
+               .manfid = MANFID_SOCKET,
+               .prodid = PRODID_SOCKET_DUAL_RS232,
+               .multi  = 2,
+               .config = quirk_config_socket,
+       }, {
+               .manfid = MANFID_SOCKET,
+               .prodid = ~0,
+               .multi  = -1,
+               .config = quirk_config_socket,
+       }
+};
+
+
+static int serial_config(struct pcmcia_device * link);
+
+
+static void serial_remove(struct pcmcia_device *link)
+{
+       struct serial_info *info = link->priv;
+       int i;
+
+       dev_dbg(&link->dev, "serial_release\n");
+
+       /*
+        * Recheck to see if the device is still configured.
+        */
+       for (i = 0; i < info->ndev; i++)
+               serial8250_unregister_port(info->line[i]);
+
+       if (!info->slave)
+               pcmcia_disable_device(link);
+}
+
+static int serial_suspend(struct pcmcia_device *link)
+{
+       struct serial_info *info = link->priv;
+       int i;
+
+       for (i = 0; i < info->ndev; i++)
+               serial8250_suspend_port(info->line[i]);
+
+       return 0;
+}
+
+static int serial_resume(struct pcmcia_device *link)
+{
+       struct serial_info *info = link->priv;
+       int i;
+
+       for (i = 0; i < info->ndev; i++)
+               serial8250_resume_port(info->line[i]);
+
+       if (info->quirk && info->quirk->wakeup)
+               info->quirk->wakeup(link);
+
+       return 0;
+}
+
+static int serial_probe(struct pcmcia_device *link)
+{
+       struct serial_info *info;
+
+       dev_dbg(&link->dev, "serial_attach()\n");
+
+       /* Create new serial device */
+       info = kzalloc(sizeof (*info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+       info->p_dev = link;
+       link->priv = info;
+
+       link->config_flags |= CONF_ENABLE_IRQ;
+       if (do_sound)
+               link->config_flags |= CONF_ENABLE_SPKR;
+
+       return serial_config(link);
+}
+
+static void serial_detach(struct pcmcia_device *link)
+{
+       struct serial_info *info = link->priv;
+
+       dev_dbg(&link->dev, "serial_detach\n");
+
+       /*
+        * Ensure that the ports have been released.
+        */
+       serial_remove(link);
+
+       /* free bits */
+       kfree(info);
+}
+
+/*====================================================================*/
+
+static int setup_serial(struct pcmcia_device *handle, struct serial_info * info,
+                       unsigned int iobase, int irq)
+{
+       struct uart_port port;
+       int line;
+
+       memset(&port, 0, sizeof (struct uart_port));
+       port.iobase = iobase;
+       port.irq = irq;
+       port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
+       port.uartclk = 1843200;
+       port.dev = &handle->dev;
+       if (buggy_uart)
+               port.flags |= UPF_BUGGY_UART;
+
+       if (info->quirk && info->quirk->setup)
+               info->quirk->setup(handle, &port);
+
+       line = serial8250_register_port(&port);
+       if (line < 0) {
+               printk(KERN_NOTICE "serial_cs: serial8250_register_port() at "
+                      "0x%04lx, irq %d failed\n", (u_long)iobase, irq);
+               return -EINVAL;
+       }
+
+       info->line[info->ndev] = line;
+       info->ndev++;
+
+       return 0;
+}
+
+/*====================================================================*/
+
+static int pfc_config(struct pcmcia_device *p_dev)
+{
+       unsigned int port = 0;
+       struct serial_info *info = p_dev->priv;
+
+       if ((p_dev->resource[1]->end != 0) &&
+               (resource_size(p_dev->resource[1]) == 8)) {
+               port = p_dev->resource[1]->start;
+               info->slave = 1;
+       } else if ((info->manfid == MANFID_OSITECH) &&
+               (resource_size(p_dev->resource[0]) == 0x40)) {
+               port = p_dev->resource[0]->start + 0x28;
+               info->slave = 1;
+       }
+       if (info->slave)
+               return setup_serial(p_dev, info, port, p_dev->irq);
+
+       dev_warn(&p_dev->dev, "no usable port range found, giving up\n");
+       return -ENODEV;
+}
+
+static int simple_config_check(struct pcmcia_device *p_dev, void *priv_data)
+{
+       static const int size_table[2] = { 8, 16 };
+       int *try = priv_data;
+
+       if (p_dev->resource[0]->start == 0)
+               return -ENODEV;
+
+       if ((*try & 0x1) == 0)
+               p_dev->io_lines = 16;
+
+       if (p_dev->resource[0]->end != size_table[(*try >> 1)])
+               return -ENODEV;
+
+       p_dev->resource[0]->end = 8;
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+
+       return pcmcia_request_io(p_dev);
+}
+
+static int simple_config_check_notpicky(struct pcmcia_device *p_dev,
+                                       void *priv_data)
+{
+       static const unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
+       int j;
+
+       if (p_dev->io_lines > 3)
+               return -ENODEV;
+
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+       p_dev->resource[0]->end = 8;
+
+       for (j = 0; j < 5; j++) {
+               p_dev->resource[0]->start = base[j];
+               p_dev->io_lines = base[j] ? 16 : 3;
+               if (!pcmcia_request_io(p_dev))
+                       return 0;
+       }
+       return -ENODEV;
+}
+
+static int simple_config(struct pcmcia_device *link)
+{
+       struct serial_info *info = link->priv;
+       int i = -ENODEV, try;
+
+       /* First pass: look for a config entry that looks normal.
+        * Two tries: without IO aliases, then with aliases */
+       link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_SET_IO;
+       for (try = 0; try < 4; try++)
+               if (!pcmcia_loop_config(link, simple_config_check, &try))
+                       goto found_port;
+
+       /* Second pass: try to find an entry that isn't picky about
+          its base address, then try to grab any standard serial port
+          address, and finally try to get any free port. */
+       if (!pcmcia_loop_config(link, simple_config_check_notpicky, NULL))
+               goto found_port;
+
+       dev_warn(&link->dev, "no usable port range found, giving up\n");
+       return -1;
+
+found_port:
+       if (info->multi && (info->manfid == MANFID_3COM))
+               link->config_index &= ~(0x08);
+
+       /*
+        * Apply any configuration quirks.
+        */
+       if (info->quirk && info->quirk->config)
+               info->quirk->config(link);
+
+       i = pcmcia_enable_device(link);
+       if (i != 0)
+               return -1;
+       return setup_serial(link, info, link->resource[0]->start, link->irq);
+}
+
+static int multi_config_check(struct pcmcia_device *p_dev, void *priv_data)
+{
+       int *multi = priv_data;
+
+       if (p_dev->resource[1]->end)
+               return -EINVAL;
+
+       /* The quad port cards have bad CIS's, so just look for a
+          window larger than 8 ports and assume it will be right */
+       if (p_dev->resource[0]->end <= 8)
+               return -EINVAL;
+
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+       p_dev->resource[0]->end = *multi * 8;
+
+       if (pcmcia_request_io(p_dev))
+               return -ENODEV;
+       return 0;
+}
+
+static int multi_config_check_notpicky(struct pcmcia_device *p_dev,
+                                      void *priv_data)
+{
+       int *base2 = priv_data;
+
+       if (!p_dev->resource[0]->end || !p_dev->resource[1]->end)
+               return -ENODEV;
+
+       p_dev->resource[0]->end = p_dev->resource[1]->end = 8;
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+
+       if (pcmcia_request_io(p_dev))
+               return -ENODEV;
+
+       *base2 = p_dev->resource[0]->start + 8;
+       return 0;
+}
+
+static int multi_config(struct pcmcia_device *link)
+{
+       struct serial_info *info = link->priv;
+       int i, base2 = 0;
+
+       link->config_flags |= CONF_AUTO_SET_IO;
+       /* First, look for a generic full-sized window */
+       if (!pcmcia_loop_config(link, multi_config_check, &info->multi))
+               base2 = link->resource[0]->start + 8;
+       else {
+               /* If that didn't work, look for two windows */
+               info->multi = 2;
+               if (pcmcia_loop_config(link, multi_config_check_notpicky,
+                                      &base2)) {
+                       dev_warn(&link->dev, "no usable port range "
+                              "found, giving up\n");
+                       return -ENODEV;
+               }
+       }
+
+       if (!link->irq)
+               dev_warn(&link->dev, "no usable IRQ found, continuing...\n");
+
+       /*
+        * Apply any configuration quirks.
+        */
+       if (info->quirk && info->quirk->config)
+               info->quirk->config(link);
+
+       i = pcmcia_enable_device(link);
+       if (i != 0)
+               return -ENODEV;
+
+       /* The Oxford Semiconductor OXCF950 cards are in fact single-port:
+        * 8 registers are for the UART, the others are extra registers.
+        * Siemen's MC45 PCMCIA (Possio's GCC) is OXCF950 based too.
+        */
+       if (info->manfid == MANFID_OXSEMI || (info->manfid == MANFID_POSSIO &&
+                               info->prodid == PRODID_POSSIO_GCC)) {
+               int err;
+
+               if (link->config_index == 1 ||
+                   link->config_index == 3) {
+                       err = setup_serial(link, info, base2,
+                                       link->irq);
+                       base2 = link->resource[0]->start;
+               } else {
+                       err = setup_serial(link, info, link->resource[0]->start,
+                                       link->irq);
+               }
+               info->c950ctrl = base2;
+
+               /*
+                * FIXME: We really should wake up the port prior to
+                * handing it over to the serial layer.
+                */
+               if (info->quirk && info->quirk->wakeup)
+                       info->quirk->wakeup(link);
+
+               return 0;
+       }
+
+       setup_serial(link, info, link->resource[0]->start, link->irq);
+       for (i = 0; i < info->multi - 1; i++)
+               setup_serial(link, info, base2 + (8 * i),
+                               link->irq);
+       return 0;
+}
+
+static int serial_check_for_multi(struct pcmcia_device *p_dev,  void *priv_data)
+{
+       struct serial_info *info = p_dev->priv;
+
+       if (!p_dev->resource[0]->end)
+               return -EINVAL;
+
+       if ((!p_dev->resource[1]->end) && (p_dev->resource[0]->end % 8 == 0))
+               info->multi = p_dev->resource[0]->end >> 3;
+
+       if ((p_dev->resource[1]->end) && (p_dev->resource[0]->end == 8)
+               && (p_dev->resource[1]->end == 8))
+               info->multi = 2;
+
+       return 0; /* break */
+}
+
+
+static int serial_config(struct pcmcia_device * link)
+{
+       struct serial_info *info = link->priv;
+       int i;
+
+       dev_dbg(&link->dev, "serial_config\n");
+
+       /* Is this a compliant multifunction card? */
+       info->multi = (link->socket->functions > 1);
+
+       /* Is this a multiport card? */
+       info->manfid = link->manf_id;
+       info->prodid = link->card_id;
+
+       for (i = 0; i < ARRAY_SIZE(quirks); i++)
+               if ((quirks[i].manfid == ~0 ||
+                    quirks[i].manfid == info->manfid) &&
+                   (quirks[i].prodid == ~0 ||
+                    quirks[i].prodid == info->prodid)) {
+                       info->quirk = &quirks[i];
+                       break;
+               }
+
+       /* Another check for dual-serial cards: look for either serial or
+          multifunction cards that ask for appropriate IO port ranges */
+       if ((info->multi == 0) &&
+           (link->has_func_id) &&
+           (link->socket->pcmcia_pfc == 0) &&
+           ((link->func_id == CISTPL_FUNCID_MULTI) ||
+            (link->func_id == CISTPL_FUNCID_SERIAL)))
+               pcmcia_loop_config(link, serial_check_for_multi, info);
+
+       /*
+        * Apply any multi-port quirk.
+        */
+       if (info->quirk && info->quirk->multi != -1)
+               info->multi = info->quirk->multi;
+
+       dev_info(&link->dev,
+               "trying to set up [0x%04x:0x%04x] (pfc: %d, multi: %d, quirk: %p)\n",
+               link->manf_id, link->card_id,
+               link->socket->pcmcia_pfc, info->multi, info->quirk);
+       if (link->socket->pcmcia_pfc)
+               i = pfc_config(link);
+       else if (info->multi > 1)
+               i = multi_config(link);
+       else
+               i = simple_config(link);
+
+       if (i || info->ndev == 0)
+               goto failed;
+
+       /*
+        * Apply any post-init quirk.  FIXME: This should really happen
+        * before we register the port, since it might already be in use.
+        */
+       if (info->quirk && info->quirk->post)
+               if (info->quirk->post(link))
+                       goto failed;
+
+       return 0;
+
+failed:
+       dev_warn(&link->dev, "failed to initialize\n");
+       serial_remove(link);
+       return -ENODEV;
+}
+
+static struct pcmcia_device_id serial_ids[] = {
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0057, 0x0021),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0089, 0x110a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0104, 0x000a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0d0a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0e0a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0xea15),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0109, 0x0501),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0138, 0x110a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0140, 0x000a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0143, 0x3341),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0143, 0xc0ab),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x016c, 0x0081),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x021b, 0x0101),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x08a1, 0xc0ab),
+       PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63),
+       PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63),
+       PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef),
+       PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef),
+       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM28", 0x2e3ee845, 0x0ea978ea),
+       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM33", 0x2e3ee845, 0x80609023),
+       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM56", 0x2e3ee845, 0xa650c32a),
+       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "REM10", 0x2e3ee845, 0x76df1d29),
+       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "XEM5600", 0x2e3ee845, 0xf1403719),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "AnyCom", "Fast Ethernet + 56K COMBO", 0x578ba6e7, 0xb0ac62c4),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "ATKK", "LM33-PCM-T", 0xba9eb7e2, 0x077c174e),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "D-Link", "DME336T", 0x1a424a1c, 0xb23897ff),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "MICRO RESEARCH", "COMBO-L/M-336", 0xb2ced065, 0x3ced0555),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "NEC", "PK-UG-J001" ,0x18df0ba0 ,0x831b1064),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c648f),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Xircom", "CreditCard Ethernet+Modem II", 0x2e3ee845, 0xeca401bf),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0e01),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0a05),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x1101),
+       PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0104, 0x0070),
+       PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0101, 0x0562),
+       PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0104, 0x0070),
+       PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x016c, 0x0020),
+       PCMCIA_MFC_DEVICE_PROD_ID123(1, "APEX DATA", "MULTICARD", "ETHERNET-MODEM", 0x11c2da09, 0x7289dc5d, 0xaad95e1f),
+       PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "Home and Away 28.8 PC Card       ", 0xb569a6e5, 0x5bd4ff2c),
+       PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "Home and Away Credit Card Adapter", 0xb569a6e5, 0x4bdf15c3),
+       PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "w95 Home and Away Credit Card ", 0xb569a6e5, 0xae911c15),
+       PCMCIA_MFC_DEVICE_PROD_ID1(1, "Motorola MARQUIS", 0xf03e4e77),
+       PCMCIA_MFC_DEVICE_PROD_ID2(1, "FAX/Modem/Ethernet Combo Card ", 0x1ed59302),
+       PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0301),
+       PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x0276),
+       PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0039),
+       PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0006),
+       PCMCIA_DEVICE_MANF_CARD(0x0105, 0x0101), /* TDK DF2814 */
+       PCMCIA_DEVICE_MANF_CARD(0x0105, 0x100a), /* Xircom CM-56G */
+       PCMCIA_DEVICE_MANF_CARD(0x0105, 0x3e0a), /* TDK DF5660 */
+       PCMCIA_DEVICE_MANF_CARD(0x0105, 0x410a),
+       PCMCIA_DEVICE_MANF_CARD(0x0107, 0x0002), /* USRobotics 14,400 */
+       PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d50),
+       PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d51),
+       PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d52),
+       PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d53),
+       PCMCIA_DEVICE_MANF_CARD(0x010b, 0xd180),
+       PCMCIA_DEVICE_MANF_CARD(0x0115, 0x3330), /* USRobotics/SUN 14,400 */
+       PCMCIA_DEVICE_MANF_CARD(0x0124, 0x0100), /* Nokia DTP-2 ver II */
+       PCMCIA_DEVICE_MANF_CARD(0x0134, 0x5600), /* LASAT COMMUNICATIONS A/S */
+       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x000e),
+       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x001b),
+       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0025),
+       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0045),
+       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0052),
+       PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0006), /* Psion 56K+Fax */
+       PCMCIA_DEVICE_MANF_CARD(0x0200, 0x0001), /* MultiMobile */
+       PCMCIA_DEVICE_PROD_ID134("ADV", "TECH", "COMpad-32/85", 0x67459937, 0x916d02ba, 0x8fbe92ae),
+       PCMCIA_DEVICE_PROD_ID124("GATEWAY2000", "CC3144", "PCMCIA MODEM", 0x506bccae, 0xcb3685f1, 0xbd6c43ef),
+       PCMCIA_DEVICE_PROD_ID14("MEGAHERTZ", "PCMCIA MODEM", 0xf510db04, 0xbd6c43ef),
+       PCMCIA_DEVICE_PROD_ID124("TOSHIBA", "T144PF", "PCMCIA MODEM", 0xb4585a1a, 0x7271409c, 0xbd6c43ef),
+       PCMCIA_DEVICE_PROD_ID123("FUJITSU", "FC14F ", "MBH10213", 0x6ee5a3d8, 0x30ead12b, 0xb00f05a0),
+       PCMCIA_DEVICE_PROD_ID123("Novatel Wireless", "Merlin UMTS Modem", "U630", 0x32607776, 0xd9e73b13, 0xe87332e),
+       PCMCIA_DEVICE_PROD_ID13("MEGAHERTZ", "V.34 PCMCIA MODEM", 0xf510db04, 0xbb2cce4a),
+       PCMCIA_DEVICE_PROD_ID12("Brain Boxes", "Bluetooth PC Card", 0xee138382, 0xd4ce9b02),
+       PCMCIA_DEVICE_PROD_ID12("CIRRUS LOGIC", "FAX MODEM", 0xe625f451, 0xcecd6dfa),
+       PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 28800 FAX/DATA MODEM", 0xa3a3062c, 0x8cbd7c76),
+       PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 33600 FAX/DATA MODEM", 0xa3a3062c, 0x5a00ce95),
+       PCMCIA_DEVICE_PROD_ID12("Computerboards, Inc.", "PCM-COM422", 0xd0b78f51, 0x7e2d49ed),
+       PCMCIA_DEVICE_PROD_ID12("Dr. Neuhaus", "FURY CARD 14K4", 0x76942813, 0x8b96ce65),
+       PCMCIA_DEVICE_PROD_ID12("IBM", "ISDN/56K/GSM", 0xb569a6e5, 0xfee5297b),
+       PCMCIA_DEVICE_PROD_ID12("Intelligent", "ANGIA FAX/MODEM", 0xb496e65e, 0xf31602a6),
+       PCMCIA_DEVICE_PROD_ID12("Intel", "MODEM 2400+", 0x816cc815, 0x412729fb),
+       PCMCIA_DEVICE_PROD_ID12("Intertex", "IX34-PCMCIA", 0xf8a097e3, 0x97880447),
+       PCMCIA_DEVICE_PROD_ID12("IOTech Inc ", "PCMCIA Dual RS-232 Serial Port Card", 0x3bd2d898, 0x92abc92f),
+       PCMCIA_DEVICE_PROD_ID12("MACRONIX", "FAX/MODEM", 0x668388b3, 0x3f9bdf2f),
+       PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT1432LT", 0x5f73be51, 0x0b3e2383),
+       PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT2834LT", 0x5f73be51, 0x4cd7c09e),
+       PCMCIA_DEVICE_PROD_ID12("OEM      ", "C288MX     ", 0xb572d360, 0xd2385b7a),
+       PCMCIA_DEVICE_PROD_ID12("Option International", "V34bis GSM/PSTN Data/Fax Modem", 0x9d7cd6f5, 0x5cb8bf41),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA   ", "C336MX     ", 0x99bcafe9, 0xaa25bcab),
+       PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "PCMCIA Dual RS-232 Serial Port Card", 0xc4420b35, 0x92abc92f),
+       PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "Dual RS-232 Serial Port PC Card", 0xc4420b35, 0x031a380d),
+       PCMCIA_DEVICE_PROD_ID12("Telia", "SurfinBird 560P/A+", 0xe2cdd5e, 0xc9314b38),
+       PCMCIA_DEVICE_PROD_ID1("Smart Serial Port", 0x2d8ce292),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "EN2218-LAN/MODEM", 0x281f1c5d, 0x570f348e, "cis/PCMLM28.cis"),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "UE2218-LAN/MODEM", 0x281f1c5d, 0x6fdcacee, "cis/PCMLM28.cis"),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "cis/PCMLM28.cis"),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet GSM", 0xf5f025c2, 0x4ae85d35, "cis/PCMLM28.cis"),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "cis/PCMLM28.cis"),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "TOSHIBA", "Modem/LAN Card", 0xb4585a1a, 0x53f922f8, "cis/PCMLM28.cis"),
+       PCMCIA_MFC_DEVICE_CIS_PROD_ID12(1, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "cis/DP83903.cis"),
+       PCMCIA_MFC_DEVICE_CIS_PROD_ID4(1, "NSC MF LAN/Modem", 0x58fc6056, "cis/DP83903.cis"),
+       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0556, "cis/3CCFEM556.cis"),
+       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0175, 0x0000, "cis/DP83903.cis"),
+       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0035, "cis/3CXEM556.cis"),
+       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x003d, "cis/3CXEM556.cis"),
+       PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC850", 0xd85f6206, 0x42a2c018, "cis/SW_8xx_SER.cis"), /* Sierra Wireless AC850 3G Network Adapter R1 */
+       PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC860", 0xd85f6206, 0x698f93db, "cis/SW_8xx_SER.cis"), /* Sierra Wireless AC860 3G Network Adapter R1 */
+       PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC710/AC750", 0xd85f6206, 0x761b11e0, "cis/SW_7xx_SER.cis"),  /* Sierra Wireless AC710/AC750 GPRS Network Adapter R1 */
+       PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0xa555, "cis/SW_555_SER.cis"),  /* Sierra Aircard 555 CDMA 1xrtt Modem -- pre update */
+       PCMCIA_DEVICE_CIS_MANF_CARD(0x013f, 0xa555, "cis/SW_555_SER.cis"),  /* Sierra Aircard 555 CDMA 1xrtt Modem -- post update */
+       PCMCIA_DEVICE_CIS_PROD_ID12("MultiTech", "PCMCIA 56K DataFax", 0x842047ee, 0xc2efcf03, "cis/MT5634ZLX.cis"),
+       PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-2", 0x96913a85, 0x27ab5437, "cis/COMpad2.cis"),
+       PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-4", 0x96913a85, 0xcec8f102, "cis/COMpad4.cis"),
+       PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "cis/COMpad2.cis"),
+       PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "cis/RS-COM-2P.cis"),
+       PCMCIA_DEVICE_CIS_MANF_CARD(0x0013, 0x0000, "cis/GLOBETROTTER.cis"),
+       PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100  1.00.",0x19ca78af,0xf964f42b),
+       PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100",0x19ca78af,0x71d98e83),
+       PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL232  1.00.",0x19ca78af,0x69fb7490),
+       PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL232",0x19ca78af,0xb6bc0235),
+       PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.","SERIAL CARD: CF232",0x63f2e0bd,0xb9e175d3),
+       PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.","SERIAL CARD: CF232-5",0x63f2e0bd,0xfce33442),
+       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF232",0x3beb8cf2,0x171e7190),
+       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF232-5",0x3beb8cf2,0x20da4262),
+       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF428",0x3beb8cf2,0xea5dd57d),
+       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF500",0x3beb8cf2,0xd77255fa),
+       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: IC232",0x3beb8cf2,0x6a709903),
+       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: SL232",0x3beb8cf2,0x18430676),
+       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: XL232",0x3beb8cf2,0x6f933767),
+       PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: CF332",0x3beb8cf2,0x16dc1ba7),
+       PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL332",0x3beb8cf2,0x19816c41),
+       PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL385",0x3beb8cf2,0x64112029),
+       PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
+       PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc),
+       PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: CF332",0x3beb8cf2,0x16dc1ba7),
+       PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL332",0x3beb8cf2,0x19816c41),
+       PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL385",0x3beb8cf2,0x64112029),
+       PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
+       PCMCIA_MFC_DEVICE_PROD_ID12(2,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
+       PCMCIA_MFC_DEVICE_PROD_ID12(3,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
+       PCMCIA_DEVICE_MANF_CARD(0x0279, 0x950b),
+       /* too generic */
+       /* PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0160, 0x0002), */
+       /* PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0160, 0x0002), */
+       PCMCIA_DEVICE_FUNC_ID(2),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, serial_ids);
+
+MODULE_FIRMWARE("cis/PCMLM28.cis");
+MODULE_FIRMWARE("cis/DP83903.cis");
+MODULE_FIRMWARE("cis/3CCFEM556.cis");
+MODULE_FIRMWARE("cis/3CXEM556.cis");
+MODULE_FIRMWARE("cis/SW_8xx_SER.cis");
+MODULE_FIRMWARE("cis/SW_7xx_SER.cis");
+MODULE_FIRMWARE("cis/SW_555_SER.cis");
+MODULE_FIRMWARE("cis/MT5634ZLX.cis");
+MODULE_FIRMWARE("cis/COMpad2.cis");
+MODULE_FIRMWARE("cis/COMpad4.cis");
+MODULE_FIRMWARE("cis/RS-COM-2P.cis");
+
+static struct pcmcia_driver serial_cs_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "serial_cs",
+       .probe          = serial_probe,
+       .remove         = serial_detach,
+       .id_table       = serial_ids,
+       .suspend        = serial_suspend,
+       .resume         = serial_resume,
+};
+
+static int __init init_serial_cs(void)
+{
+       return pcmcia_register_driver(&serial_cs_driver);
+}
+
+static void __exit exit_serial_cs(void)
+{
+       pcmcia_unregister_driver(&serial_cs_driver);
+}
+
+module_init(init_serial_cs);
+module_exit(exit_serial_cs);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/serial_ks8695.c b/drivers/tty/serial/serial_ks8695.c
new file mode 100644 (file)
index 0000000..b196202
--- /dev/null
@@ -0,0 +1,705 @@
+/*
+ *  drivers/serial/serial_ks8695.c
+ *
+ *  Driver for KS8695 serial ports
+ *
+ *  Based on drivers/serial/serial_amba.c, by Kam Lee.
+ *
+ *  Copyright 2002-2005 Micrel Inc.
+ *
+ * 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.
+ *
+ */
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+
+#include <mach/regs-uart.h>
+#include <mach/regs-irq.h>
+
+#if defined(CONFIG_SERIAL_KS8695_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+
+#define SERIAL_KS8695_MAJOR    204
+#define SERIAL_KS8695_MINOR    16
+#define SERIAL_KS8695_DEVNAME  "ttyAM"
+
+#define SERIAL_KS8695_NR       1
+
+/*
+ * Access macros for the KS8695 UART
+ */
+#define UART_GET_CHAR(p)       (__raw_readl((p)->membase + KS8695_URRB) & 0xFF)
+#define UART_PUT_CHAR(p, c)    __raw_writel((c), (p)->membase + KS8695_URTH)
+#define UART_GET_FCR(p)                __raw_readl((p)->membase + KS8695_URFC)
+#define UART_PUT_FCR(p, c)     __raw_writel((c), (p)->membase + KS8695_URFC)
+#define UART_GET_MSR(p)                __raw_readl((p)->membase + KS8695_URMS)
+#define UART_GET_LSR(p)                __raw_readl((p)->membase + KS8695_URLS)
+#define UART_GET_LCR(p)                __raw_readl((p)->membase + KS8695_URLC)
+#define UART_PUT_LCR(p, c)     __raw_writel((c), (p)->membase + KS8695_URLC)
+#define UART_GET_MCR(p)                __raw_readl((p)->membase + KS8695_URMC)
+#define UART_PUT_MCR(p, c)     __raw_writel((c), (p)->membase + KS8695_URMC)
+#define UART_GET_BRDR(p)       __raw_readl((p)->membase + KS8695_URBD)
+#define UART_PUT_BRDR(p, c)    __raw_writel((c), (p)->membase + KS8695_URBD)
+
+#define KS8695_CLR_TX_INT()    __raw_writel(1 << KS8695_IRQ_UART_TX, KS8695_IRQ_VA + KS8695_INTST)
+
+#define UART_DUMMY_LSR_RX      0x100
+#define UART_PORT_SIZE         (KS8695_USR - KS8695_URRB + 4)
+
+static inline int tx_enabled(struct uart_port *port)
+{
+       return port->unused[0] & 1;
+}
+
+static inline int rx_enabled(struct uart_port *port)
+{
+       return port->unused[0] & 2;
+}
+
+static inline int ms_enabled(struct uart_port *port)
+{
+       return port->unused[0] & 4;
+}
+
+static inline void ms_enable(struct uart_port *port, int enabled)
+{
+       if(enabled)
+               port->unused[0] |= 4;
+       else
+               port->unused[0] &= ~4;
+}
+
+static inline void rx_enable(struct uart_port *port, int enabled)
+{
+       if(enabled)
+               port->unused[0] |= 2;
+       else
+               port->unused[0] &= ~2;
+}
+
+static inline void tx_enable(struct uart_port *port, int enabled)
+{
+       if(enabled)
+               port->unused[0] |= 1;
+       else
+               port->unused[0] &= ~1;
+}
+
+
+#ifdef SUPPORT_SYSRQ
+static struct console ks8695_console;
+#endif
+
+static void ks8695uart_stop_tx(struct uart_port *port)
+{
+       if (tx_enabled(port)) {
+               /* use disable_irq_nosync() and not disable_irq() to avoid self
+                * imposed deadlock by not waiting for irq handler to end,
+                * since this ks8695uart_stop_tx() is called from interrupt context.
+                */
+               disable_irq_nosync(KS8695_IRQ_UART_TX);
+               tx_enable(port, 0);
+       }
+}
+
+static void ks8695uart_start_tx(struct uart_port *port)
+{
+       if (!tx_enabled(port)) {
+               enable_irq(KS8695_IRQ_UART_TX);
+               tx_enable(port, 1);
+       }
+}
+
+static void ks8695uart_stop_rx(struct uart_port *port)
+{
+       if (rx_enabled(port)) {
+               disable_irq(KS8695_IRQ_UART_RX);
+               rx_enable(port, 0);
+       }
+}
+
+static void ks8695uart_enable_ms(struct uart_port *port)
+{
+       if (!ms_enabled(port)) {
+               enable_irq(KS8695_IRQ_UART_MODEM_STATUS);
+               ms_enable(port,1);
+       }
+}
+
+static void ks8695uart_disable_ms(struct uart_port *port)
+{
+       if (ms_enabled(port)) {
+               disable_irq(KS8695_IRQ_UART_MODEM_STATUS);
+               ms_enable(port,0);
+       }
+}
+
+static irqreturn_t ks8695uart_rx_chars(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       struct tty_struct *tty = port->state->port.tty;
+       unsigned int status, ch, lsr, flg, max_count = 256;
+
+       status = UART_GET_LSR(port);            /* clears pending LSR interrupts */
+       while ((status & URLS_URDR) && max_count--) {
+               ch = UART_GET_CHAR(port);
+               flg = TTY_NORMAL;
+
+               port->icount.rx++;
+
+               /*
+                * Note that the error handling code is
+                * out of the main execution path
+                */
+               lsr = UART_GET_LSR(port) | UART_DUMMY_LSR_RX;
+               if (unlikely(lsr & (URLS_URBI | URLS_URPE | URLS_URFE | URLS_URROE))) {
+                       if (lsr & URLS_URBI) {
+                               lsr &= ~(URLS_URFE | URLS_URPE);
+                               port->icount.brk++;
+                               if (uart_handle_break(port))
+                                       goto ignore_char;
+                       }
+                       if (lsr & URLS_URPE)
+                               port->icount.parity++;
+                       if (lsr & URLS_URFE)
+                               port->icount.frame++;
+                       if (lsr & URLS_URROE)
+                               port->icount.overrun++;
+
+                       lsr &= port->read_status_mask;
+
+                       if (lsr & URLS_URBI)
+                               flg = TTY_BREAK;
+                       else if (lsr & URLS_URPE)
+                               flg = TTY_PARITY;
+                       else if (lsr & URLS_URFE)
+                               flg = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(port, ch))
+                       goto ignore_char;
+
+               uart_insert_char(port, lsr, URLS_URROE, ch, flg);
+
+ignore_char:
+               status = UART_GET_LSR(port);
+       }
+       tty_flip_buffer_push(tty);
+
+       return IRQ_HANDLED;
+}
+
+
+static irqreturn_t ks8695uart_tx_chars(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       struct circ_buf *xmit = &port->state->xmit;
+       unsigned int count;
+
+       if (port->x_char) {
+               KS8695_CLR_TX_INT();
+               UART_PUT_CHAR(port, port->x_char);
+               port->icount.tx++;
+               port->x_char = 0;
+               return IRQ_HANDLED;
+       }
+
+       if (uart_tx_stopped(port) || uart_circ_empty(xmit)) {
+               ks8695uart_stop_tx(port);
+               return IRQ_HANDLED;
+       }
+
+       count = 16;     /* fifo size */
+       while (!uart_circ_empty(xmit) && (count-- > 0)) {
+               KS8695_CLR_TX_INT();
+               UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
+
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit))
+               ks8695uart_stop_tx(port);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t ks8695uart_modem_status(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       unsigned int status;
+
+       /*
+        * clear modem interrupt by reading MSR
+        */
+       status = UART_GET_MSR(port);
+
+       if (status & URMS_URDDCD)
+               uart_handle_dcd_change(port, status & URMS_URDDCD);
+
+       if (status & URMS_URDDST)
+               port->icount.dsr++;
+
+       if (status & URMS_URDCTS)
+               uart_handle_cts_change(port, status & URMS_URDCTS);
+
+       if (status & URMS_URTERI)
+               port->icount.rng++;
+
+       wake_up_interruptible(&port->state->port.delta_msr_wait);
+
+       return IRQ_HANDLED;
+}
+
+static unsigned int ks8695uart_tx_empty(struct uart_port *port)
+{
+       return (UART_GET_LSR(port) & URLS_URTE) ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int ks8695uart_get_mctrl(struct uart_port *port)
+{
+       unsigned int result = 0;
+       unsigned int status;
+
+       status = UART_GET_MSR(port);
+       if (status & URMS_URDCD)
+               result |= TIOCM_CAR;
+       if (status & URMS_URDSR)
+               result |= TIOCM_DSR;
+       if (status & URMS_URCTS)
+               result |= TIOCM_CTS;
+       if (status & URMS_URRI)
+               result |= TIOCM_RI;
+
+       return result;
+}
+
+static void ks8695uart_set_mctrl(struct uart_port *port, u_int mctrl)
+{
+       unsigned int mcr;
+
+       mcr = UART_GET_MCR(port);
+       if (mctrl & TIOCM_RTS)
+               mcr |= URMC_URRTS;
+       else
+               mcr &= ~URMC_URRTS;
+
+       if (mctrl & TIOCM_DTR)
+               mcr |= URMC_URDTR;
+       else
+               mcr &= ~URMC_URDTR;
+
+       UART_PUT_MCR(port, mcr);
+}
+
+static void ks8695uart_break_ctl(struct uart_port *port, int break_state)
+{
+       unsigned int lcr;
+
+       lcr = UART_GET_LCR(port);
+
+       if (break_state == -1)
+               lcr |= URLC_URSBC;
+       else
+               lcr &= ~URLC_URSBC;
+
+       UART_PUT_LCR(port, lcr);
+}
+
+static int ks8695uart_startup(struct uart_port *port)
+{
+       int retval;
+
+       set_irq_flags(KS8695_IRQ_UART_TX, IRQF_VALID | IRQF_NOAUTOEN);
+       tx_enable(port, 0);
+       rx_enable(port, 1);
+       ms_enable(port, 1);
+
+       /*
+        * Allocate the IRQ
+        */
+       retval = request_irq(KS8695_IRQ_UART_TX, ks8695uart_tx_chars, IRQF_DISABLED, "UART TX", port);
+       if (retval)
+               goto err_tx;
+
+       retval = request_irq(KS8695_IRQ_UART_RX, ks8695uart_rx_chars, IRQF_DISABLED, "UART RX", port);
+       if (retval)
+               goto err_rx;
+
+       retval = request_irq(KS8695_IRQ_UART_LINE_STATUS, ks8695uart_rx_chars, IRQF_DISABLED, "UART LineStatus", port);
+       if (retval)
+               goto err_ls;
+
+       retval = request_irq(KS8695_IRQ_UART_MODEM_STATUS, ks8695uart_modem_status, IRQF_DISABLED, "UART ModemStatus", port);
+       if (retval)
+               goto err_ms;
+
+       return 0;
+
+err_ms:
+       free_irq(KS8695_IRQ_UART_LINE_STATUS, port);
+err_ls:
+       free_irq(KS8695_IRQ_UART_RX, port);
+err_rx:
+       free_irq(KS8695_IRQ_UART_TX, port);
+err_tx:
+       return retval;
+}
+
+static void ks8695uart_shutdown(struct uart_port *port)
+{
+       /*
+        * Free the interrupt
+        */
+       free_irq(KS8695_IRQ_UART_RX, port);
+       free_irq(KS8695_IRQ_UART_TX, port);
+       free_irq(KS8695_IRQ_UART_MODEM_STATUS, port);
+       free_irq(KS8695_IRQ_UART_LINE_STATUS, port);
+
+       /* disable break condition and fifos */
+       UART_PUT_LCR(port, UART_GET_LCR(port) & ~URLC_URSBC);
+       UART_PUT_FCR(port, UART_GET_FCR(port) & ~URFC_URFE);
+}
+
+static void ks8695uart_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old)
+{
+       unsigned int lcr, fcr = 0;
+       unsigned long flags;
+       unsigned int baud, quot;
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+       quot = uart_get_divisor(port, baud);
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               lcr = URCL_5;
+               break;
+       case CS6:
+               lcr = URCL_6;
+               break;
+       case CS7:
+               lcr = URCL_7;
+               break;
+       default:
+               lcr = URCL_8;
+               break;
+       }
+
+       /* stop bits */
+       if (termios->c_cflag & CSTOPB)
+               lcr |= URLC_URSB;
+
+       /* parity */
+       if (termios->c_cflag & PARENB) {
+               if (termios->c_cflag & CMSPAR) {        /* Mark or Space parity */
+                       if (termios->c_cflag & PARODD)
+                               lcr |= URPE_MARK;
+                       else
+                               lcr |= URPE_SPACE;
+               }
+               else if (termios->c_cflag & PARODD)
+                       lcr |= URPE_ODD;
+               else
+                       lcr |= URPE_EVEN;
+       }
+
+       if (port->fifosize > 1)
+               fcr = URFC_URFRT_8 | URFC_URTFR | URFC_URRFR | URFC_URFE;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       port->read_status_mask = URLS_URROE;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= (URLS_URFE | URLS_URPE);
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               port->read_status_mask |= URLS_URBI;
+
+       /*
+        * Characters to ignore
+        */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= (URLS_URFE | URLS_URPE);
+       if (termios->c_iflag & IGNBRK) {
+               port->ignore_status_mask |= URLS_URBI;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       port->ignore_status_mask |= URLS_URROE;
+       }
+
+       /*
+        * Ignore all characters if CREAD is not set.
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               port->ignore_status_mask |= UART_DUMMY_LSR_RX;
+
+       /* first, disable everything */
+       if (UART_ENABLE_MS(port, termios->c_cflag))
+               ks8695uart_enable_ms(port);
+       else
+               ks8695uart_disable_ms(port);
+
+       /* Set baud rate */
+       UART_PUT_BRDR(port, quot);
+
+       UART_PUT_LCR(port, lcr);
+       UART_PUT_FCR(port, fcr);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *ks8695uart_type(struct uart_port *port)
+{
+       return port->type == PORT_KS8695 ? "KS8695" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'
+ */
+static void ks8695uart_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 ks8695uart_request_port(struct uart_port *port)
+{
+       return request_mem_region(port->mapbase, UART_PORT_SIZE,
+                       "serial_ks8695") != NULL ? 0 : -EBUSY;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void ks8695uart_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = PORT_KS8695;
+               ks8695uart_request_port(port);
+       }
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int ks8695uart_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       int ret = 0;
+
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_KS8695)
+               ret = -EINVAL;
+       if (ser->irq != port->irq)
+               ret = -EINVAL;
+       if (ser->baud_base < 9600)
+               ret = -EINVAL;
+       return ret;
+}
+
+static struct uart_ops ks8695uart_pops = {
+       .tx_empty       = ks8695uart_tx_empty,
+       .set_mctrl      = ks8695uart_set_mctrl,
+       .get_mctrl      = ks8695uart_get_mctrl,
+       .stop_tx        = ks8695uart_stop_tx,
+       .start_tx       = ks8695uart_start_tx,
+       .stop_rx        = ks8695uart_stop_rx,
+       .enable_ms      = ks8695uart_enable_ms,
+       .break_ctl      = ks8695uart_break_ctl,
+       .startup        = ks8695uart_startup,
+       .shutdown       = ks8695uart_shutdown,
+       .set_termios    = ks8695uart_set_termios,
+       .type           = ks8695uart_type,
+       .release_port   = ks8695uart_release_port,
+       .request_port   = ks8695uart_request_port,
+       .config_port    = ks8695uart_config_port,
+       .verify_port    = ks8695uart_verify_port,
+};
+
+static struct uart_port ks8695uart_ports[SERIAL_KS8695_NR] = {
+       {
+               .membase        = (void *) KS8695_UART_VA,
+               .mapbase        = KS8695_UART_VA,
+               .iotype         = SERIAL_IO_MEM,
+               .irq            = KS8695_IRQ_UART_TX,
+               .uartclk        = KS8695_CLOCK_RATE * 16,
+               .fifosize       = 16,
+               .ops            = &ks8695uart_pops,
+               .flags          = ASYNC_BOOT_AUTOCONF,
+               .line           = 0,
+       }
+};
+
+#ifdef CONFIG_SERIAL_KS8695_CONSOLE
+static void ks8695_console_putchar(struct uart_port *port, int ch)
+{
+       while (!(UART_GET_LSR(port) & URLS_URTHRE))
+               barrier();
+
+       UART_PUT_CHAR(port, ch);
+}
+
+static void ks8695_console_write(struct console *co, const char *s, u_int count)
+{
+       struct uart_port *port = ks8695uart_ports + co->index;
+
+       uart_console_write(port, s, count, ks8695_console_putchar);
+}
+
+static void __init ks8695_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
+{
+       unsigned int lcr;
+
+       lcr = UART_GET_LCR(port);
+
+       switch (lcr & URLC_PARITY) {
+               case URPE_ODD:
+                       *parity = 'o';
+                       break;
+               case URPE_EVEN:
+                       *parity = 'e';
+                       break;
+               default:
+                       *parity = 'n';
+       }
+
+       switch (lcr & URLC_URCL) {
+               case URCL_5:
+                       *bits = 5;
+                       break;
+               case URCL_6:
+                       *bits = 6;
+                       break;
+               case URCL_7:
+                       *bits = 7;
+                       break;
+               default:
+                       *bits = 8;
+       }
+
+       *baud = port->uartclk / (UART_GET_BRDR(port) & 0x0FFF);
+       *baud /= 16;
+       *baud &= 0xFFFFFFF0;
+}
+
+static int __init ks8695_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       int baud = 115200;
+       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(ks8695uart_ports, SERIAL_KS8695_NR, co);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               ks8695_console_get_options(port, &baud, &parity, &bits);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver ks8695_reg;
+
+static struct console ks8695_console = {
+       .name           = SERIAL_KS8695_DEVNAME,
+       .write          = ks8695_console_write,
+       .device         = uart_console_device,
+       .setup          = ks8695_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &ks8695_reg,
+};
+
+static int __init ks8695_console_init(void)
+{
+       add_preferred_console(SERIAL_KS8695_DEVNAME, 0, NULL);
+       register_console(&ks8695_console);
+       return 0;
+}
+
+console_initcall(ks8695_console_init);
+
+#define KS8695_CONSOLE &ks8695_console
+#else
+#define KS8695_CONSOLE NULL
+#endif
+
+static struct uart_driver ks8695_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "serial_ks8695",
+       .dev_name               = SERIAL_KS8695_DEVNAME,
+       .major                  = SERIAL_KS8695_MAJOR,
+       .minor                  = SERIAL_KS8695_MINOR,
+       .nr                     = SERIAL_KS8695_NR,
+       .cons                   = KS8695_CONSOLE,
+};
+
+static int __init ks8695uart_init(void)
+{
+       int i, ret;
+
+       printk(KERN_INFO "Serial: Micrel KS8695 UART driver\n");
+
+       ret = uart_register_driver(&ks8695_reg);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < SERIAL_KS8695_NR; i++)
+               uart_add_one_port(&ks8695_reg, &ks8695uart_ports[0]);
+
+       return 0;
+}
+
+static void __exit ks8695uart_exit(void)
+{
+       int i;
+
+       for (i = 0; i < SERIAL_KS8695_NR; i++)
+               uart_remove_one_port(&ks8695_reg, &ks8695uart_ports[0]);
+       uart_unregister_driver(&ks8695_reg);
+}
+
+module_init(ks8695uart_init);
+module_exit(ks8695uart_exit);
+
+MODULE_DESCRIPTION("KS8695 serial port driver");
+MODULE_AUTHOR("Micrel Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/serial_lh7a40x.c b/drivers/tty/serial/serial_lh7a40x.c
new file mode 100644 (file)
index 0000000..ea74470
--- /dev/null
@@ -0,0 +1,682 @@
+/* drivers/serial/serial_lh7a40x.c
+ *
+ *  Copyright (C) 2004 Coastal Environmental Systems
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  version 2 as published by the Free Software Foundation.
+ *
+ */
+
+/* Driver for Sharp LH7A40X embedded serial ports
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *  Based on drivers/serial/amba.c, by Deep Blue Solutions Ltd.
+ *
+ *  ---
+ *
+ * This driver supports the embedded UARTs of the Sharp LH7A40X series
+ * CPUs.  While similar to the 16550 and other UART chips, there is
+ * nothing close to register compatibility.  Moreover, some of the
+ * modem control lines are not available, either in the chip or they
+ * are lacking in the board-level implementation.
+ *
+ * - Use of SIRDIS
+ *   For simplicity, we disable the IR functions of any UART whenever
+ *   we enable it.
+ *
+ */
+
+
+#if defined(CONFIG_SERIAL_LH7A40X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+#include <mach/hardware.h>
+
+#define DEV_MAJOR      204
+#define DEV_MINOR      16
+#define DEV_NR         3
+
+#define ISR_LOOP_LIMIT 256
+
+#define UR(p,o)        _UR ((p)->membase, o)
+#define _UR(b,o) (*((volatile unsigned int*)(((unsigned char*) b) + (o))))
+#define BIT_CLR(p,o,m) UR(p,o) = UR(p,o) & (~(unsigned int)m)
+#define BIT_SET(p,o,m) UR(p,o) = UR(p,o) | ( (unsigned int)m)
+
+#define UART_REG_SIZE  32
+
+#define UART_R_DATA    (0x00)
+#define UART_R_FCON    (0x04)
+#define UART_R_BRCON   (0x08)
+#define UART_R_CON     (0x0c)
+#define UART_R_STATUS  (0x10)
+#define UART_R_RAWISR  (0x14)
+#define UART_R_INTEN   (0x18)
+#define UART_R_ISR     (0x1c)
+
+#define UARTEN         (0x01)          /* UART enable */
+#define SIRDIS         (0x02)          /* Serial IR disable (UART1 only) */
+
+#define RxEmpty                (0x10)
+#define TxEmpty                (0x80)
+#define TxFull         (0x20)
+#define nRxRdy         RxEmpty
+#define nTxRdy         TxFull
+#define TxBusy         (0x08)
+
+#define RxBreak                (0x0800)
+#define RxOverrunError (0x0400)
+#define RxParityError  (0x0200)
+#define RxFramingError (0x0100)
+#define RxError     (RxBreak | RxOverrunError | RxParityError | RxFramingError)
+
+#define DCD            (0x04)
+#define DSR            (0x02)
+#define CTS            (0x01)
+
+#define RxInt          (0x01)
+#define TxInt          (0x02)
+#define ModemInt       (0x04)
+#define RxTimeoutInt   (0x08)
+
+#define MSEOI          (0x10)
+
+#define WLEN_8         (0x60)
+#define WLEN_7         (0x40)
+#define WLEN_6         (0x20)
+#define WLEN_5         (0x00)
+#define WLEN           (0x60)  /* Mask for all word-length bits */
+#define STP2           (0x08)
+#define PEN            (0x02)  /* Parity Enable */
+#define EPS            (0x04)  /* Even Parity Set */
+#define FEN            (0x10)  /* FIFO Enable */
+#define BRK            (0x01)  /* Send Break */
+
+
+struct uart_port_lh7a40x {
+       struct uart_port port;
+       unsigned int statusPrev; /* Most recently read modem status */
+};
+
+static void lh7a40xuart_stop_tx (struct uart_port* port)
+{
+       BIT_CLR (port, UART_R_INTEN, TxInt);
+}
+
+static void lh7a40xuart_start_tx (struct uart_port* port)
+{
+       BIT_SET (port, UART_R_INTEN, TxInt);
+
+       /* *** FIXME: do I need to check for startup of the
+                     transmitter?  The old driver did, but AMBA
+                     doesn't . */
+}
+
+static void lh7a40xuart_stop_rx (struct uart_port* port)
+{
+       BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
+}
+
+static void lh7a40xuart_enable_ms (struct uart_port* port)
+{
+       BIT_SET (port, UART_R_INTEN, ModemInt);
+}
+
+static void lh7a40xuart_rx_chars (struct uart_port* port)
+{
+       struct tty_struct* tty = port->state->port.tty;
+       int cbRxMax = 256;      /* (Gross) limit on receive */
+       unsigned int data;      /* Received data and status */
+       unsigned int flag;
+
+       while (!(UR (port, UART_R_STATUS) & nRxRdy) && --cbRxMax) {
+               data = UR (port, UART_R_DATA);
+               flag = TTY_NORMAL;
+               ++port->icount.rx;
+
+               if (unlikely(data & RxError)) {
+                       if (data & RxBreak) {
+                               data &= ~(RxFramingError | RxParityError);
+                               ++port->icount.brk;
+                               if (uart_handle_break (port))
+                                       continue;
+                       }
+                       else if (data & RxParityError)
+                               ++port->icount.parity;
+                       else if (data & RxFramingError)
+                               ++port->icount.frame;
+                       if (data & RxOverrunError)
+                               ++port->icount.overrun;
+
+                               /* Mask by termios, leave Rx'd byte */
+                       data &= port->read_status_mask | 0xff;
+
+                       if (data & RxBreak)
+                               flag = TTY_BREAK;
+                       else if (data & RxParityError)
+                               flag = TTY_PARITY;
+                       else if (data & RxFramingError)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char (port, (unsigned char) data))
+                       continue;
+
+               uart_insert_char(port, data, RxOverrunError, data, flag);
+       }
+       tty_flip_buffer_push (tty);
+       return;
+}
+
+static void lh7a40xuart_tx_chars (struct uart_port* port)
+{
+       struct circ_buf* xmit = &port->state->xmit;
+       int cbTxMax = port->fifosize;
+
+       if (port->x_char) {
+               UR (port, UART_R_DATA) = port->x_char;
+               ++port->icount.tx;
+               port->x_char = 0;
+               return;
+       }
+       if (uart_circ_empty (xmit) || uart_tx_stopped (port)) {
+               lh7a40xuart_stop_tx (port);
+               return;
+       }
+
+       /* Unlike the AMBA UART, the lh7a40x UART does not guarantee
+          that at least half of the FIFO is empty.  Instead, we check
+          status for every character.  Using the AMBA method causes
+          the transmitter to drop characters. */
+
+       do {
+               UR (port, UART_R_DATA) = xmit->buf[xmit->tail];
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               ++port->icount.tx;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (!(UR (port, UART_R_STATUS) & nTxRdy)
+                && cbTxMax--);
+
+       if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS)
+               uart_write_wakeup (port);
+
+       if (uart_circ_empty (xmit))
+               lh7a40xuart_stop_tx (port);
+}
+
+static void lh7a40xuart_modem_status (struct uart_port* port)
+{
+       unsigned int status = UR (port, UART_R_STATUS);
+       unsigned int delta
+               = status ^ ((struct uart_port_lh7a40x*) port)->statusPrev;
+
+       BIT_SET (port, UART_R_RAWISR, MSEOI); /* Clear modem status intr */
+
+       if (!delta)             /* Only happens if we missed 2 transitions */
+               return;
+
+       ((struct uart_port_lh7a40x*) port)->statusPrev = status;
+
+       if (delta & DCD)
+               uart_handle_dcd_change (port, status & DCD);
+
+       if (delta & DSR)
+               ++port->icount.dsr;
+
+       if (delta & CTS)
+               uart_handle_cts_change (port, status & CTS);
+
+       wake_up_interruptible (&port->state->port.delta_msr_wait);
+}
+
+static irqreturn_t lh7a40xuart_int (int irq, void* dev_id)
+{
+       struct uart_port* port = dev_id;
+       unsigned int cLoopLimit = ISR_LOOP_LIMIT;
+       unsigned int isr = UR (port, UART_R_ISR);
+
+
+       do {
+               if (isr & (RxInt | RxTimeoutInt))
+                       lh7a40xuart_rx_chars(port);
+               if (isr & ModemInt)
+                       lh7a40xuart_modem_status (port);
+               if (isr & TxInt)
+                       lh7a40xuart_tx_chars (port);
+
+               if (--cLoopLimit == 0)
+                       break;
+
+               isr = UR (port, UART_R_ISR);
+       } while (isr & (RxInt | TxInt | RxTimeoutInt));
+
+       return IRQ_HANDLED;
+}
+
+static unsigned int lh7a40xuart_tx_empty (struct uart_port* port)
+{
+       return (UR (port, UART_R_STATUS) & TxEmpty) ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int lh7a40xuart_get_mctrl (struct uart_port* port)
+{
+       unsigned int result = 0;
+       unsigned int status = UR (port, UART_R_STATUS);
+
+       if (status & DCD)
+               result |= TIOCM_CAR;
+       if (status & DSR)
+               result |= TIOCM_DSR;
+       if (status & CTS)
+               result |= TIOCM_CTS;
+
+       return result;
+}
+
+static void lh7a40xuart_set_mctrl (struct uart_port* port, unsigned int mctrl)
+{
+       /* None of the ports supports DTR. UART1 supports RTS through GPIO. */
+       /* Note, kernel appears to be setting DTR and RTS on console. */
+
+       /* *** FIXME: this deserves more work.  There's some work in
+              tracing all of the IO pins. */
+#if 0
+       if( port->mapbase == UART1_PHYS) {
+               gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS);
+
+               if (mctrl & TIOCM_RTS)
+                       gpio->pbdr &= ~GPIOB_UART1_RTS;
+               else
+                       gpio->pbdr |= GPIOB_UART1_RTS;
+       }
+#endif
+}
+
+static void lh7a40xuart_break_ctl (struct uart_port* port, int break_state)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       if (break_state == -1)
+               BIT_SET (port, UART_R_FCON, BRK); /* Assert break */
+       else
+               BIT_CLR (port, UART_R_FCON, BRK); /* Deassert break */
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int lh7a40xuart_startup (struct uart_port* port)
+{
+       int retval;
+
+       retval = request_irq (port->irq, lh7a40xuart_int, 0,
+                             "serial_lh7a40x", port);
+       if (retval)
+               return retval;
+
+                               /* Initial modem control-line settings */
+       ((struct uart_port_lh7a40x*) port)->statusPrev
+               = UR (port, UART_R_STATUS);
+
+       /* There is presently no configuration option to enable IR.
+          Thus, we always disable it. */
+
+       BIT_SET (port, UART_R_CON, UARTEN | SIRDIS);
+       BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
+
+       return 0;
+}
+
+static void lh7a40xuart_shutdown (struct uart_port* port)
+{
+       free_irq (port->irq, port);
+       BIT_CLR (port, UART_R_FCON, BRK | FEN);
+       BIT_CLR (port, UART_R_CON, UARTEN);
+}
+
+static void lh7a40xuart_set_termios (struct uart_port* port,
+                                    struct ktermios* termios,
+                                    struct ktermios* old)
+{
+       unsigned int con;
+       unsigned int inten;
+       unsigned int fcon;
+       unsigned long flags;
+       unsigned int baud;
+       unsigned int quot;
+
+       baud = uart_get_baud_rate (port, termios, old, 8, port->uartclk/16);
+       quot = uart_get_divisor (port, baud); /* -1 performed elsewhere */
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               fcon = WLEN_5;
+               break;
+       case CS6:
+               fcon = WLEN_6;
+               break;
+       case CS7:
+               fcon = WLEN_7;
+               break;
+       case CS8:
+       default:
+               fcon = WLEN_8;
+               break;
+       }
+       if (termios->c_cflag & CSTOPB)
+               fcon |= STP2;
+       if (termios->c_cflag & PARENB) {
+               fcon |= PEN;
+               if (!(termios->c_cflag & PARODD))
+                       fcon |= EPS;
+       }
+       if (port->fifosize > 1)
+               fcon |= FEN;
+
+       spin_lock_irqsave (&port->lock, flags);
+
+       uart_update_timeout (port, termios->c_cflag, baud);
+
+       port->read_status_mask = RxOverrunError;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= RxFramingError | RxParityError;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               port->read_status_mask |= RxBreak;
+
+               /* Figure mask for status we ignore */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= RxFramingError | RxParityError;
+       if (termios->c_iflag & IGNBRK) {
+               port->ignore_status_mask |= RxBreak;
+               /* Ignore overrun when ignorning parity */
+               /* *** FIXME: is this in the right place? */
+               if (termios->c_iflag & IGNPAR)
+                       port->ignore_status_mask |= RxOverrunError;
+       }
+
+               /* Ignore all receive errors when receive disabled */
+       if ((termios->c_cflag & CREAD) == 0)
+               port->ignore_status_mask |= RxError;
+
+       con   = UR (port, UART_R_CON);
+       inten = (UR (port, UART_R_INTEN) & ~ModemInt);
+
+       if (UART_ENABLE_MS (port, termios->c_cflag))
+               inten |= ModemInt;
+
+       BIT_CLR (port, UART_R_CON, UARTEN);     /* Disable UART */
+       UR (port, UART_R_INTEN) = 0;            /* Disable interrupts */
+       UR (port, UART_R_BRCON) = quot - 1;     /* Set baud rate divisor */
+       UR (port, UART_R_FCON)  = fcon;         /* Set FIFO and frame ctrl */
+       UR (port, UART_R_INTEN) = inten;        /* Enable interrupts */
+       UR (port, UART_R_CON)   = con;          /* Restore UART mode */
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char* lh7a40xuart_type (struct uart_port* port)
+{
+       return port->type == PORT_LH7A40X ? "LH7A40X" : NULL;
+}
+
+static void lh7a40xuart_release_port (struct uart_port* port)
+{
+       release_mem_region (port->mapbase, UART_REG_SIZE);
+}
+
+static int lh7a40xuart_request_port (struct uart_port* port)
+{
+       return request_mem_region (port->mapbase, UART_REG_SIZE,
+                                  "serial_lh7a40x") != NULL
+               ? 0 : -EBUSY;
+}
+
+static void lh7a40xuart_config_port (struct uart_port* port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = PORT_LH7A40X;
+               lh7a40xuart_request_port (port);
+       }
+}
+
+static int lh7a40xuart_verify_port (struct uart_port* port,
+                                   struct serial_struct* ser)
+{
+       int ret = 0;
+
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_LH7A40X)
+               ret = -EINVAL;
+       if (ser->irq < 0 || ser->irq >= nr_irqs)
+               ret = -EINVAL;
+       if (ser->baud_base < 9600) /* *** FIXME: is this true? */
+               ret = -EINVAL;
+       return ret;
+}
+
+static struct uart_ops lh7a40x_uart_ops = {
+       .tx_empty       = lh7a40xuart_tx_empty,
+       .set_mctrl      = lh7a40xuart_set_mctrl,
+       .get_mctrl      = lh7a40xuart_get_mctrl,
+       .stop_tx        = lh7a40xuart_stop_tx,
+       .start_tx       = lh7a40xuart_start_tx,
+       .stop_rx        = lh7a40xuart_stop_rx,
+       .enable_ms      = lh7a40xuart_enable_ms,
+       .break_ctl      = lh7a40xuart_break_ctl,
+       .startup        = lh7a40xuart_startup,
+       .shutdown       = lh7a40xuart_shutdown,
+       .set_termios    = lh7a40xuart_set_termios,
+       .type           = lh7a40xuart_type,
+       .release_port   = lh7a40xuart_release_port,
+       .request_port   = lh7a40xuart_request_port,
+       .config_port    = lh7a40xuart_config_port,
+       .verify_port    = lh7a40xuart_verify_port,
+};
+
+static struct uart_port_lh7a40x lh7a40x_ports[DEV_NR] = {
+       {
+               .port = {
+                       .membase        = (void*) io_p2v (UART1_PHYS),
+                       .mapbase        = UART1_PHYS,
+                       .iotype         = UPIO_MEM,
+                       .irq            = IRQ_UART1INTR,
+                       .uartclk        = 14745600/2,
+                       .fifosize       = 16,
+                       .ops            = &lh7a40x_uart_ops,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 0,
+               },
+       },
+       {
+               .port = {
+                       .membase        = (void*) io_p2v (UART2_PHYS),
+                       .mapbase        = UART2_PHYS,
+                       .iotype         = UPIO_MEM,
+                       .irq            = IRQ_UART2INTR,
+                       .uartclk        = 14745600/2,
+                       .fifosize       = 16,
+                       .ops            = &lh7a40x_uart_ops,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 1,
+               },
+       },
+       {
+               .port = {
+                       .membase        = (void*) io_p2v (UART3_PHYS),
+                       .mapbase        = UART3_PHYS,
+                       .iotype         = UPIO_MEM,
+                       .irq            = IRQ_UART3INTR,
+                       .uartclk        = 14745600/2,
+                       .fifosize       = 16,
+                       .ops            = &lh7a40x_uart_ops,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 2,
+               },
+       },
+};
+
+#ifndef CONFIG_SERIAL_LH7A40X_CONSOLE
+# define LH7A40X_CONSOLE NULL
+#else
+# define LH7A40X_CONSOLE &lh7a40x_console
+
+static void lh7a40xuart_console_putchar(struct uart_port *port, int ch)
+{
+       while (UR(port, UART_R_STATUS) & nTxRdy)
+               ;
+       UR(port, UART_R_DATA) = ch;
+}
+
+static void lh7a40xuart_console_write (struct console* co,
+                                      const char* s,
+                                      unsigned int count)
+{
+       struct uart_port* port = &lh7a40x_ports[co->index].port;
+       unsigned int con = UR (port, UART_R_CON);
+       unsigned int inten = UR (port, UART_R_INTEN);
+
+
+       UR (port, UART_R_INTEN) = 0;            /* Disable all interrupts */
+       BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); /* Enable UART */
+
+       uart_console_write(port, s, count, lh7a40xuart_console_putchar);
+
+                               /* Wait until all characters are sent */
+       while (UR (port, UART_R_STATUS) & TxBusy)
+               ;
+
+                               /* Restore control and interrupt mask */
+       UR (port, UART_R_CON) = con;
+       UR (port, UART_R_INTEN) = inten;
+}
+
+static void __init lh7a40xuart_console_get_options (struct uart_port* port,
+                                                   int* baud,
+                                                   int* parity,
+                                                   int* bits)
+{
+       if (UR (port, UART_R_CON) & UARTEN) {
+               unsigned int fcon = UR (port, UART_R_FCON);
+               unsigned int quot = UR (port, UART_R_BRCON) + 1;
+
+               switch (fcon & (PEN | EPS)) {
+               default:        *parity = 'n'; break;
+               case PEN:       *parity = 'o'; break;
+               case PEN | EPS: *parity = 'e'; break;
+               }
+
+               switch (fcon & WLEN) {
+               default:
+               case WLEN_8: *bits = 8; break;
+               case WLEN_7: *bits = 7; break;
+               case WLEN_6: *bits = 6; break;
+               case WLEN_5: *bits = 5; break;
+               }
+
+               *baud = port->uartclk/(16*quot);
+       }
+}
+
+static int __init lh7a40xuart_console_setup (struct console* co, char* options)
+{
+       struct uart_port* port;
+       int baud = 38400;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (co->index >= DEV_NR) /* Bounds check on device number */
+               co->index = 0;
+       port = &lh7a40x_ports[co->index].port;
+
+       if (options)
+               uart_parse_options (options, &baud, &parity, &bits, &flow);
+       else
+               lh7a40xuart_console_get_options (port, &baud, &parity, &bits);
+
+       return uart_set_options (port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver lh7a40x_reg;
+static struct console lh7a40x_console = {
+       .name           = "ttyAM",
+       .write          = lh7a40xuart_console_write,
+       .device         = uart_console_device,
+       .setup          = lh7a40xuart_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &lh7a40x_reg,
+};
+
+static int __init lh7a40xuart_console_init(void)
+{
+       register_console (&lh7a40x_console);
+       return 0;
+}
+
+console_initcall (lh7a40xuart_console_init);
+
+#endif
+
+static struct uart_driver lh7a40x_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "ttyAM",
+       .dev_name               = "ttyAM",
+       .major                  = DEV_MAJOR,
+       .minor                  = DEV_MINOR,
+       .nr                     = DEV_NR,
+       .cons                   = LH7A40X_CONSOLE,
+};
+
+static int __init lh7a40xuart_init(void)
+{
+       int ret;
+
+       printk (KERN_INFO "serial: LH7A40X serial driver\n");
+
+       ret = uart_register_driver (&lh7a40x_reg);
+
+       if (ret == 0) {
+               int i;
+
+               for (i = 0; i < DEV_NR; i++) {
+                       /* UART3, when used, requires GPIO pin reallocation */
+                       if (lh7a40x_ports[i].port.mapbase == UART3_PHYS)
+                               GPIO_PINMUX |= 1<<3;
+                       uart_add_one_port (&lh7a40x_reg,
+                                          &lh7a40x_ports[i].port);
+               }
+       }
+       return ret;
+}
+
+static void __exit lh7a40xuart_exit(void)
+{
+       int i;
+
+       for (i = 0; i < DEV_NR; i++)
+               uart_remove_one_port (&lh7a40x_reg, &lh7a40x_ports[i].port);
+
+       uart_unregister_driver (&lh7a40x_reg);
+}
+
+module_init (lh7a40xuart_init);
+module_exit (lh7a40xuart_exit);
+
+MODULE_AUTHOR ("Marc Singer");
+MODULE_DESCRIPTION ("Sharp LH7A40X serial port driver");
+MODULE_LICENSE ("GPL");
diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c
new file mode 100644 (file)
index 0000000..c50e9fb
--- /dev/null
@@ -0,0 +1,1344 @@
+/*
+ *  drivers/serial/serial_txx9.c
+ *
+ * Derived from many drivers using generic_serial interface,
+ * especially serial_tx3912.c by Steven J. Hill and r39xx_serial.c
+ * (was in Linux/VR tree) by Jim Pick.
+ *
+ *  Copyright (C) 1999 Harald Koerfgen
+ *  Copyright (C) 2000 Jim Pick <jim@jimpick.com>
+ *  Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com)
+ *  Copyright (C) 2000-2002 Toshiba Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Serial driver for TX3927/TX4927/TX4925/TX4938 internal SIO controller
+ */
+
+#if defined(CONFIG_SERIAL_TXX9_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+
+#include <asm/io.h>
+
+static char *serial_version = "1.11";
+static char *serial_name = "TX39/49 Serial driver";
+
+#define PASS_LIMIT     256
+
+#if !defined(CONFIG_SERIAL_TXX9_STDSERIAL)
+/* "ttyS" is used for standard serial driver */
+#define TXX9_TTY_NAME "ttyTX"
+#define TXX9_TTY_MINOR_START   196
+#define TXX9_TTY_MAJOR 204
+#else
+/* acts like standard serial driver */
+#define TXX9_TTY_NAME "ttyS"
+#define TXX9_TTY_MINOR_START   64
+#define TXX9_TTY_MAJOR TTY_MAJOR
+#endif
+
+/* flag aliases */
+#define UPF_TXX9_HAVE_CTS_LINE UPF_BUGGY_UART
+#define UPF_TXX9_USE_SCLK      UPF_MAGIC_MULTIPLIER
+
+#ifdef CONFIG_PCI
+/* support for Toshiba TC86C001 SIO */
+#define ENABLE_SERIAL_TXX9_PCI
+#endif
+
+/*
+ * Number of serial ports
+ */
+#define UART_NR  CONFIG_SERIAL_TXX9_NR_UARTS
+
+struct uart_txx9_port {
+       struct uart_port        port;
+       /* No additional info for now */
+};
+
+#define TXX9_REGION_SIZE       0x24
+
+/* TXX9 Serial Registers */
+#define TXX9_SILCR     0x00
+#define TXX9_SIDICR    0x04
+#define TXX9_SIDISR    0x08
+#define TXX9_SICISR    0x0c
+#define TXX9_SIFCR     0x10
+#define TXX9_SIFLCR    0x14
+#define TXX9_SIBGR     0x18
+#define TXX9_SITFIFO   0x1c
+#define TXX9_SIRFIFO   0x20
+
+/* SILCR : Line Control */
+#define TXX9_SILCR_SCS_MASK    0x00000060
+#define TXX9_SILCR_SCS_IMCLK   0x00000000
+#define TXX9_SILCR_SCS_IMCLK_BG        0x00000020
+#define TXX9_SILCR_SCS_SCLK    0x00000040
+#define TXX9_SILCR_SCS_SCLK_BG 0x00000060
+#define TXX9_SILCR_UEPS        0x00000010
+#define TXX9_SILCR_UPEN        0x00000008
+#define TXX9_SILCR_USBL_MASK   0x00000004
+#define TXX9_SILCR_USBL_1BIT   0x00000000
+#define TXX9_SILCR_USBL_2BIT   0x00000004
+#define TXX9_SILCR_UMODE_MASK  0x00000003
+#define TXX9_SILCR_UMODE_8BIT  0x00000000
+#define TXX9_SILCR_UMODE_7BIT  0x00000001
+
+/* SIDICR : DMA/Int. Control */
+#define TXX9_SIDICR_TDE        0x00008000
+#define TXX9_SIDICR_RDE        0x00004000
+#define TXX9_SIDICR_TIE        0x00002000
+#define TXX9_SIDICR_RIE        0x00001000
+#define TXX9_SIDICR_SPIE       0x00000800
+#define TXX9_SIDICR_CTSAC      0x00000600
+#define TXX9_SIDICR_STIE_MASK  0x0000003f
+#define TXX9_SIDICR_STIE_OERS          0x00000020
+#define TXX9_SIDICR_STIE_CTSS          0x00000010
+#define TXX9_SIDICR_STIE_RBRKD 0x00000008
+#define TXX9_SIDICR_STIE_TRDY          0x00000004
+#define TXX9_SIDICR_STIE_TXALS 0x00000002
+#define TXX9_SIDICR_STIE_UBRKD 0x00000001
+
+/* SIDISR : DMA/Int. Status */
+#define TXX9_SIDISR_UBRK       0x00008000
+#define TXX9_SIDISR_UVALID     0x00004000
+#define TXX9_SIDISR_UFER       0x00002000
+#define TXX9_SIDISR_UPER       0x00001000
+#define TXX9_SIDISR_UOER       0x00000800
+#define TXX9_SIDISR_ERI        0x00000400
+#define TXX9_SIDISR_TOUT       0x00000200
+#define TXX9_SIDISR_TDIS       0x00000100
+#define TXX9_SIDISR_RDIS       0x00000080
+#define TXX9_SIDISR_STIS       0x00000040
+#define TXX9_SIDISR_RFDN_MASK  0x0000001f
+
+/* SICISR : Change Int. Status */
+#define TXX9_SICISR_OERS       0x00000020
+#define TXX9_SICISR_CTSS       0x00000010
+#define TXX9_SICISR_RBRKD      0x00000008
+#define TXX9_SICISR_TRDY       0x00000004
+#define TXX9_SICISR_TXALS      0x00000002
+#define TXX9_SICISR_UBRKD      0x00000001
+
+/* SIFCR : FIFO Control */
+#define TXX9_SIFCR_SWRST       0x00008000
+#define TXX9_SIFCR_RDIL_MASK   0x00000180
+#define TXX9_SIFCR_RDIL_1      0x00000000
+#define TXX9_SIFCR_RDIL_4      0x00000080
+#define TXX9_SIFCR_RDIL_8      0x00000100
+#define TXX9_SIFCR_RDIL_12     0x00000180
+#define TXX9_SIFCR_RDIL_MAX    0x00000180
+#define TXX9_SIFCR_TDIL_MASK   0x00000018
+#define TXX9_SIFCR_TDIL_MASK   0x00000018
+#define TXX9_SIFCR_TDIL_1      0x00000000
+#define TXX9_SIFCR_TDIL_4      0x00000001
+#define TXX9_SIFCR_TDIL_8      0x00000010
+#define TXX9_SIFCR_TDIL_MAX    0x00000010
+#define TXX9_SIFCR_TFRST       0x00000004
+#define TXX9_SIFCR_RFRST       0x00000002
+#define TXX9_SIFCR_FRSTE       0x00000001
+#define TXX9_SIO_TX_FIFO       8
+#define TXX9_SIO_RX_FIFO       16
+
+/* SIFLCR : Flow Control */
+#define TXX9_SIFLCR_RCS        0x00001000
+#define TXX9_SIFLCR_TES        0x00000800
+#define TXX9_SIFLCR_RTSSC      0x00000200
+#define TXX9_SIFLCR_RSDE       0x00000100
+#define TXX9_SIFLCR_TSDE       0x00000080
+#define TXX9_SIFLCR_RTSTL_MASK 0x0000001e
+#define TXX9_SIFLCR_RTSTL_MAX  0x0000001e
+#define TXX9_SIFLCR_TBRK       0x00000001
+
+/* SIBGR : Baudrate Control */
+#define TXX9_SIBGR_BCLK_MASK   0x00000300
+#define TXX9_SIBGR_BCLK_T0     0x00000000
+#define TXX9_SIBGR_BCLK_T2     0x00000100
+#define TXX9_SIBGR_BCLK_T4     0x00000200
+#define TXX9_SIBGR_BCLK_T6     0x00000300
+#define TXX9_SIBGR_BRD_MASK    0x000000ff
+
+static inline unsigned int sio_in(struct uart_txx9_port *up, int offset)
+{
+       switch (up->port.iotype) {
+       default:
+               return __raw_readl(up->port.membase + offset);
+       case UPIO_PORT:
+               return inl(up->port.iobase + offset);
+       }
+}
+
+static inline void
+sio_out(struct uart_txx9_port *up, int offset, int value)
+{
+       switch (up->port.iotype) {
+       default:
+               __raw_writel(value, up->port.membase + offset);
+               break;
+       case UPIO_PORT:
+               outl(value, up->port.iobase + offset);
+               break;
+       }
+}
+
+static inline void
+sio_mask(struct uart_txx9_port *up, int offset, unsigned int value)
+{
+       sio_out(up, offset, sio_in(up, offset) & ~value);
+}
+static inline void
+sio_set(struct uart_txx9_port *up, int offset, unsigned int value)
+{
+       sio_out(up, offset, sio_in(up, offset) | value);
+}
+
+static inline void
+sio_quot_set(struct uart_txx9_port *up, int quot)
+{
+       quot >>= 1;
+       if (quot < 256)
+               sio_out(up, TXX9_SIBGR, quot | TXX9_SIBGR_BCLK_T0);
+       else if (quot < (256 << 2))
+               sio_out(up, TXX9_SIBGR, (quot >> 2) | TXX9_SIBGR_BCLK_T2);
+       else if (quot < (256 << 4))
+               sio_out(up, TXX9_SIBGR, (quot >> 4) | TXX9_SIBGR_BCLK_T4);
+       else if (quot < (256 << 6))
+               sio_out(up, TXX9_SIBGR, (quot >> 6) | TXX9_SIBGR_BCLK_T6);
+       else
+               sio_out(up, TXX9_SIBGR, 0xff | TXX9_SIBGR_BCLK_T6);
+}
+
+static struct uart_txx9_port *to_uart_txx9_port(struct uart_port *port)
+{
+       return container_of(port, struct uart_txx9_port, port);
+}
+
+static void serial_txx9_stop_tx(struct uart_port *port)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+       sio_mask(up, TXX9_SIDICR, TXX9_SIDICR_TIE);
+}
+
+static void serial_txx9_start_tx(struct uart_port *port)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+       sio_set(up, TXX9_SIDICR, TXX9_SIDICR_TIE);
+}
+
+static void serial_txx9_stop_rx(struct uart_port *port)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+       up->port.read_status_mask &= ~TXX9_SIDISR_RDIS;
+}
+
+static void serial_txx9_enable_ms(struct uart_port *port)
+{
+       /* TXX9-SIO can not control DTR... */
+}
+
+static void serial_txx9_initialize(struct uart_port *port)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+       unsigned int tmout = 10000;
+
+       sio_out(up, TXX9_SIFCR, TXX9_SIFCR_SWRST);
+       /* TX4925 BUG WORKAROUND.  Accessing SIOC register
+        * immediately after soft reset causes bus error. */
+       mmiowb();
+       udelay(1);
+       while ((sio_in(up, TXX9_SIFCR) & TXX9_SIFCR_SWRST) && --tmout)
+               udelay(1);
+       /* TX Int by FIFO Empty, RX Int by Receiving 1 char. */
+       sio_set(up, TXX9_SIFCR,
+               TXX9_SIFCR_TDIL_MAX | TXX9_SIFCR_RDIL_1);
+       /* initial settings */
+       sio_out(up, TXX9_SILCR,
+               TXX9_SILCR_UMODE_8BIT | TXX9_SILCR_USBL_1BIT |
+               ((up->port.flags & UPF_TXX9_USE_SCLK) ?
+                TXX9_SILCR_SCS_SCLK_BG : TXX9_SILCR_SCS_IMCLK_BG));
+       sio_quot_set(up, uart_get_divisor(port, 9600));
+       sio_out(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSTL_MAX /* 15 */);
+       sio_out(up, TXX9_SIDICR, 0);
+}
+
+static inline void
+receive_chars(struct uart_txx9_port *up, unsigned int *status)
+{
+       struct tty_struct *tty = up->port.state->port.tty;
+       unsigned char ch;
+       unsigned int disr = *status;
+       int max_count = 256;
+       char flag;
+       unsigned int next_ignore_status_mask;
+
+       do {
+               ch = sio_in(up, TXX9_SIRFIFO);
+               flag = TTY_NORMAL;
+               up->port.icount.rx++;
+
+               /* mask out RFDN_MASK bit added by previous overrun */
+               next_ignore_status_mask =
+                       up->port.ignore_status_mask & ~TXX9_SIDISR_RFDN_MASK;
+               if (unlikely(disr & (TXX9_SIDISR_UBRK | TXX9_SIDISR_UPER |
+                                    TXX9_SIDISR_UFER | TXX9_SIDISR_UOER))) {
+                       /*
+                        * For statistics only
+                        */
+                       if (disr & TXX9_SIDISR_UBRK) {
+                               disr &= ~(TXX9_SIDISR_UFER | TXX9_SIDISR_UPER);
+                               up->port.icount.brk++;
+                               /*
+                                * We do the SysRQ and SAK checking
+                                * here because otherwise the break
+                                * may get masked by ignore_status_mask
+                                * or read_status_mask.
+                                */
+                               if (uart_handle_break(&up->port))
+                                       goto ignore_char;
+                       } else if (disr & TXX9_SIDISR_UPER)
+                               up->port.icount.parity++;
+                       else if (disr & TXX9_SIDISR_UFER)
+                               up->port.icount.frame++;
+                       if (disr & TXX9_SIDISR_UOER) {
+                               up->port.icount.overrun++;
+                               /*
+                                * The receiver read buffer still hold
+                                * a char which caused overrun.
+                                * Ignore next char by adding RFDN_MASK
+                                * to ignore_status_mask temporarily.
+                                */
+                               next_ignore_status_mask |=
+                                       TXX9_SIDISR_RFDN_MASK;
+                       }
+
+                       /*
+                        * Mask off conditions which should be ingored.
+                        */
+                       disr &= up->port.read_status_mask;
+
+                       if (disr & TXX9_SIDISR_UBRK) {
+                               flag = TTY_BREAK;
+                       } else if (disr & TXX9_SIDISR_UPER)
+                               flag = TTY_PARITY;
+                       else if (disr & TXX9_SIDISR_UFER)
+                               flag = TTY_FRAME;
+               }
+               if (uart_handle_sysrq_char(&up->port, ch))
+                       goto ignore_char;
+
+               uart_insert_char(&up->port, disr, TXX9_SIDISR_UOER, ch, flag);
+
+       ignore_char:
+               up->port.ignore_status_mask = next_ignore_status_mask;
+               disr = sio_in(up, TXX9_SIDISR);
+       } while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0));
+       spin_unlock(&up->port.lock);
+       tty_flip_buffer_push(tty);
+       spin_lock(&up->port.lock);
+       *status = disr;
+}
+
+static inline void transmit_chars(struct uart_txx9_port *up)
+{
+       struct circ_buf *xmit = &up->port.state->xmit;
+       int count;
+
+       if (up->port.x_char) {
+               sio_out(up, TXX9_SITFIFO, up->port.x_char);
+               up->port.icount.tx++;
+               up->port.x_char = 0;
+               return;
+       }
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+               serial_txx9_stop_tx(&up->port);
+               return;
+       }
+
+       count = TXX9_SIO_TX_FIFO;
+       do {
+               sio_out(up, TXX9_SITFIFO, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               up->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (--count > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+       if (uart_circ_empty(xmit))
+               serial_txx9_stop_tx(&up->port);
+}
+
+static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id)
+{
+       int pass_counter = 0;
+       struct uart_txx9_port *up = dev_id;
+       unsigned int status;
+
+       while (1) {
+               spin_lock(&up->port.lock);
+               status = sio_in(up, TXX9_SIDISR);
+               if (!(sio_in(up, TXX9_SIDICR) & TXX9_SIDICR_TIE))
+                       status &= ~TXX9_SIDISR_TDIS;
+               if (!(status & (TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS |
+                               TXX9_SIDISR_TOUT))) {
+                       spin_unlock(&up->port.lock);
+                       break;
+               }
+
+               if (status & TXX9_SIDISR_RDIS)
+                       receive_chars(up, &status);
+               if (status & TXX9_SIDISR_TDIS)
+                       transmit_chars(up);
+               /* Clear TX/RX Int. Status */
+               sio_mask(up, TXX9_SIDISR,
+                        TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS |
+                        TXX9_SIDISR_TOUT);
+               spin_unlock(&up->port.lock);
+
+               if (pass_counter++ > PASS_LIMIT)
+                       break;
+       }
+
+       return pass_counter ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static unsigned int serial_txx9_tx_empty(struct uart_port *port)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+       unsigned long flags;
+       unsigned int ret;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       ret = (sio_in(up, TXX9_SICISR) & TXX9_SICISR_TXALS) ? TIOCSER_TEMT : 0;
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       return ret;
+}
+
+static unsigned int serial_txx9_get_mctrl(struct uart_port *port)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+       unsigned int ret;
+
+       /* no modem control lines */
+       ret = TIOCM_CAR | TIOCM_DSR;
+       ret |= (sio_in(up, TXX9_SIFLCR) & TXX9_SIFLCR_RTSSC) ? 0 : TIOCM_RTS;
+       ret |= (sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS) ? 0 : TIOCM_CTS;
+
+       return ret;
+}
+
+static void serial_txx9_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+
+       if (mctrl & TIOCM_RTS)
+               sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC);
+       else
+               sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC);
+}
+
+static void serial_txx9_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+       unsigned long flags;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       if (break_state == -1)
+               sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK);
+       else
+               sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+#if defined(CONFIG_SERIAL_TXX9_CONSOLE) || (CONFIG_CONSOLE_POLL)
+/*
+ *     Wait for transmitter & holding register to empty
+ */
+static void wait_for_xmitr(struct uart_txx9_port *up)
+{
+       unsigned int tmout = 10000;
+
+       /* Wait up to 10ms for the character(s) to be sent. */
+       while (--tmout &&
+              !(sio_in(up, TXX9_SICISR) & TXX9_SICISR_TXALS))
+               udelay(1);
+
+       /* Wait up to 1s for flow control if necessary */
+       if (up->port.flags & UPF_CONS_FLOW) {
+               tmout = 1000000;
+               while (--tmout &&
+                      (sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS))
+                       udelay(1);
+       }
+}
+#endif
+
+#ifdef CONFIG_CONSOLE_POLL
+/*
+ * Console polling routines for writing and reading from the uart while
+ * in an interrupt or debug context.
+ */
+
+static int serial_txx9_get_poll_char(struct uart_port *port)
+{
+       unsigned int ier;
+       unsigned char c;
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+
+       /*
+        *      First save the IER then disable the interrupts
+        */
+       ier = sio_in(up, TXX9_SIDICR);
+       sio_out(up, TXX9_SIDICR, 0);
+
+       while (sio_in(up, TXX9_SIDISR) & TXX9_SIDISR_UVALID)
+               ;
+
+       c = sio_in(up, TXX9_SIRFIFO);
+
+       /*
+        *      Finally, clear RX interrupt status
+        *      and restore the IER
+        */
+       sio_mask(up, TXX9_SIDISR, TXX9_SIDISR_RDIS);
+       sio_out(up, TXX9_SIDICR, ier);
+       return c;
+}
+
+
+static void serial_txx9_put_poll_char(struct uart_port *port, unsigned char c)
+{
+       unsigned int ier;
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+
+       /*
+        *      First save the IER then disable the interrupts
+        */
+       ier = sio_in(up, TXX9_SIDICR);
+       sio_out(up, TXX9_SIDICR, 0);
+
+       wait_for_xmitr(up);
+       /*
+        *      Send the character out.
+        *      If a LF, also do CR...
+        */
+       sio_out(up, TXX9_SITFIFO, c);
+       if (c == 10) {
+               wait_for_xmitr(up);
+               sio_out(up, TXX9_SITFIFO, 13);
+       }
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the IER
+        */
+       wait_for_xmitr(up);
+       sio_out(up, TXX9_SIDICR, ier);
+}
+
+#endif /* CONFIG_CONSOLE_POLL */
+
+static int serial_txx9_startup(struct uart_port *port)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+       unsigned long flags;
+       int retval;
+
+       /*
+        * Clear the FIFO buffers and disable them.
+        * (they will be reenabled in set_termios())
+        */
+       sio_set(up, TXX9_SIFCR,
+               TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE);
+       /* clear reset */
+       sio_mask(up, TXX9_SIFCR,
+                TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE);
+       sio_out(up, TXX9_SIDICR, 0);
+
+       /*
+        * Clear the interrupt registers.
+        */
+       sio_out(up, TXX9_SIDISR, 0);
+
+       retval = request_irq(up->port.irq, serial_txx9_interrupt,
+                            IRQF_SHARED, "serial_txx9", up);
+       if (retval)
+               return retval;
+
+       /*
+        * Now, initialize the UART
+        */
+       spin_lock_irqsave(&up->port.lock, flags);
+       serial_txx9_set_mctrl(&up->port, up->port.mctrl);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       /* Enable RX/TX */
+       sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RSDE | TXX9_SIFLCR_TSDE);
+
+       /*
+        * Finally, enable interrupts.
+        */
+       sio_set(up, TXX9_SIDICR, TXX9_SIDICR_RIE);
+
+       return 0;
+}
+
+static void serial_txx9_shutdown(struct uart_port *port)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+       unsigned long flags;
+
+       /*
+        * Disable interrupts from this port
+        */
+       sio_out(up, TXX9_SIDICR, 0);    /* disable all intrs */
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       serial_txx9_set_mctrl(&up->port, up->port.mctrl);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       /*
+        * Disable break condition
+        */
+       sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK);
+
+#ifdef CONFIG_SERIAL_TXX9_CONSOLE
+       if (up->port.cons && up->port.line == up->port.cons->index) {
+               free_irq(up->port.irq, up);
+               return;
+       }
+#endif
+       /* reset FIFOs */
+       sio_set(up, TXX9_SIFCR,
+               TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE);
+       /* clear reset */
+       sio_mask(up, TXX9_SIFCR,
+                TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE);
+
+       /* Disable RX/TX */
+       sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RSDE | TXX9_SIFLCR_TSDE);
+
+       free_irq(up->port.irq, up);
+}
+
+static void
+serial_txx9_set_termios(struct uart_port *port, struct ktermios *termios,
+                      struct ktermios *old)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+       unsigned int cval, fcr = 0;
+       unsigned long flags;
+       unsigned int baud, quot;
+
+       /*
+        * We don't support modem control lines.
+        */
+       termios->c_cflag &= ~(HUPCL | CMSPAR);
+       termios->c_cflag |= CLOCAL;
+
+       cval = sio_in(up, TXX9_SILCR);
+       /* byte size and parity */
+       cval &= ~TXX9_SILCR_UMODE_MASK;
+       switch (termios->c_cflag & CSIZE) {
+       case CS7:
+               cval |= TXX9_SILCR_UMODE_7BIT;
+               break;
+       default:
+       case CS5:       /* not supported */
+       case CS6:       /* not supported */
+       case CS8:
+               cval |= TXX9_SILCR_UMODE_8BIT;
+               break;
+       }
+
+       cval &= ~TXX9_SILCR_USBL_MASK;
+       if (termios->c_cflag & CSTOPB)
+               cval |= TXX9_SILCR_USBL_2BIT;
+       else
+               cval |= TXX9_SILCR_USBL_1BIT;
+       cval &= ~(TXX9_SILCR_UPEN | TXX9_SILCR_UEPS);
+       if (termios->c_cflag & PARENB)
+               cval |= TXX9_SILCR_UPEN;
+       if (!(termios->c_cflag & PARODD))
+               cval |= TXX9_SILCR_UEPS;
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16/2);
+       quot = uart_get_divisor(port, baud);
+
+       /* Set up FIFOs */
+       /* TX Int by FIFO Empty, RX Int by Receiving 1 char. */
+       fcr = TXX9_SIFCR_TDIL_MAX | TXX9_SIFCR_RDIL_1;
+
+       /*
+        * Ok, we're now changing the port state.  Do it with
+        * interrupts disabled.
+        */
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       up->port.read_status_mask = TXX9_SIDISR_UOER |
+               TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS;
+       if (termios->c_iflag & INPCK)
+               up->port.read_status_mask |= TXX9_SIDISR_UFER | TXX9_SIDISR_UPER;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               up->port.read_status_mask |= TXX9_SIDISR_UBRK;
+
+       /*
+        * Characteres to ignore
+        */
+       up->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               up->port.ignore_status_mask |= TXX9_SIDISR_UPER | TXX9_SIDISR_UFER;
+       if (termios->c_iflag & IGNBRK) {
+               up->port.ignore_status_mask |= TXX9_SIDISR_UBRK;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       up->port.ignore_status_mask |= TXX9_SIDISR_UOER;
+       }
+
+       /*
+        * ignore all characters if CREAD is not set
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               up->port.ignore_status_mask |= TXX9_SIDISR_RDIS;
+
+       /* CTS flow control flag */
+       if ((termios->c_cflag & CRTSCTS) &&
+           (up->port.flags & UPF_TXX9_HAVE_CTS_LINE)) {
+               sio_set(up, TXX9_SIFLCR,
+                       TXX9_SIFLCR_RCS | TXX9_SIFLCR_TES);
+       } else {
+               sio_mask(up, TXX9_SIFLCR,
+                        TXX9_SIFLCR_RCS | TXX9_SIFLCR_TES);
+       }
+
+       sio_out(up, TXX9_SILCR, cval);
+       sio_quot_set(up, quot);
+       sio_out(up, TXX9_SIFCR, fcr);
+
+       serial_txx9_set_mctrl(&up->port, up->port.mctrl);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static void
+serial_txx9_pm(struct uart_port *port, unsigned int state,
+             unsigned int oldstate)
+{
+       /*
+        * If oldstate was -1 this is called from
+        * uart_configure_port().  In this case do not initialize the
+        * port now, because the port was already initialized (for
+        * non-console port) or should not be initialized here (for
+        * console port).  If we initialized the port here we lose
+        * serial console settings.
+        */
+       if (state == 0 && oldstate != -1)
+               serial_txx9_initialize(port);
+}
+
+static int serial_txx9_request_resource(struct uart_txx9_port *up)
+{
+       unsigned int size = TXX9_REGION_SIZE;
+       int ret = 0;
+
+       switch (up->port.iotype) {
+       default:
+               if (!up->port.mapbase)
+                       break;
+
+               if (!request_mem_region(up->port.mapbase, size, "serial_txx9")) {
+                       ret = -EBUSY;
+                       break;
+               }
+
+               if (up->port.flags & UPF_IOREMAP) {
+                       up->port.membase = ioremap(up->port.mapbase, size);
+                       if (!up->port.membase) {
+                               release_mem_region(up->port.mapbase, size);
+                               ret = -ENOMEM;
+                       }
+               }
+               break;
+
+       case UPIO_PORT:
+               if (!request_region(up->port.iobase, size, "serial_txx9"))
+                       ret = -EBUSY;
+               break;
+       }
+       return ret;
+}
+
+static void serial_txx9_release_resource(struct uart_txx9_port *up)
+{
+       unsigned int size = TXX9_REGION_SIZE;
+
+       switch (up->port.iotype) {
+       default:
+               if (!up->port.mapbase)
+                       break;
+
+               if (up->port.flags & UPF_IOREMAP) {
+                       iounmap(up->port.membase);
+                       up->port.membase = NULL;
+               }
+
+               release_mem_region(up->port.mapbase, size);
+               break;
+
+       case UPIO_PORT:
+               release_region(up->port.iobase, size);
+               break;
+       }
+}
+
+static void serial_txx9_release_port(struct uart_port *port)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+       serial_txx9_release_resource(up);
+}
+
+static int serial_txx9_request_port(struct uart_port *port)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+       return serial_txx9_request_resource(up);
+}
+
+static void serial_txx9_config_port(struct uart_port *port, int uflags)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+       int ret;
+
+       /*
+        * Find the region that we can probe for.  This in turn
+        * tells us whether we can probe for the type of port.
+        */
+       ret = serial_txx9_request_resource(up);
+       if (ret < 0)
+               return;
+       port->type = PORT_TXX9;
+       up->port.fifosize = TXX9_SIO_TX_FIFO;
+
+#ifdef CONFIG_SERIAL_TXX9_CONSOLE
+       if (up->port.line == up->port.cons->index)
+               return;
+#endif
+       serial_txx9_initialize(port);
+}
+
+static const char *
+serial_txx9_type(struct uart_port *port)
+{
+       return "txx9";
+}
+
+static struct uart_ops serial_txx9_pops = {
+       .tx_empty       = serial_txx9_tx_empty,
+       .set_mctrl      = serial_txx9_set_mctrl,
+       .get_mctrl      = serial_txx9_get_mctrl,
+       .stop_tx        = serial_txx9_stop_tx,
+       .start_tx       = serial_txx9_start_tx,
+       .stop_rx        = serial_txx9_stop_rx,
+       .enable_ms      = serial_txx9_enable_ms,
+       .break_ctl      = serial_txx9_break_ctl,
+       .startup        = serial_txx9_startup,
+       .shutdown       = serial_txx9_shutdown,
+       .set_termios    = serial_txx9_set_termios,
+       .pm             = serial_txx9_pm,
+       .type           = serial_txx9_type,
+       .release_port   = serial_txx9_release_port,
+       .request_port   = serial_txx9_request_port,
+       .config_port    = serial_txx9_config_port,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char  = serial_txx9_get_poll_char,
+       .poll_put_char  = serial_txx9_put_poll_char,
+#endif
+};
+
+static struct uart_txx9_port serial_txx9_ports[UART_NR];
+
+static void __init serial_txx9_register_ports(struct uart_driver *drv,
+                                             struct device *dev)
+{
+       int i;
+
+       for (i = 0; i < UART_NR; i++) {
+               struct uart_txx9_port *up = &serial_txx9_ports[i];
+
+               up->port.line = i;
+               up->port.ops = &serial_txx9_pops;
+               up->port.dev = dev;
+               if (up->port.iobase || up->port.mapbase)
+                       uart_add_one_port(drv, &up->port);
+       }
+}
+
+#ifdef CONFIG_SERIAL_TXX9_CONSOLE
+
+static void serial_txx9_console_putchar(struct uart_port *port, int ch)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+
+       wait_for_xmitr(up);
+       sio_out(up, TXX9_SITFIFO, ch);
+}
+
+/*
+ *     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.
+ */
+static void
+serial_txx9_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct uart_txx9_port *up = &serial_txx9_ports[co->index];
+       unsigned int ier, flcr;
+
+       /*
+        *      First save the UER then disable the interrupts
+        */
+       ier = sio_in(up, TXX9_SIDICR);
+       sio_out(up, TXX9_SIDICR, 0);
+       /*
+        *      Disable flow-control if enabled (and unnecessary)
+        */
+       flcr = sio_in(up, TXX9_SIFLCR);
+       if (!(up->port.flags & UPF_CONS_FLOW) && (flcr & TXX9_SIFLCR_TES))
+               sio_out(up, TXX9_SIFLCR, flcr & ~TXX9_SIFLCR_TES);
+
+       uart_console_write(&up->port, s, count, serial_txx9_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the IER
+        */
+       wait_for_xmitr(up);
+       sio_out(up, TXX9_SIFLCR, flcr);
+       sio_out(up, TXX9_SIDICR, ier);
+}
+
+static int __init serial_txx9_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       struct uart_txx9_port *up;
+       int baud = 9600;
+       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.
+        */
+       if (co->index >= UART_NR)
+               co->index = 0;
+       up = &serial_txx9_ports[co->index];
+       port = &up->port;
+       if (!port->ops)
+               return -ENODEV;
+
+       serial_txx9_initialize(&up->port);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver serial_txx9_reg;
+static struct console serial_txx9_console = {
+       .name           = TXX9_TTY_NAME,
+       .write          = serial_txx9_console_write,
+       .device         = uart_console_device,
+       .setup          = serial_txx9_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &serial_txx9_reg,
+};
+
+static int __init serial_txx9_console_init(void)
+{
+       register_console(&serial_txx9_console);
+       return 0;
+}
+console_initcall(serial_txx9_console_init);
+
+#define SERIAL_TXX9_CONSOLE    &serial_txx9_console
+#else
+#define SERIAL_TXX9_CONSOLE    NULL
+#endif
+
+static struct uart_driver serial_txx9_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "serial_txx9",
+       .dev_name               = TXX9_TTY_NAME,
+       .major                  = TXX9_TTY_MAJOR,
+       .minor                  = TXX9_TTY_MINOR_START,
+       .nr                     = UART_NR,
+       .cons                   = SERIAL_TXX9_CONSOLE,
+};
+
+int __init early_serial_txx9_setup(struct uart_port *port)
+{
+       if (port->line >= ARRAY_SIZE(serial_txx9_ports))
+               return -ENODEV;
+
+       serial_txx9_ports[port->line].port = *port;
+       serial_txx9_ports[port->line].port.ops = &serial_txx9_pops;
+       serial_txx9_ports[port->line].port.flags |=
+               UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
+       return 0;
+}
+
+static DEFINE_MUTEX(serial_txx9_mutex);
+
+/**
+ *     serial_txx9_register_port - register a serial port
+ *     @port: serial port template
+ *
+ *     Configure the serial port specified by the request.
+ *
+ *     The port is then probed and if necessary the IRQ is autodetected
+ *     If this fails an error is returned.
+ *
+ *     On success the port is ready to use and the line number is returned.
+ */
+static int __devinit serial_txx9_register_port(struct uart_port *port)
+{
+       int i;
+       struct uart_txx9_port *uart;
+       int ret = -ENOSPC;
+
+       mutex_lock(&serial_txx9_mutex);
+       for (i = 0; i < UART_NR; i++) {
+               uart = &serial_txx9_ports[i];
+               if (uart_match_port(&uart->port, port)) {
+                       uart_remove_one_port(&serial_txx9_reg, &uart->port);
+                       break;
+               }
+       }
+       if (i == UART_NR) {
+               /* Find unused port */
+               for (i = 0; i < UART_NR; i++) {
+                       uart = &serial_txx9_ports[i];
+                       if (!(uart->port.iobase || uart->port.mapbase))
+                               break;
+               }
+       }
+       if (i < UART_NR) {
+               uart->port.iobase = port->iobase;
+               uart->port.membase = port->membase;
+               uart->port.irq      = port->irq;
+               uart->port.uartclk  = port->uartclk;
+               uart->port.iotype   = port->iotype;
+               uart->port.flags    = port->flags
+                       | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
+               uart->port.mapbase  = port->mapbase;
+               if (port->dev)
+                       uart->port.dev = port->dev;
+               ret = uart_add_one_port(&serial_txx9_reg, &uart->port);
+               if (ret == 0)
+                       ret = uart->port.line;
+       }
+       mutex_unlock(&serial_txx9_mutex);
+       return ret;
+}
+
+/**
+ *     serial_txx9_unregister_port - remove a txx9 serial port at runtime
+ *     @line: serial line number
+ *
+ *     Remove one serial port.  This may not be called from interrupt
+ *     context.  We hand the port back to the our control.
+ */
+static void __devexit serial_txx9_unregister_port(int line)
+{
+       struct uart_txx9_port *uart = &serial_txx9_ports[line];
+
+       mutex_lock(&serial_txx9_mutex);
+       uart_remove_one_port(&serial_txx9_reg, &uart->port);
+       uart->port.flags = 0;
+       uart->port.type = PORT_UNKNOWN;
+       uart->port.iobase = 0;
+       uart->port.mapbase = 0;
+       uart->port.membase = NULL;
+       uart->port.dev = NULL;
+       mutex_unlock(&serial_txx9_mutex);
+}
+
+/*
+ * Register a set of serial devices attached to a platform device.
+ */
+static int __devinit serial_txx9_probe(struct platform_device *dev)
+{
+       struct uart_port *p = dev->dev.platform_data;
+       struct uart_port port;
+       int ret, i;
+
+       memset(&port, 0, sizeof(struct uart_port));
+       for (i = 0; p && p->uartclk != 0; p++, i++) {
+               port.iobase     = p->iobase;
+               port.membase    = p->membase;
+               port.irq        = p->irq;
+               port.uartclk    = p->uartclk;
+               port.iotype     = p->iotype;
+               port.flags      = p->flags;
+               port.mapbase    = p->mapbase;
+               port.dev        = &dev->dev;
+               ret = serial_txx9_register_port(&port);
+               if (ret < 0) {
+                       dev_err(&dev->dev, "unable to register port at index %d "
+                               "(IO%lx MEM%llx IRQ%d): %d\n", i,
+                               p->iobase, (unsigned long long)p->mapbase,
+                               p->irq, ret);
+               }
+       }
+       return 0;
+}
+
+/*
+ * Remove serial ports registered against a platform device.
+ */
+static int __devexit serial_txx9_remove(struct platform_device *dev)
+{
+       int i;
+
+       for (i = 0; i < UART_NR; i++) {
+               struct uart_txx9_port *up = &serial_txx9_ports[i];
+
+               if (up->port.dev == &dev->dev)
+                       serial_txx9_unregister_port(i);
+       }
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int serial_txx9_suspend(struct platform_device *dev, pm_message_t state)
+{
+       int i;
+
+       for (i = 0; i < UART_NR; i++) {
+               struct uart_txx9_port *up = &serial_txx9_ports[i];
+
+               if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
+                       uart_suspend_port(&serial_txx9_reg, &up->port);
+       }
+
+       return 0;
+}
+
+static int serial_txx9_resume(struct platform_device *dev)
+{
+       int i;
+
+       for (i = 0; i < UART_NR; i++) {
+               struct uart_txx9_port *up = &serial_txx9_ports[i];
+
+               if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
+                       uart_resume_port(&serial_txx9_reg, &up->port);
+       }
+
+       return 0;
+}
+#endif
+
+static struct platform_driver serial_txx9_plat_driver = {
+       .probe          = serial_txx9_probe,
+       .remove         = __devexit_p(serial_txx9_remove),
+#ifdef CONFIG_PM
+       .suspend        = serial_txx9_suspend,
+       .resume         = serial_txx9_resume,
+#endif
+       .driver         = {
+               .name   = "serial_txx9",
+               .owner  = THIS_MODULE,
+       },
+};
+
+#ifdef ENABLE_SERIAL_TXX9_PCI
+/*
+ * Probe one serial board.  Unfortunately, there is no rhyme nor reason
+ * to the arrangement of serial ports on a PCI card.
+ */
+static int __devinit
+pciserial_txx9_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
+{
+       struct uart_port port;
+       int line;
+       int rc;
+
+       rc = pci_enable_device(dev);
+       if (rc)
+               return rc;
+
+       memset(&port, 0, sizeof(port));
+       port.ops = &serial_txx9_pops;
+       port.flags |= UPF_TXX9_HAVE_CTS_LINE;
+       port.uartclk = 66670000;
+       port.irq = dev->irq;
+       port.iotype = UPIO_PORT;
+       port.iobase = pci_resource_start(dev, 1);
+       port.dev = &dev->dev;
+       line = serial_txx9_register_port(&port);
+       if (line < 0) {
+               printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), line);
+               pci_disable_device(dev);
+               return line;
+       }
+       pci_set_drvdata(dev, &serial_txx9_ports[line]);
+
+       return 0;
+}
+
+static void __devexit pciserial_txx9_remove_one(struct pci_dev *dev)
+{
+       struct uart_txx9_port *up = pci_get_drvdata(dev);
+
+       pci_set_drvdata(dev, NULL);
+
+       if (up) {
+               serial_txx9_unregister_port(up->port.line);
+               pci_disable_device(dev);
+       }
+}
+
+#ifdef CONFIG_PM
+static int pciserial_txx9_suspend_one(struct pci_dev *dev, pm_message_t state)
+{
+       struct uart_txx9_port *up = pci_get_drvdata(dev);
+
+       if (up)
+               uart_suspend_port(&serial_txx9_reg, &up->port);
+       pci_save_state(dev);
+       pci_set_power_state(dev, pci_choose_state(dev, state));
+       return 0;
+}
+
+static int pciserial_txx9_resume_one(struct pci_dev *dev)
+{
+       struct uart_txx9_port *up = pci_get_drvdata(dev);
+
+       pci_set_power_state(dev, PCI_D0);
+       pci_restore_state(dev);
+       if (up)
+               uart_resume_port(&serial_txx9_reg, &up->port);
+       return 0;
+}
+#endif
+
+static const struct pci_device_id serial_txx9_pci_tbl[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC) },
+       { 0, }
+};
+
+static struct pci_driver serial_txx9_pci_driver = {
+       .name           = "serial_txx9",
+       .probe          = pciserial_txx9_init_one,
+       .remove         = __devexit_p(pciserial_txx9_remove_one),
+#ifdef CONFIG_PM
+       .suspend        = pciserial_txx9_suspend_one,
+       .resume         = pciserial_txx9_resume_one,
+#endif
+       .id_table       = serial_txx9_pci_tbl,
+};
+
+MODULE_DEVICE_TABLE(pci, serial_txx9_pci_tbl);
+#endif /* ENABLE_SERIAL_TXX9_PCI */
+
+static struct platform_device *serial_txx9_plat_devs;
+
+static int __init serial_txx9_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
+
+       ret = uart_register_driver(&serial_txx9_reg);
+       if (ret)
+               goto out;
+
+       serial_txx9_plat_devs = platform_device_alloc("serial_txx9", -1);
+       if (!serial_txx9_plat_devs) {
+               ret = -ENOMEM;
+               goto unreg_uart_drv;
+       }
+
+       ret = platform_device_add(serial_txx9_plat_devs);
+       if (ret)
+               goto put_dev;
+
+       serial_txx9_register_ports(&serial_txx9_reg,
+                                  &serial_txx9_plat_devs->dev);
+
+       ret = platform_driver_register(&serial_txx9_plat_driver);
+       if (ret)
+               goto del_dev;
+
+#ifdef ENABLE_SERIAL_TXX9_PCI
+       ret = pci_register_driver(&serial_txx9_pci_driver);
+#endif
+       if (ret == 0)
+               goto out;
+
+ del_dev:
+       platform_device_del(serial_txx9_plat_devs);
+ put_dev:
+       platform_device_put(serial_txx9_plat_devs);
+ unreg_uart_drv:
+       uart_unregister_driver(&serial_txx9_reg);
+ out:
+       return ret;
+}
+
+static void __exit serial_txx9_exit(void)
+{
+       int i;
+
+#ifdef ENABLE_SERIAL_TXX9_PCI
+       pci_unregister_driver(&serial_txx9_pci_driver);
+#endif
+       platform_driver_unregister(&serial_txx9_plat_driver);
+       platform_device_unregister(serial_txx9_plat_devs);
+       for (i = 0; i < UART_NR; i++) {
+               struct uart_txx9_port *up = &serial_txx9_ports[i];
+               if (up->port.iobase || up->port.mapbase)
+                       uart_remove_one_port(&serial_txx9_reg, &up->port);
+       }
+
+       uart_unregister_driver(&serial_txx9_reg);
+}
+
+module_init(serial_txx9_init);
+module_exit(serial_txx9_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("TX39/49 serial driver");
+
+MODULE_ALIAS_CHARDEV_MAJOR(TXX9_TTY_MAJOR);
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
new file mode 100644 (file)
index 0000000..c291b3a
--- /dev/null
@@ -0,0 +1,2027 @@
+/*
+ * drivers/serial/sh-sci.c
+ *
+ * SuperH on-chip serial module support.  (SCI with no FIFO / with FIFO)
+ *
+ *  Copyright (C) 2002 - 2008  Paul Mundt
+ *  Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Jul 2007).
+ *
+ * based off of the old drivers/char/sh-sci.c by:
+ *
+ *   Copyright (C) 1999, 2000  Niibe Yutaka
+ *   Copyright (C) 2000  Sugioka Toshinobu
+ *   Modified to support multiple serial ports. Stuart Menefy (May 2000).
+ *   Modified to support SecureEdge. David McCullough (2002)
+ *   Modified to support SH7300 SCIF. Takashi Kusuda (Jun 2003).
+ *   Removed SH7300 support (Jul 2007).
+ *
+ * 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.
+ */
+#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#undef DEBUG
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/sysrq.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/console.h>
+#include <linux/platform_device.h>
+#include <linux/serial_sci.h>
+#include <linux/notifier.h>
+#include <linux/cpufreq.h>
+#include <linux/clk.h>
+#include <linux/ctype.h>
+#include <linux/err.h>
+#include <linux/list.h>
+#include <linux/dmaengine.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+
+#ifdef CONFIG_SUPERH
+#include <asm/sh_bios.h>
+#endif
+
+#ifdef CONFIG_H8300
+#include <asm/gpio.h>
+#endif
+
+#include "sh-sci.h"
+
+struct sci_port {
+       struct uart_port        port;
+
+       /* Port type */
+       unsigned int            type;
+
+       /* Port IRQs: ERI, RXI, TXI, BRI (optional) */
+       unsigned int            irqs[SCIx_NR_IRQS];
+
+       /* Port enable callback */
+       void                    (*enable)(struct uart_port *port);
+
+       /* Port disable callback */
+       void                    (*disable)(struct uart_port *port);
+
+       /* Break timer */
+       struct timer_list       break_timer;
+       int                     break_flag;
+
+       /* Interface clock */
+       struct clk              *iclk;
+       /* Function clock */
+       struct clk              *fclk;
+
+       struct list_head        node;
+       struct dma_chan                 *chan_tx;
+       struct dma_chan                 *chan_rx;
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+       struct device                   *dma_dev;
+       unsigned int                    slave_tx;
+       unsigned int                    slave_rx;
+       struct dma_async_tx_descriptor  *desc_tx;
+       struct dma_async_tx_descriptor  *desc_rx[2];
+       dma_cookie_t                    cookie_tx;
+       dma_cookie_t                    cookie_rx[2];
+       dma_cookie_t                    active_rx;
+       struct scatterlist              sg_tx;
+       unsigned int                    sg_len_tx;
+       struct scatterlist              sg_rx[2];
+       size_t                          buf_len_rx;
+       struct sh_dmae_slave            param_tx;
+       struct sh_dmae_slave            param_rx;
+       struct work_struct              work_tx;
+       struct work_struct              work_rx;
+       struct timer_list               rx_timer;
+       unsigned int                    rx_timeout;
+#endif
+};
+
+struct sh_sci_priv {
+       spinlock_t lock;
+       struct list_head ports;
+       struct notifier_block clk_nb;
+};
+
+/* Function prototypes */
+static void sci_stop_tx(struct uart_port *port);
+
+#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
+
+static struct sci_port sci_ports[SCI_NPORTS];
+static struct uart_driver sci_uart_driver;
+
+static inline struct sci_port *
+to_sci_port(struct uart_port *uart)
+{
+       return container_of(uart, struct sci_port, port);
+}
+
+#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
+
+#ifdef CONFIG_CONSOLE_POLL
+static inline void handle_error(struct uart_port *port)
+{
+       /* Clear error flags */
+       sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
+}
+
+static int sci_poll_get_char(struct uart_port *port)
+{
+       unsigned short status;
+       int c;
+
+       do {
+               status = sci_in(port, SCxSR);
+               if (status & SCxSR_ERRORS(port)) {
+                       handle_error(port);
+                       continue;
+               }
+               break;
+       } while (1);
+
+       if (!(status & SCxSR_RDxF(port)))
+               return NO_POLL_CHAR;
+
+       c = sci_in(port, SCxRDR);
+
+       /* Dummy read */
+       sci_in(port, SCxSR);
+       sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+
+       return c;
+}
+#endif
+
+static void sci_poll_put_char(struct uart_port *port, unsigned char c)
+{
+       unsigned short status;
+
+       do {
+               status = sci_in(port, SCxSR);
+       } while (!(status & SCxSR_TDxE(port)));
+
+       sci_out(port, SCxTDR, c);
+       sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
+}
+#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */
+
+#if defined(__H8300H__) || defined(__H8300S__)
+static void sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+       int ch = (port->mapbase - SMR0) >> 3;
+
+       /* set DDR regs */
+       H8300_GPIO_DDR(h8300_sci_pins[ch].port,
+                      h8300_sci_pins[ch].rx,
+                      H8300_GPIO_INPUT);
+       H8300_GPIO_DDR(h8300_sci_pins[ch].port,
+                      h8300_sci_pins[ch].tx,
+                      H8300_GPIO_OUTPUT);
+
+       /* tx mark output*/
+       H8300_SCI_DR(ch) |= h8300_sci_pins[ch].tx;
+}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
+static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+       if (port->mapbase == 0xA4400000) {
+               __raw_writew(__raw_readw(PACR) & 0xffc0, PACR);
+               __raw_writew(__raw_readw(PBCR) & 0x0fff, PBCR);
+       } else if (port->mapbase == 0xA4410000)
+               __raw_writew(__raw_readw(PBCR) & 0xf003, PBCR);
+}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || defined(CONFIG_CPU_SUBTYPE_SH7721)
+static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+       unsigned short data;
+
+       if (cflag & CRTSCTS) {
+               /* enable RTS/CTS */
+               if (port->mapbase == 0xa4430000) { /* SCIF0 */
+                       /* Clear PTCR bit 9-2; enable all scif pins but sck */
+                       data = __raw_readw(PORT_PTCR);
+                       __raw_writew((data & 0xfc03), PORT_PTCR);
+               } else if (port->mapbase == 0xa4438000) { /* SCIF1 */
+                       /* Clear PVCR bit 9-2 */
+                       data = __raw_readw(PORT_PVCR);
+                       __raw_writew((data & 0xfc03), PORT_PVCR);
+               }
+       } else {
+               if (port->mapbase == 0xa4430000) { /* SCIF0 */
+                       /* Clear PTCR bit 5-2; enable only tx and rx  */
+                       data = __raw_readw(PORT_PTCR);
+                       __raw_writew((data & 0xffc3), PORT_PTCR);
+               } else if (port->mapbase == 0xa4438000) { /* SCIF1 */
+                       /* Clear PVCR bit 5-2 */
+                       data = __raw_readw(PORT_PVCR);
+                       __raw_writew((data & 0xffc3), PORT_PVCR);
+               }
+       }
+}
+#elif defined(CONFIG_CPU_SH3)
+/* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */
+static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+       unsigned short data;
+
+       /* We need to set SCPCR to enable RTS/CTS */
+       data = __raw_readw(SCPCR);
+       /* Clear out SCP7MD1,0, SCP6MD1,0, SCP4MD1,0*/
+       __raw_writew(data & 0x0fcf, SCPCR);
+
+       if (!(cflag & CRTSCTS)) {
+               /* We need to set SCPCR to enable RTS/CTS */
+               data = __raw_readw(SCPCR);
+               /* Clear out SCP7MD1,0, SCP4MD1,0,
+                  Set SCP6MD1,0 = {01} (output)  */
+               __raw_writew((data & 0x0fcf) | 0x1000, SCPCR);
+
+               data = __raw_readb(SCPDR);
+               /* Set /RTS2 (bit6) = 0 */
+               __raw_writeb(data & 0xbf, SCPDR);
+       }
+}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
+static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+       unsigned short data;
+
+       if (port->mapbase == 0xffe00000) {
+               data = __raw_readw(PSCR);
+               data &= ~0x03cf;
+               if (!(cflag & CRTSCTS))
+                       data |= 0x0340;
+
+               __raw_writew(data, PSCR);
+       }
+}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7757) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7763) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7785) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7786) || \
+      defined(CONFIG_CPU_SUBTYPE_SHX3)
+static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+       if (!(cflag & CRTSCTS))
+               __raw_writew(0x0080, SCSPTR0); /* Set RTS = 1 */
+}
+#elif defined(CONFIG_CPU_SH4) && !defined(CONFIG_CPU_SH4A)
+static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+       if (!(cflag & CRTSCTS))
+               __raw_writew(0x0080, SCSPTR2); /* Set RTS = 1 */
+}
+#else
+static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+       /* Nothing to do */
+}
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7760) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7785) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7786)
+static int scif_txfill(struct uart_port *port)
+{
+       return sci_in(port, SCTFDR) & 0xff;
+}
+
+static int scif_txroom(struct uart_port *port)
+{
+       return SCIF_TXROOM_MAX - scif_txfill(port);
+}
+
+static int scif_rxfill(struct uart_port *port)
+{
+       return sci_in(port, SCRFDR) & 0xff;
+}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
+static int scif_txfill(struct uart_port *port)
+{
+       if (port->mapbase == 0xffe00000 ||
+           port->mapbase == 0xffe08000)
+               /* SCIF0/1*/
+               return sci_in(port, SCTFDR) & 0xff;
+       else
+               /* SCIF2 */
+               return sci_in(port, SCFDR) >> 8;
+}
+
+static int scif_txroom(struct uart_port *port)
+{
+       if (port->mapbase == 0xffe00000 ||
+           port->mapbase == 0xffe08000)
+               /* SCIF0/1*/
+               return SCIF_TXROOM_MAX - scif_txfill(port);
+       else
+               /* SCIF2 */
+               return SCIF2_TXROOM_MAX - scif_txfill(port);
+}
+
+static int scif_rxfill(struct uart_port *port)
+{
+       if ((port->mapbase == 0xffe00000) ||
+           (port->mapbase == 0xffe08000)) {
+               /* SCIF0/1*/
+               return sci_in(port, SCRFDR) & 0xff;
+       } else {
+               /* SCIF2 */
+               return sci_in(port, SCFDR) & SCIF2_RFDC_MASK;
+       }
+}
+#elif defined(CONFIG_ARCH_SH7372)
+static int scif_txfill(struct uart_port *port)
+{
+       if (port->type == PORT_SCIFA)
+               return sci_in(port, SCFDR) >> 8;
+       else
+               return sci_in(port, SCTFDR);
+}
+
+static int scif_txroom(struct uart_port *port)
+{
+       return port->fifosize - scif_txfill(port);
+}
+
+static int scif_rxfill(struct uart_port *port)
+{
+       if (port->type == PORT_SCIFA)
+               return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
+       else
+               return sci_in(port, SCRFDR);
+}
+#else
+static int scif_txfill(struct uart_port *port)
+{
+       return sci_in(port, SCFDR) >> 8;
+}
+
+static int scif_txroom(struct uart_port *port)
+{
+       return SCIF_TXROOM_MAX - scif_txfill(port);
+}
+
+static int scif_rxfill(struct uart_port *port)
+{
+       return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
+}
+#endif
+
+static int sci_txfill(struct uart_port *port)
+{
+       return !(sci_in(port, SCxSR) & SCI_TDRE);
+}
+
+static int sci_txroom(struct uart_port *port)
+{
+       return !sci_txfill(port);
+}
+
+static int sci_rxfill(struct uart_port *port)
+{
+       return (sci_in(port, SCxSR) & SCxSR_RDxF(port)) != 0;
+}
+
+/* ********************************************************************** *
+ *                   the interrupt related routines                       *
+ * ********************************************************************** */
+
+static void sci_transmit_chars(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->state->xmit;
+       unsigned int stopped = uart_tx_stopped(port);
+       unsigned short status;
+       unsigned short ctrl;
+       int count;
+
+       status = sci_in(port, SCxSR);
+       if (!(status & SCxSR_TDxE(port))) {
+               ctrl = sci_in(port, SCSCR);
+               if (uart_circ_empty(xmit))
+                       ctrl &= ~SCI_CTRL_FLAGS_TIE;
+               else
+                       ctrl |= SCI_CTRL_FLAGS_TIE;
+               sci_out(port, SCSCR, ctrl);
+               return;
+       }
+
+       if (port->type == PORT_SCI)
+               count = sci_txroom(port);
+       else
+               count = scif_txroom(port);
+
+       do {
+               unsigned char c;
+
+               if (port->x_char) {
+                       c = port->x_char;
+                       port->x_char = 0;
+               } else if (!uart_circ_empty(xmit) && !stopped) {
+                       c = xmit->buf[xmit->tail];
+                       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               } else {
+                       break;
+               }
+
+               sci_out(port, SCxTDR, c);
+
+               port->icount.tx++;
+       } while (--count > 0);
+
+       sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+       if (uart_circ_empty(xmit)) {
+               sci_stop_tx(port);
+       } else {
+               ctrl = sci_in(port, SCSCR);
+
+               if (port->type != PORT_SCI) {
+                       sci_in(port, SCxSR); /* Dummy read */
+                       sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
+               }
+
+               ctrl |= SCI_CTRL_FLAGS_TIE;
+               sci_out(port, SCSCR, ctrl);
+       }
+}
+
+/* On SH3, SCIF may read end-of-break as a space->mark char */
+#define STEPFN(c)  ({int __c = (c); (((__c-1)|(__c)) == -1); })
+
+static inline void sci_receive_chars(struct uart_port *port)
+{
+       struct sci_port *sci_port = to_sci_port(port);
+       struct tty_struct *tty = port->state->port.tty;
+       int i, count, copied = 0;
+       unsigned short status;
+       unsigned char flag;
+
+       status = sci_in(port, SCxSR);
+       if (!(status & SCxSR_RDxF(port)))
+               return;
+
+       while (1) {
+               if (port->type == PORT_SCI)
+                       count = sci_rxfill(port);
+               else
+                       count = scif_rxfill(port);
+
+               /* Don't copy more bytes than there is room for in the buffer */
+               count = tty_buffer_request_room(tty, count);
+
+               /* If for any reason we can't copy more data, we're done! */
+               if (count == 0)
+                       break;
+
+               if (port->type == PORT_SCI) {
+                       char c = sci_in(port, SCxRDR);
+                       if (uart_handle_sysrq_char(port, c) ||
+                           sci_port->break_flag)
+                               count = 0;
+                       else
+                               tty_insert_flip_char(tty, c, TTY_NORMAL);
+               } else {
+                       for (i = 0; i < count; i++) {
+                               char c = sci_in(port, SCxRDR);
+                               status = sci_in(port, SCxSR);
+#if defined(CONFIG_CPU_SH3)
+                               /* Skip "chars" during break */
+                               if (sci_port->break_flag) {
+                                       if ((c == 0) &&
+                                           (status & SCxSR_FER(port))) {
+                                               count--; i--;
+                                               continue;
+                                       }
+
+                                       /* Nonzero => end-of-break */
+                                       dev_dbg(port->dev, "debounce<%02x>\n", c);
+                                       sci_port->break_flag = 0;
+
+                                       if (STEPFN(c)) {
+                                               count--; i--;
+                                               continue;
+                                       }
+                               }
+#endif /* CONFIG_CPU_SH3 */
+                               if (uart_handle_sysrq_char(port, c)) {
+                                       count--; i--;
+                                       continue;
+                               }
+
+                               /* Store data and status */
+                               if (status & SCxSR_FER(port)) {
+                                       flag = TTY_FRAME;
+                                       dev_notice(port->dev, "frame error\n");
+                               } else if (status & SCxSR_PER(port)) {
+                                       flag = TTY_PARITY;
+                                       dev_notice(port->dev, "parity error\n");
+                               } else
+                                       flag = TTY_NORMAL;
+
+                               tty_insert_flip_char(tty, c, flag);
+                       }
+               }
+
+               sci_in(port, SCxSR); /* dummy read */
+               sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+
+               copied += count;
+               port->icount.rx += count;
+       }
+
+       if (copied) {
+               /* Tell the rest of the system the news. New characters! */
+               tty_flip_buffer_push(tty);
+       } else {
+               sci_in(port, SCxSR); /* dummy read */
+               sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+       }
+}
+
+#define SCI_BREAK_JIFFIES (HZ/20)
+/* The sci generates interrupts during the break,
+ * 1 per millisecond or so during the break period, for 9600 baud.
+ * So dont bother disabling interrupts.
+ * But dont want more than 1 break event.
+ * Use a kernel timer to periodically poll the rx line until
+ * the break is finished.
+ */
+static void sci_schedule_break_timer(struct sci_port *port)
+{
+       port->break_timer.expires = jiffies + SCI_BREAK_JIFFIES;
+       add_timer(&port->break_timer);
+}
+/* Ensure that two consecutive samples find the break over. */
+static void sci_break_timer(unsigned long data)
+{
+       struct sci_port *port = (struct sci_port *)data;
+
+       if (sci_rxd_in(&port->port) == 0) {
+               port->break_flag = 1;
+               sci_schedule_break_timer(port);
+       } else if (port->break_flag == 1) {
+               /* break is over. */
+               port->break_flag = 2;
+               sci_schedule_break_timer(port);
+       } else
+               port->break_flag = 0;
+}
+
+static inline int sci_handle_errors(struct uart_port *port)
+{
+       int copied = 0;
+       unsigned short status = sci_in(port, SCxSR);
+       struct tty_struct *tty = port->state->port.tty;
+
+       if (status & SCxSR_ORER(port)) {
+               /* overrun error */
+               if (tty_insert_flip_char(tty, 0, TTY_OVERRUN))
+                       copied++;
+
+               dev_notice(port->dev, "overrun error");
+       }
+
+       if (status & SCxSR_FER(port)) {
+               if (sci_rxd_in(port) == 0) {
+                       /* Notify of BREAK */
+                       struct sci_port *sci_port = to_sci_port(port);
+
+                       if (!sci_port->break_flag) {
+                               sci_port->break_flag = 1;
+                               sci_schedule_break_timer(sci_port);
+
+                               /* Do sysrq handling. */
+                               if (uart_handle_break(port))
+                                       return 0;
+
+                               dev_dbg(port->dev, "BREAK detected\n");
+
+                               if (tty_insert_flip_char(tty, 0, TTY_BREAK))
+                                       copied++;
+                       }
+
+               } else {
+                       /* frame error */
+                       if (tty_insert_flip_char(tty, 0, TTY_FRAME))
+                               copied++;
+
+                       dev_notice(port->dev, "frame error\n");
+               }
+       }
+
+       if (status & SCxSR_PER(port)) {
+               /* parity error */
+               if (tty_insert_flip_char(tty, 0, TTY_PARITY))
+                       copied++;
+
+               dev_notice(port->dev, "parity error");
+       }
+
+       if (copied)
+               tty_flip_buffer_push(tty);
+
+       return copied;
+}
+
+static inline int sci_handle_fifo_overrun(struct uart_port *port)
+{
+       struct tty_struct *tty = port->state->port.tty;
+       int copied = 0;
+
+       if (port->type != PORT_SCIF)
+               return 0;
+
+       if ((sci_in(port, SCLSR) & SCIF_ORER) != 0) {
+               sci_out(port, SCLSR, 0);
+
+               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+               tty_flip_buffer_push(tty);
+
+               dev_notice(port->dev, "overrun error\n");
+               copied++;
+       }
+
+       return copied;
+}
+
+static inline int sci_handle_breaks(struct uart_port *port)
+{
+       int copied = 0;
+       unsigned short status = sci_in(port, SCxSR);
+       struct tty_struct *tty = port->state->port.tty;
+       struct sci_port *s = to_sci_port(port);
+
+       if (uart_handle_break(port))
+               return 0;
+
+       if (!s->break_flag && status & SCxSR_BRK(port)) {
+#if defined(CONFIG_CPU_SH3)
+               /* Debounce break */
+               s->break_flag = 1;
+#endif
+               /* Notify of BREAK */
+               if (tty_insert_flip_char(tty, 0, TTY_BREAK))
+                       copied++;
+
+               dev_dbg(port->dev, "BREAK detected\n");
+       }
+
+       if (copied)
+               tty_flip_buffer_push(tty);
+
+       copied += sci_handle_fifo_overrun(port);
+
+       return copied;
+}
+
+static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
+{
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+       struct uart_port *port = ptr;
+       struct sci_port *s = to_sci_port(port);
+
+       if (s->chan_rx) {
+               u16 scr = sci_in(port, SCSCR);
+               u16 ssr = sci_in(port, SCxSR);
+
+               /* Disable future Rx interrupts */
+               if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+                       disable_irq_nosync(irq);
+                       scr |= 0x4000;
+               } else {
+                       scr &= ~SCI_CTRL_FLAGS_RIE;
+               }
+               sci_out(port, SCSCR, scr);
+               /* Clear current interrupt */
+               sci_out(port, SCxSR, ssr & ~(1 | SCxSR_RDxF(port)));
+               dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u jiffies\n",
+                       jiffies, s->rx_timeout);
+               mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
+
+               return IRQ_HANDLED;
+       }
+#endif
+
+       /* I think sci_receive_chars has to be called irrespective
+        * of whether the I_IXOFF is set, otherwise, how is the interrupt
+        * to be disabled?
+        */
+       sci_receive_chars(ptr);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t sci_tx_interrupt(int irq, void *ptr)
+{
+       struct uart_port *port = ptr;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       sci_transmit_chars(port);
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t sci_er_interrupt(int irq, void *ptr)
+{
+       struct uart_port *port = ptr;
+
+       /* Handle errors */
+       if (port->type == PORT_SCI) {
+               if (sci_handle_errors(port)) {
+                       /* discard character in rx buffer */
+                       sci_in(port, SCxSR);
+                       sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+               }
+       } else {
+               sci_handle_fifo_overrun(port);
+               sci_rx_interrupt(irq, ptr);
+       }
+
+       sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
+
+       /* Kick the transmission */
+       sci_tx_interrupt(irq, ptr);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t sci_br_interrupt(int irq, void *ptr)
+{
+       struct uart_port *port = ptr;
+
+       /* Handle BREAKs */
+       sci_handle_breaks(port);
+       sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port));
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
+{
+       unsigned short ssr_status, scr_status, err_enabled;
+       struct uart_port *port = ptr;
+       struct sci_port *s = to_sci_port(port);
+       irqreturn_t ret = IRQ_NONE;
+
+       ssr_status = sci_in(port, SCxSR);
+       scr_status = sci_in(port, SCSCR);
+       err_enabled = scr_status & (SCI_CTRL_FLAGS_REIE | SCI_CTRL_FLAGS_RIE);
+
+       /* Tx Interrupt */
+       if ((ssr_status & SCxSR_TDxE(port)) && (scr_status & SCI_CTRL_FLAGS_TIE) &&
+           !s->chan_tx)
+               ret = sci_tx_interrupt(irq, ptr);
+       /*
+        * Rx Interrupt: if we're using DMA, the DMA controller clears RDF /
+        * DR flags
+        */
+       if (((ssr_status & SCxSR_RDxF(port)) || s->chan_rx) &&
+           (scr_status & SCI_CTRL_FLAGS_RIE))
+               ret = sci_rx_interrupt(irq, ptr);
+       /* Error Interrupt */
+       if ((ssr_status & SCxSR_ERRORS(port)) && err_enabled)
+               ret = sci_er_interrupt(irq, ptr);
+       /* Break Interrupt */
+       if ((ssr_status & SCxSR_BRK(port)) && err_enabled)
+               ret = sci_br_interrupt(irq, ptr);
+
+       return ret;
+}
+
+/*
+ * Here we define a transistion notifier so that we can update all of our
+ * ports' baud rate when the peripheral clock changes.
+ */
+static int sci_notifier(struct notifier_block *self,
+                       unsigned long phase, void *p)
+{
+       struct sh_sci_priv *priv = container_of(self,
+                                               struct sh_sci_priv, clk_nb);
+       struct sci_port *sci_port;
+       unsigned long flags;
+
+       if ((phase == CPUFREQ_POSTCHANGE) ||
+           (phase == CPUFREQ_RESUMECHANGE)) {
+               spin_lock_irqsave(&priv->lock, flags);
+               list_for_each_entry(sci_port, &priv->ports, node)
+                       sci_port->port.uartclk = clk_get_rate(sci_port->iclk);
+               spin_unlock_irqrestore(&priv->lock, flags);
+       }
+
+       return NOTIFY_OK;
+}
+
+static void sci_clk_enable(struct uart_port *port)
+{
+       struct sci_port *sci_port = to_sci_port(port);
+
+       clk_enable(sci_port->iclk);
+       sci_port->port.uartclk = clk_get_rate(sci_port->iclk);
+       clk_enable(sci_port->fclk);
+}
+
+static void sci_clk_disable(struct uart_port *port)
+{
+       struct sci_port *sci_port = to_sci_port(port);
+
+       clk_disable(sci_port->fclk);
+       clk_disable(sci_port->iclk);
+}
+
+static int sci_request_irq(struct sci_port *port)
+{
+       int i;
+       irqreturn_t (*handlers[4])(int irq, void *ptr) = {
+               sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt,
+               sci_br_interrupt,
+       };
+       const char *desc[] = { "SCI Receive Error", "SCI Receive Data Full",
+                              "SCI Transmit Data Empty", "SCI Break" };
+
+       if (port->irqs[0] == port->irqs[1]) {
+               if (unlikely(!port->irqs[0]))
+                       return -ENODEV;
+
+               if (request_irq(port->irqs[0], sci_mpxed_interrupt,
+                               IRQF_DISABLED, "sci", port)) {
+                       dev_err(port->port.dev, "Can't allocate IRQ\n");
+                       return -ENODEV;
+               }
+       } else {
+               for (i = 0; i < ARRAY_SIZE(handlers); i++) {
+                       if (unlikely(!port->irqs[i]))
+                               continue;
+
+                       if (request_irq(port->irqs[i], handlers[i],
+                                       IRQF_DISABLED, desc[i], port)) {
+                               dev_err(port->port.dev, "Can't allocate IRQ\n");
+                               return -ENODEV;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static void sci_free_irq(struct sci_port *port)
+{
+       int i;
+
+       if (port->irqs[0] == port->irqs[1])
+               free_irq(port->irqs[0], port);
+       else {
+               for (i = 0; i < ARRAY_SIZE(port->irqs); i++) {
+                       if (!port->irqs[i])
+                               continue;
+
+                       free_irq(port->irqs[i], port);
+               }
+       }
+}
+
+static unsigned int sci_tx_empty(struct uart_port *port)
+{
+       unsigned short status = sci_in(port, SCxSR);
+       unsigned short in_tx_fifo = scif_txfill(port);
+
+       return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0;
+}
+
+static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       /* This routine is used for seting signals of: DTR, DCD, CTS/RTS */
+       /* We use SCIF's hardware for CTS/RTS, so don't need any for that. */
+       /* If you have signals for DTR and DCD, please implement here. */
+}
+
+static unsigned int sci_get_mctrl(struct uart_port *port)
+{
+       /* This routine is used for getting signals of: DTR, DCD, DSR, RI,
+          and CTS/RTS */
+
+       return TIOCM_DTR | TIOCM_RTS | TIOCM_DSR;
+}
+
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+static void sci_dma_tx_complete(void *arg)
+{
+       struct sci_port *s = arg;
+       struct uart_port *port = &s->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       unsigned long flags;
+
+       dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       xmit->tail += sg_dma_len(&s->sg_tx);
+       xmit->tail &= UART_XMIT_SIZE - 1;
+
+       port->icount.tx += sg_dma_len(&s->sg_tx);
+
+       async_tx_ack(s->desc_tx);
+       s->cookie_tx = -EINVAL;
+       s->desc_tx = NULL;
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (!uart_circ_empty(xmit)) {
+               schedule_work(&s->work_tx);
+       } else if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+               u16 ctrl = sci_in(port, SCSCR);
+               sci_out(port, SCSCR, ctrl & ~SCI_CTRL_FLAGS_TIE);
+       }
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* Locking: called with port lock held */
+static int sci_dma_rx_push(struct sci_port *s, struct tty_struct *tty,
+                          size_t count)
+{
+       struct uart_port *port = &s->port;
+       int i, active, room;
+
+       room = tty_buffer_request_room(tty, count);
+
+       if (s->active_rx == s->cookie_rx[0]) {
+               active = 0;
+       } else if (s->active_rx == s->cookie_rx[1]) {
+               active = 1;
+       } else {
+               dev_err(port->dev, "cookie %d not found!\n", s->active_rx);
+               return 0;
+       }
+
+       if (room < count)
+               dev_warn(port->dev, "Rx overrun: dropping %u bytes\n",
+                        count - room);
+       if (!room)
+               return room;
+
+       for (i = 0; i < room; i++)
+               tty_insert_flip_char(tty, ((u8 *)sg_virt(&s->sg_rx[active]))[i],
+                                    TTY_NORMAL);
+
+       port->icount.rx += room;
+
+       return room;
+}
+
+static void sci_dma_rx_complete(void *arg)
+{
+       struct sci_port *s = arg;
+       struct uart_port *port = &s->port;
+       struct tty_struct *tty = port->state->port.tty;
+       unsigned long flags;
+       int count;
+
+       dev_dbg(port->dev, "%s(%d) active #%d\n", __func__, port->line, s->active_rx);
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       count = sci_dma_rx_push(s, tty, s->buf_len_rx);
+
+       mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       if (count)
+               tty_flip_buffer_push(tty);
+
+       schedule_work(&s->work_rx);
+}
+
+static void sci_start_rx(struct uart_port *port);
+static void sci_start_tx(struct uart_port *port);
+
+static void sci_rx_dma_release(struct sci_port *s, bool enable_pio)
+{
+       struct dma_chan *chan = s->chan_rx;
+       struct uart_port *port = &s->port;
+
+       s->chan_rx = NULL;
+       s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL;
+       dma_release_channel(chan);
+       if (sg_dma_address(&s->sg_rx[0]))
+               dma_free_coherent(port->dev, s->buf_len_rx * 2,
+                                 sg_virt(&s->sg_rx[0]), sg_dma_address(&s->sg_rx[0]));
+       if (enable_pio)
+               sci_start_rx(port);
+}
+
+static void sci_tx_dma_release(struct sci_port *s, bool enable_pio)
+{
+       struct dma_chan *chan = s->chan_tx;
+       struct uart_port *port = &s->port;
+
+       s->chan_tx = NULL;
+       s->cookie_tx = -EINVAL;
+       dma_release_channel(chan);
+       if (enable_pio)
+               sci_start_tx(port);
+}
+
+static void sci_submit_rx(struct sci_port *s)
+{
+       struct dma_chan *chan = s->chan_rx;
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               struct scatterlist *sg = &s->sg_rx[i];
+               struct dma_async_tx_descriptor *desc;
+
+               desc = chan->device->device_prep_slave_sg(chan,
+                       sg, 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT);
+
+               if (desc) {
+                       s->desc_rx[i] = desc;
+                       desc->callback = sci_dma_rx_complete;
+                       desc->callback_param = s;
+                       s->cookie_rx[i] = desc->tx_submit(desc);
+               }
+
+               if (!desc || s->cookie_rx[i] < 0) {
+                       if (i) {
+                               async_tx_ack(s->desc_rx[0]);
+                               s->cookie_rx[0] = -EINVAL;
+                       }
+                       if (desc) {
+                               async_tx_ack(desc);
+                               s->cookie_rx[i] = -EINVAL;
+                       }
+                       dev_warn(s->port.dev,
+                                "failed to re-start DMA, using PIO\n");
+                       sci_rx_dma_release(s, true);
+                       return;
+               }
+               dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", __func__,
+                       s->cookie_rx[i], i);
+       }
+
+       s->active_rx = s->cookie_rx[0];
+
+       dma_async_issue_pending(chan);
+}
+
+static void work_fn_rx(struct work_struct *work)
+{
+       struct sci_port *s = container_of(work, struct sci_port, work_rx);
+       struct uart_port *port = &s->port;
+       struct dma_async_tx_descriptor *desc;
+       int new;
+
+       if (s->active_rx == s->cookie_rx[0]) {
+               new = 0;
+       } else if (s->active_rx == s->cookie_rx[1]) {
+               new = 1;
+       } else {
+               dev_err(port->dev, "cookie %d not found!\n", s->active_rx);
+               return;
+       }
+       desc = s->desc_rx[new];
+
+       if (dma_async_is_tx_complete(s->chan_rx, s->active_rx, NULL, NULL) !=
+           DMA_SUCCESS) {
+               /* Handle incomplete DMA receive */
+               struct tty_struct *tty = port->state->port.tty;
+               struct dma_chan *chan = s->chan_rx;
+               struct sh_desc *sh_desc = container_of(desc, struct sh_desc,
+                                                      async_tx);
+               unsigned long flags;
+               int count;
+
+               chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+               dev_dbg(port->dev, "Read %u bytes with cookie %d\n",
+                       sh_desc->partial, sh_desc->cookie);
+
+               spin_lock_irqsave(&port->lock, flags);
+               count = sci_dma_rx_push(s, tty, sh_desc->partial);
+               spin_unlock_irqrestore(&port->lock, flags);
+
+               if (count)
+                       tty_flip_buffer_push(tty);
+
+               sci_submit_rx(s);
+
+               return;
+       }
+
+       s->cookie_rx[new] = desc->tx_submit(desc);
+       if (s->cookie_rx[new] < 0) {
+               dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n");
+               sci_rx_dma_release(s, true);
+               return;
+       }
+
+       s->active_rx = s->cookie_rx[!new];
+
+       dev_dbg(port->dev, "%s: cookie %d #%d, new active #%d\n", __func__,
+               s->cookie_rx[new], new, s->active_rx);
+}
+
+static void work_fn_tx(struct work_struct *work)
+{
+       struct sci_port *s = container_of(work, struct sci_port, work_tx);
+       struct dma_async_tx_descriptor *desc;
+       struct dma_chan *chan = s->chan_tx;
+       struct uart_port *port = &s->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       struct scatterlist *sg = &s->sg_tx;
+
+       /*
+        * DMA is idle now.
+        * Port xmit buffer is already mapped, and it is one page... Just adjust
+        * offsets and lengths. Since it is a circular buffer, we have to
+        * transmit till the end, and then the rest. Take the port lock to get a
+        * consistent xmit buffer state.
+        */
+       spin_lock_irq(&port->lock);
+       sg->offset = xmit->tail & (UART_XMIT_SIZE - 1);
+       sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) +
+               sg->offset;
+       sg_dma_len(sg) = min((int)CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE),
+               CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE));
+       spin_unlock_irq(&port->lock);
+
+       BUG_ON(!sg_dma_len(sg));
+
+       desc = chan->device->device_prep_slave_sg(chan,
+                       sg, s->sg_len_tx, DMA_TO_DEVICE,
+                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!desc) {
+               /* switch to PIO */
+               sci_tx_dma_release(s, true);
+               return;
+       }
+
+       dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE);
+
+       spin_lock_irq(&port->lock);
+       s->desc_tx = desc;
+       desc->callback = sci_dma_tx_complete;
+       desc->callback_param = s;
+       spin_unlock_irq(&port->lock);
+       s->cookie_tx = desc->tx_submit(desc);
+       if (s->cookie_tx < 0) {
+               dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n");
+               /* switch to PIO */
+               sci_tx_dma_release(s, true);
+               return;
+       }
+
+       dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", __func__,
+               xmit->buf, xmit->tail, xmit->head, s->cookie_tx);
+
+       dma_async_issue_pending(chan);
+}
+#endif
+
+static void sci_start_tx(struct uart_port *port)
+{
+       struct sci_port *s = to_sci_port(port);
+       unsigned short ctrl;
+
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+               u16 new, scr = sci_in(port, SCSCR);
+               if (s->chan_tx)
+                       new = scr | 0x8000;
+               else
+                       new = scr & ~0x8000;
+               if (new != scr)
+                       sci_out(port, SCSCR, new);
+       }
+       if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) &&
+           s->cookie_tx < 0)
+               schedule_work(&s->work_tx);
+#endif
+       if (!s->chan_tx || port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+               /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
+               ctrl = sci_in(port, SCSCR);
+               sci_out(port, SCSCR, ctrl | SCI_CTRL_FLAGS_TIE);
+       }
+}
+
+static void sci_stop_tx(struct uart_port *port)
+{
+       unsigned short ctrl;
+
+       /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */
+       ctrl = sci_in(port, SCSCR);
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+               ctrl &= ~0x8000;
+       ctrl &= ~SCI_CTRL_FLAGS_TIE;
+       sci_out(port, SCSCR, ctrl);
+}
+
+static void sci_start_rx(struct uart_port *port)
+{
+       unsigned short ctrl = SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE;
+
+       /* Set RIE (Receive Interrupt Enable) bit in SCSCR */
+       ctrl |= sci_in(port, SCSCR);
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+               ctrl &= ~0x4000;
+       sci_out(port, SCSCR, ctrl);
+}
+
+static void sci_stop_rx(struct uart_port *port)
+{
+       unsigned short ctrl;
+
+       /* Clear RIE (Receive Interrupt Enable) bit in SCSCR */
+       ctrl = sci_in(port, SCSCR);
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+               ctrl &= ~0x4000;
+       ctrl &= ~(SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE);
+       sci_out(port, SCSCR, ctrl);
+}
+
+static void sci_enable_ms(struct uart_port *port)
+{
+       /* Nothing here yet .. */
+}
+
+static void sci_break_ctl(struct uart_port *port, int break_state)
+{
+       /* Nothing here yet .. */
+}
+
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+static bool filter(struct dma_chan *chan, void *slave)
+{
+       struct sh_dmae_slave *param = slave;
+
+       dev_dbg(chan->device->dev, "%s: slave ID %d\n", __func__,
+               param->slave_id);
+
+       if (param->dma_dev == chan->device->dev) {
+               chan->private = param;
+               return true;
+       } else {
+               return false;
+       }
+}
+
+static void rx_timer_fn(unsigned long arg)
+{
+       struct sci_port *s = (struct sci_port *)arg;
+       struct uart_port *port = &s->port;
+       u16 scr = sci_in(port, SCSCR);
+
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+               scr &= ~0x4000;
+               enable_irq(s->irqs[1]);
+       }
+       sci_out(port, SCSCR, scr | SCI_CTRL_FLAGS_RIE);
+       dev_dbg(port->dev, "DMA Rx timed out\n");
+       schedule_work(&s->work_rx);
+}
+
+static void sci_request_dma(struct uart_port *port)
+{
+       struct sci_port *s = to_sci_port(port);
+       struct sh_dmae_slave *param;
+       struct dma_chan *chan;
+       dma_cap_mask_t mask;
+       int nent;
+
+       dev_dbg(port->dev, "%s: port %d DMA %p\n", __func__,
+               port->line, s->dma_dev);
+
+       if (!s->dma_dev)
+               return;
+
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+
+       param = &s->param_tx;
+
+       /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_TX */
+       param->slave_id = s->slave_tx;
+       param->dma_dev = s->dma_dev;
+
+       s->cookie_tx = -EINVAL;
+       chan = dma_request_channel(mask, filter, param);
+       dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan);
+       if (chan) {
+               s->chan_tx = chan;
+               sg_init_table(&s->sg_tx, 1);
+               /* UART circular tx buffer is an aligned page. */
+               BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK);
+               sg_set_page(&s->sg_tx, virt_to_page(port->state->xmit.buf),
+                           UART_XMIT_SIZE, (int)port->state->xmit.buf & ~PAGE_MASK);
+               nent = dma_map_sg(port->dev, &s->sg_tx, 1, DMA_TO_DEVICE);
+               if (!nent)
+                       sci_tx_dma_release(s, false);
+               else
+                       dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__,
+                               sg_dma_len(&s->sg_tx),
+                               port->state->xmit.buf, sg_dma_address(&s->sg_tx));
+
+               s->sg_len_tx = nent;
+
+               INIT_WORK(&s->work_tx, work_fn_tx);
+       }
+
+       param = &s->param_rx;
+
+       /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_RX */
+       param->slave_id = s->slave_rx;
+       param->dma_dev = s->dma_dev;
+
+       chan = dma_request_channel(mask, filter, param);
+       dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan);
+       if (chan) {
+               dma_addr_t dma[2];
+               void *buf[2];
+               int i;
+
+               s->chan_rx = chan;
+
+               s->buf_len_rx = 2 * max(16, (int)port->fifosize);
+               buf[0] = dma_alloc_coherent(port->dev, s->buf_len_rx * 2,
+                                           &dma[0], GFP_KERNEL);
+
+               if (!buf[0]) {
+                       dev_warn(port->dev,
+                                "failed to allocate dma buffer, using PIO\n");
+                       sci_rx_dma_release(s, true);
+                       return;
+               }
+
+               buf[1] = buf[0] + s->buf_len_rx;
+               dma[1] = dma[0] + s->buf_len_rx;
+
+               for (i = 0; i < 2; i++) {
+                       struct scatterlist *sg = &s->sg_rx[i];
+
+                       sg_init_table(sg, 1);
+                       sg_set_page(sg, virt_to_page(buf[i]), s->buf_len_rx,
+                                   (int)buf[i] & ~PAGE_MASK);
+                       sg_dma_address(sg) = dma[i];
+               }
+
+               INIT_WORK(&s->work_rx, work_fn_rx);
+               setup_timer(&s->rx_timer, rx_timer_fn, (unsigned long)s);
+
+               sci_submit_rx(s);
+       }
+}
+
+static void sci_free_dma(struct uart_port *port)
+{
+       struct sci_port *s = to_sci_port(port);
+
+       if (!s->dma_dev)
+               return;
+
+       if (s->chan_tx)
+               sci_tx_dma_release(s, false);
+       if (s->chan_rx)
+               sci_rx_dma_release(s, false);
+}
+#endif
+
+static int sci_startup(struct uart_port *port)
+{
+       struct sci_port *s = to_sci_port(port);
+
+       dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
+
+       if (s->enable)
+               s->enable(port);
+
+       sci_request_irq(s);
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+       sci_request_dma(port);
+#endif
+       sci_start_tx(port);
+       sci_start_rx(port);
+
+       return 0;
+}
+
+static void sci_shutdown(struct uart_port *port)
+{
+       struct sci_port *s = to_sci_port(port);
+
+       dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
+
+       sci_stop_rx(port);
+       sci_stop_tx(port);
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+       sci_free_dma(port);
+#endif
+       sci_free_irq(s);
+
+       if (s->disable)
+               s->disable(port);
+}
+
+static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
+                           struct ktermios *old)
+{
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+       struct sci_port *s = to_sci_port(port);
+#endif
+       unsigned int status, baud, smr_val, max_baud;
+       int t = -1;
+       u16 scfcr = 0;
+
+       /*
+        * earlyprintk comes here early on with port->uartclk set to zero.
+        * the clock framework is not up and running at this point so here
+        * we assume that 115200 is the maximum baud rate. please note that
+        * the baud rate is not programmed during earlyprintk - it is assumed
+        * that the previous boot loader has enabled required clocks and
+        * setup the baud rate generator hardware for us already.
+        */
+       max_baud = port->uartclk ? port->uartclk / 16 : 115200;
+
+       baud = uart_get_baud_rate(port, termios, old, 0, max_baud);
+       if (likely(baud && port->uartclk))
+               t = SCBRR_VALUE(baud, port->uartclk);
+
+       do {
+               status = sci_in(port, SCxSR);
+       } while (!(status & SCxSR_TEND(port)));
+
+       sci_out(port, SCSCR, 0x00);     /* TE=0, RE=0, CKE1=0 */
+
+       if (port->type != PORT_SCI)
+               sci_out(port, SCFCR, scfcr | SCFCR_RFRST | SCFCR_TFRST);
+
+       smr_val = sci_in(port, SCSMR) & 3;
+       if ((termios->c_cflag & CSIZE) == CS7)
+               smr_val |= 0x40;
+       if (termios->c_cflag & PARENB)
+               smr_val |= 0x20;
+       if (termios->c_cflag & PARODD)
+               smr_val |= 0x30;
+       if (termios->c_cflag & CSTOPB)
+               smr_val |= 0x08;
+
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       sci_out(port, SCSMR, smr_val);
+
+       dev_dbg(port->dev, "%s: SMR %x, t %x, SCSCR %x\n", __func__, smr_val, t,
+               SCSCR_INIT(port));
+
+       if (t > 0) {
+               if (t >= 256) {
+                       sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1);
+                       t >>= 2;
+               } else
+                       sci_out(port, SCSMR, sci_in(port, SCSMR) & ~3);
+
+               sci_out(port, SCBRR, t);
+               udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */
+       }
+
+       sci_init_pins(port, termios->c_cflag);
+       sci_out(port, SCFCR, scfcr | ((termios->c_cflag & CRTSCTS) ? SCFCR_MCE : 0));
+
+       sci_out(port, SCSCR, SCSCR_INIT(port));
+
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+       /*
+        * Calculate delay for 1.5 DMA buffers: see
+        * drivers/serial/serial_core.c::uart_update_timeout(). With 10 bits
+        * (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above function
+        * calculates 1 jiffie for the data plus 5 jiffies for the "slop(e)."
+        * Then below we calculate 3 jiffies (12ms) for 1.5 DMA buffers (3 FIFO
+        * sizes), but it has been found out experimentally, that this is not
+        * enough: the driver too often needlessly runs on a DMA timeout. 20ms
+        * as a minimum seem to work perfectly.
+        */
+       if (s->chan_rx) {
+               s->rx_timeout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 /
+                       port->fifosize / 2;
+               dev_dbg(port->dev,
+                       "DMA Rx t-out %ums, tty t-out %u jiffies\n",
+                       s->rx_timeout * 1000 / HZ, port->timeout);
+               if (s->rx_timeout < msecs_to_jiffies(20))
+                       s->rx_timeout = msecs_to_jiffies(20);
+       }
+#endif
+
+       if ((termios->c_cflag & CREAD) != 0)
+               sci_start_rx(port);
+}
+
+static const char *sci_type(struct uart_port *port)
+{
+       switch (port->type) {
+       case PORT_IRDA:
+               return "irda";
+       case PORT_SCI:
+               return "sci";
+       case PORT_SCIF:
+               return "scif";
+       case PORT_SCIFA:
+               return "scifa";
+       case PORT_SCIFB:
+               return "scifb";
+       }
+
+       return NULL;
+}
+
+static void sci_release_port(struct uart_port *port)
+{
+       /* Nothing here yet .. */
+}
+
+static int sci_request_port(struct uart_port *port)
+{
+       /* Nothing here yet .. */
+       return 0;
+}
+
+static void sci_config_port(struct uart_port *port, int flags)
+{
+       struct sci_port *s = to_sci_port(port);
+
+       port->type = s->type;
+
+       if (port->membase)
+               return;
+
+       if (port->flags & UPF_IOREMAP) {
+               port->membase = ioremap_nocache(port->mapbase, 0x40);
+
+               if (IS_ERR(port->membase))
+                       dev_err(port->dev, "can't remap port#%d\n", port->line);
+       } else {
+               /*
+                * For the simple (and majority of) cases where we don't
+                * need to do any remapping, just cast the cookie
+                * directly.
+                */
+               port->membase = (void __iomem *)port->mapbase;
+       }
+}
+
+static int sci_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       struct sci_port *s = to_sci_port(port);
+
+       if (ser->irq != s->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs)
+               return -EINVAL;
+       if (ser->baud_base < 2400)
+               /* No paper tape reader for Mitch.. */
+               return -EINVAL;
+
+       return 0;
+}
+
+static struct uart_ops sci_uart_ops = {
+       .tx_empty       = sci_tx_empty,
+       .set_mctrl      = sci_set_mctrl,
+       .get_mctrl      = sci_get_mctrl,
+       .start_tx       = sci_start_tx,
+       .stop_tx        = sci_stop_tx,
+       .stop_rx        = sci_stop_rx,
+       .enable_ms      = sci_enable_ms,
+       .break_ctl      = sci_break_ctl,
+       .startup        = sci_startup,
+       .shutdown       = sci_shutdown,
+       .set_termios    = sci_set_termios,
+       .type           = sci_type,
+       .release_port   = sci_release_port,
+       .request_port   = sci_request_port,
+       .config_port    = sci_config_port,
+       .verify_port    = sci_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char  = sci_poll_get_char,
+       .poll_put_char  = sci_poll_put_char,
+#endif
+};
+
+static int __devinit sci_init_single(struct platform_device *dev,
+                                    struct sci_port *sci_port,
+                                    unsigned int index,
+                                    struct plat_sci_port *p)
+{
+       struct uart_port *port = &sci_port->port;
+
+       port->ops       = &sci_uart_ops;
+       port->iotype    = UPIO_MEM;
+       port->line      = index;
+
+       switch (p->type) {
+       case PORT_SCIFB:
+               port->fifosize = 256;
+               break;
+       case PORT_SCIFA:
+               port->fifosize = 64;
+               break;
+       case PORT_SCIF:
+               port->fifosize = 16;
+               break;
+       default:
+               port->fifosize = 1;
+               break;
+       }
+
+       if (dev) {
+               sci_port->iclk = clk_get(&dev->dev, "sci_ick");
+               if (IS_ERR(sci_port->iclk)) {
+                       sci_port->iclk = clk_get(&dev->dev, "peripheral_clk");
+                       if (IS_ERR(sci_port->iclk)) {
+                               dev_err(&dev->dev, "can't get iclk\n");
+                               return PTR_ERR(sci_port->iclk);
+                       }
+               }
+
+               /*
+                * The function clock is optional, ignore it if we can't
+                * find it.
+                */
+               sci_port->fclk = clk_get(&dev->dev, "sci_fck");
+               if (IS_ERR(sci_port->fclk))
+                       sci_port->fclk = NULL;
+
+               sci_port->enable = sci_clk_enable;
+               sci_port->disable = sci_clk_disable;
+               port->dev = &dev->dev;
+       }
+
+       sci_port->break_timer.data = (unsigned long)sci_port;
+       sci_port->break_timer.function = sci_break_timer;
+       init_timer(&sci_port->break_timer);
+
+       port->mapbase   = p->mapbase;
+       port->membase   = p->membase;
+
+       port->irq       = p->irqs[SCIx_TXI_IRQ];
+       port->flags     = p->flags;
+       sci_port->type  = port->type = p->type;
+
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+       sci_port->dma_dev       = p->dma_dev;
+       sci_port->slave_tx      = p->dma_slave_tx;
+       sci_port->slave_rx      = p->dma_slave_rx;
+
+       dev_dbg(port->dev, "%s: DMA device %p, tx %d, rx %d\n", __func__,
+               p->dma_dev, p->dma_slave_tx, p->dma_slave_rx);
+#endif
+
+       memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs));
+       return 0;
+}
+
+#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
+static struct tty_driver *serial_console_device(struct console *co, int *index)
+{
+       struct uart_driver *p = &sci_uart_driver;
+       *index = co->index;
+       return p->tty_driver;
+}
+
+static void serial_console_putchar(struct uart_port *port, int ch)
+{
+       sci_poll_put_char(port, ch);
+}
+
+/*
+ *     Print a string to the serial port trying not to disturb
+ *     any possible real use of the port...
+ */
+static void serial_console_write(struct console *co, const char *s,
+                                unsigned count)
+{
+       struct uart_port *port = co->data;
+       struct sci_port *sci_port = to_sci_port(port);
+       unsigned short bits;
+
+       if (sci_port->enable)
+               sci_port->enable(port);
+
+       uart_console_write(port, s, count, serial_console_putchar);
+
+       /* wait until fifo is empty and last bit has been transmitted */
+       bits = SCxSR_TDxE(port) | SCxSR_TEND(port);
+       while ((sci_in(port, SCxSR) & bits) != bits)
+               cpu_relax();
+
+       if (sci_port->disable)
+               sci_port->disable(port);
+}
+
+static int __devinit serial_console_setup(struct console *co, char *options)
+{
+       struct sci_port *sci_port;
+       struct uart_port *port;
+       int baud = 115200;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+       int ret;
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index >= SCI_NPORTS)
+               co->index = 0;
+
+       if (co->data) {
+               port = co->data;
+               sci_port = to_sci_port(port);
+       } else {
+               sci_port = &sci_ports[co->index];
+               port = &sci_port->port;
+               co->data = port;
+       }
+
+       /*
+        * Also need to check port->type, we don't actually have any
+        * UPIO_PORT ports, but uart_report_port() handily misreports
+        * it anyways if we don't have a port available by the time this is
+        * called.
+        */
+       if (!port->type)
+               return -ENODEV;
+
+       sci_config_port(port, 0);
+
+       if (sci_port->enable)
+               sci_port->enable(port);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       ret = uart_set_options(port, co, baud, parity, bits, flow);
+#if defined(__H8300H__) || defined(__H8300S__)
+       /* disable rx interrupt */
+       if (ret == 0)
+               sci_stop_rx(port);
+#endif
+       /* TODO: disable clock */
+       return ret;
+}
+
+static struct console serial_console = {
+       .name           = "ttySC",
+       .device         = serial_console_device,
+       .write          = serial_console_write,
+       .setup          = serial_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+};
+
+static int __init sci_console_init(void)
+{
+       register_console(&serial_console);
+       return 0;
+}
+console_initcall(sci_console_init);
+
+static struct sci_port early_serial_port;
+static struct console early_serial_console = {
+       .name           = "early_ttySC",
+       .write          = serial_console_write,
+       .flags          = CON_PRINTBUFFER,
+};
+static char early_serial_buf[32];
+
+#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
+
+#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
+#define SCI_CONSOLE    (&serial_console)
+#else
+#define SCI_CONSOLE    0
+#endif
+
+static char banner[] __initdata =
+       KERN_INFO "SuperH SCI(F) driver initialized\n";
+
+static struct uart_driver sci_uart_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "sci",
+       .dev_name       = "ttySC",
+       .major          = SCI_MAJOR,
+       .minor          = SCI_MINOR_START,
+       .nr             = SCI_NPORTS,
+       .cons           = SCI_CONSOLE,
+};
+
+
+static int sci_remove(struct platform_device *dev)
+{
+       struct sh_sci_priv *priv = platform_get_drvdata(dev);
+       struct sci_port *p;
+       unsigned long flags;
+
+       cpufreq_unregister_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER);
+
+       spin_lock_irqsave(&priv->lock, flags);
+       list_for_each_entry(p, &priv->ports, node) {
+               uart_remove_one_port(&sci_uart_driver, &p->port);
+               clk_put(p->iclk);
+               clk_put(p->fclk);
+       }
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       kfree(priv);
+       return 0;
+}
+
+static int __devinit sci_probe_single(struct platform_device *dev,
+                                     unsigned int index,
+                                     struct plat_sci_port *p,
+                                     struct sci_port *sciport)
+{
+       struct sh_sci_priv *priv = platform_get_drvdata(dev);
+       unsigned long flags;
+       int ret;
+
+       /* Sanity check */
+       if (unlikely(index >= SCI_NPORTS)) {
+               dev_notice(&dev->dev, "Attempting to register port "
+                          "%d when only %d are available.\n",
+                          index+1, SCI_NPORTS);
+               dev_notice(&dev->dev, "Consider bumping "
+                          "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n");
+               return 0;
+       }
+
+       ret = sci_init_single(dev, sciport, index, p);
+       if (ret)
+               return ret;
+
+       ret = uart_add_one_port(&sci_uart_driver, &sciport->port);
+       if (ret)
+               return ret;
+
+       INIT_LIST_HEAD(&sciport->node);
+
+       spin_lock_irqsave(&priv->lock, flags);
+       list_add(&sciport->node, &priv->ports);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
+/*
+ * Register a set of serial devices attached to a platform device.  The
+ * list is terminated with a zero flags entry, which means we expect
+ * all entries to have at least UPF_BOOT_AUTOCONF set. Platforms that need
+ * remapping (such as sh64) should also set UPF_IOREMAP.
+ */
+static int __devinit sci_probe(struct platform_device *dev)
+{
+       struct plat_sci_port *p = dev->dev.platform_data;
+       struct sh_sci_priv *priv;
+       int i, ret = -EINVAL;
+
+#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
+       if (is_early_platform_device(dev)) {
+               if (dev->id == -1)
+                       return -ENOTSUPP;
+               early_serial_console.index = dev->id;
+               early_serial_console.data = &early_serial_port.port;
+               sci_init_single(NULL, &early_serial_port, dev->id, p);
+               serial_console_setup(&early_serial_console, early_serial_buf);
+               if (!strstr(early_serial_buf, "keep"))
+                       early_serial_console.flags |= CON_BOOT;
+               register_console(&early_serial_console);
+               return 0;
+       }
+#endif
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&priv->ports);
+       spin_lock_init(&priv->lock);
+       platform_set_drvdata(dev, priv);
+
+       priv->clk_nb.notifier_call = sci_notifier;
+       cpufreq_register_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER);
+
+       if (dev->id != -1) {
+               ret = sci_probe_single(dev, dev->id, p, &sci_ports[dev->id]);
+               if (ret)
+                       goto err_unreg;
+       } else {
+               for (i = 0; p && p->flags != 0; p++, i++) {
+                       ret = sci_probe_single(dev, i, p, &sci_ports[i]);
+                       if (ret)
+                               goto err_unreg;
+               }
+       }
+
+#ifdef CONFIG_SH_STANDARD_BIOS
+       sh_bios_gdb_detach();
+#endif
+
+       return 0;
+
+err_unreg:
+       sci_remove(dev);
+       return ret;
+}
+
+static int sci_suspend(struct device *dev)
+{
+       struct sh_sci_priv *priv = dev_get_drvdata(dev);
+       struct sci_port *p;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       list_for_each_entry(p, &priv->ports, node)
+               uart_suspend_port(&sci_uart_driver, &p->port);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
+static int sci_resume(struct device *dev)
+{
+       struct sh_sci_priv *priv = dev_get_drvdata(dev);
+       struct sci_port *p;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       list_for_each_entry(p, &priv->ports, node)
+               uart_resume_port(&sci_uart_driver, &p->port);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
+static const struct dev_pm_ops sci_dev_pm_ops = {
+       .suspend        = sci_suspend,
+       .resume         = sci_resume,
+};
+
+static struct platform_driver sci_driver = {
+       .probe          = sci_probe,
+       .remove         = sci_remove,
+       .driver         = {
+               .name   = "sh-sci",
+               .owner  = THIS_MODULE,
+               .pm     = &sci_dev_pm_ops,
+       },
+};
+
+static int __init sci_init(void)
+{
+       int ret;
+
+       printk(banner);
+
+       ret = uart_register_driver(&sci_uart_driver);
+       if (likely(ret == 0)) {
+               ret = platform_driver_register(&sci_driver);
+               if (unlikely(ret))
+                       uart_unregister_driver(&sci_uart_driver);
+       }
+
+       return ret;
+}
+
+static void __exit sci_exit(void)
+{
+       platform_driver_unregister(&sci_driver);
+       uart_unregister_driver(&sci_uart_driver);
+}
+
+#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
+early_platform_init_buffer("earlyprintk", &sci_driver,
+                          early_serial_buf, ARRAY_SIZE(early_serial_buf));
+#endif
+module_init(sci_init);
+module_exit(sci_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:sh-sci");
diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h
new file mode 100644 (file)
index 0000000..4bc614e
--- /dev/null
@@ -0,0 +1,660 @@
+#include <linux/serial_core.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
+#include <asm/regs306x.h>
+#endif
+#if defined(CONFIG_H8S2678)
+#include <asm/regs267x.h>
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7708) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7709)
+# define SCPCR  0xA4000116 /* 16 bit SCI and SCIF */
+# define SCPDR  0xA4000136 /* 8  bit SCI and SCIF */
+# define SCSCR_INIT(port)          0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
+# define SCIF0         0xA4400000
+# define SCIF2         0xA4410000
+# define SCSMR_Ir      0xA44A0000
+# define IRDA_SCIF     SCIF0
+# define SCPCR 0xA4000116
+# define SCPDR 0xA4000136
+
+/* Set the clock source,
+ * SCIF2 (0xA4410000) -> External clock, SCK pin used as clock input
+ * SCIF0 (0xA4400000) -> Internal clock, SCK pin as serial clock output
+ */
+# define SCSCR_INIT(port) (port->mapbase == SCIF2) ? 0xF3 : 0xF0
+#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+      defined(CONFIG_ARCH_SH73A0) || \
+      defined(CONFIG_ARCH_SH7367) || \
+      defined(CONFIG_ARCH_SH7377) || \
+      defined(CONFIG_ARCH_SH7372)
+# define SCSCR_INIT(port)  0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */
+# define PORT_PTCR        0xA405011EUL
+# define PORT_PVCR        0xA4050122UL
+# define SCIF_ORER        0x0200   /* overrun error bit */
+#elif defined(CONFIG_SH_RTS7751R2D)
+# define SCSPTR1 0xFFE0001C /* 8 bit SCIF */
+# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
+# define SCIF_ORER 0x0001   /* overrun error bit */
+# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7750)  || \
+      defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7091)  || \
+      defined(CONFIG_CPU_SUBTYPE_SH7751)  || \
+      defined(CONFIG_CPU_SUBTYPE_SH7751R)
+# define SCSPTR1 0xffe0001c /* 8  bit SCI */
+# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
+# define SCIF_ORER 0x0001   /* overrun error bit */
+# define SCSCR_INIT(port) (((port)->type == PORT_SCI) ? \
+       0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \
+       0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ )
+#elif defined(CONFIG_CPU_SUBTYPE_SH7760)
+# define SCSPTR0 0xfe600024 /* 16 bit SCIF */
+# define SCSPTR1 0xfe610024 /* 16 bit SCIF */
+# define SCSPTR2 0xfe620024 /* 16 bit SCIF */
+# define SCIF_ORER 0x0001  /* overrun error bit */
+# define SCSCR_INIT(port)          0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
+# define SCSPTR0 0xA4400000      /* 16 bit SCIF */
+# define SCIF_ORER 0x0001   /* overrun error bit */
+# define PACR 0xa4050100
+# define PBCR 0xa4050102
+# define SCSCR_INIT(port)          0x3B
+#elif defined(CONFIG_CPU_SUBTYPE_SH7343)
+# define SCSPTR0 0xffe00010    /* 16 bit SCIF */
+# define SCSPTR1 0xffe10010    /* 16 bit SCIF */
+# define SCSPTR2 0xffe20010    /* 16 bit SCIF */
+# define SCSPTR3 0xffe30010    /* 16 bit SCIF */
+# define SCSCR_INIT(port) 0x32 /* TIE=0,RIE=0,TE=1,RE=1,REIE=0,CKE=1 */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
+# define PADR                  0xA4050120
+# define PSDR                  0xA405013e
+# define PWDR                  0xA4050166
+# define PSCR                  0xA405011E
+# define SCIF_ORER             0x0001  /* overrun error bit */
+# define SCSCR_INIT(port)      0x0038  /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7366)
+# define SCPDR0                        0xA405013E      /* 16 bit SCIF0 PSDR */
+# define SCSPTR0               SCPDR0
+# define SCIF_ORER             0x0001  /* overrun error bit */
+# define SCSCR_INIT(port)      0x0038  /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7723)
+# define SCSPTR0                0xa4050160
+# define SCSPTR1                0xa405013e
+# define SCSPTR2                0xa4050160
+# define SCSPTR3                0xa405013e
+# define SCSPTR4                0xa4050128
+# define SCSPTR5                0xa4050128
+# define SCIF_ORER              0x0001  /* overrun error bit */
+# define SCSCR_INIT(port)       0x0038  /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7724)
+# define SCIF_ORER              0x0001  /* overrun error bit */
+# define SCSCR_INIT(port) ((port)->type == PORT_SCIFA ? \
+       0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \
+       0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ )
+#elif defined(CONFIG_CPU_SUBTYPE_SH4_202)
+# define SCSPTR2 0xffe80020 /* 16 bit SCIF */
+# define SCIF_ORER 0x0001   /* overrun error bit */
+# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+#elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103)
+# define SCIF_BASE_ADDR    0x01030000
+# define SCIF_ADDR_SH5     PHYS_PERIPHERAL_BLOCK+SCIF_BASE_ADDR
+# define SCIF_PTR2_OFFS    0x0000020
+# define SCIF_LSR2_OFFS    0x0000024
+# define SCSPTR2           ((port->mapbase)+SCIF_PTR2_OFFS) /* 16 bit SCIF */
+# define SCLSR2            ((port->mapbase)+SCIF_LSR2_OFFS) /* 16 bit SCIF */
+# define SCSCR_INIT(port)  0x38                /* TIE=0,RIE=0, TE=1,RE=1,REIE=1 */
+#elif defined(CONFIG_H83007) || defined(CONFIG_H83068)
+# define SCSCR_INIT(port)          0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
+# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
+#elif defined(CONFIG_H8S2678)
+# define SCSCR_INIT(port)          0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
+# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7757)
+# define SCSPTR0 0xfe4b0020
+# define SCSPTR1 0xfe4b0020
+# define SCSPTR2 0xfe4b0020
+# define SCIF_ORER 0x0001
+# define SCSCR_INIT(port)      0x38
+# define SCIF_ONLY
+#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
+# define SCSPTR0 0xffe00024 /* 16 bit SCIF */
+# define SCSPTR1 0xffe08024 /* 16 bit SCIF */
+# define SCSPTR2 0xffe10020 /* 16 bit SCIF/IRDA */
+# define SCIF_ORER 0x0001  /* overrun error bit */
+# define SCSCR_INIT(port)      0x38    /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7770)
+# define SCSPTR0 0xff923020 /* 16 bit SCIF */
+# define SCSPTR1 0xff924020 /* 16 bit SCIF */
+# define SCSPTR2 0xff925020 /* 16 bit SCIF */
+# define SCIF_ORER 0x0001  /* overrun error bit */
+# define SCSCR_INIT(port)      0x3c /* TIE=0,RIE=0,TE=1,RE=1,REIE=1,cke=2 */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+# define SCSPTR0       0xffe00024      /* 16 bit SCIF */
+# define SCSPTR1       0xffe10024      /* 16 bit SCIF */
+# define SCIF_ORER     0x0001          /* Overrun error bit */
+
+#if defined(CONFIG_SH_SH2007)
+/* TIE=0,RIE=0,TE=1,RE=1,REIE=1,CKE1=0 */
+# define SCSCR_INIT(port)      0x38
+#else
+/* TIE=0,RIE=0,TE=1,RE=1,REIE=1,CKE1=1 */
+# define SCSCR_INIT(port)      0x3a
+#endif
+
+#elif defined(CONFIG_CPU_SUBTYPE_SH7785) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7786)
+# define SCSPTR0       0xffea0024      /* 16 bit SCIF */
+# define SCSPTR1       0xffeb0024      /* 16 bit SCIF */
+# define SCSPTR2       0xffec0024      /* 16 bit SCIF */
+# define SCSPTR3       0xffed0024      /* 16 bit SCIF */
+# define SCSPTR4       0xffee0024      /* 16 bit SCIF */
+# define SCSPTR5       0xffef0024      /* 16 bit SCIF */
+# define SCIF_ORER     0x0001          /* Overrun error bit */
+# define SCSCR_INIT(port)      0x3a    /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7201) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7203) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7206) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7263)
+# define SCSPTR0 0xfffe8020 /* 16 bit SCIF */
+# define SCSPTR1 0xfffe8820 /* 16 bit SCIF */
+# define SCSPTR2 0xfffe9020 /* 16 bit SCIF */
+# define SCSPTR3 0xfffe9820 /* 16 bit SCIF */
+# if defined(CONFIG_CPU_SUBTYPE_SH7201)
+#  define SCSPTR4 0xfffeA020 /* 16 bit SCIF */
+#  define SCSPTR5 0xfffeA820 /* 16 bit SCIF */
+#  define SCSPTR6 0xfffeB020 /* 16 bit SCIF */
+#  define SCSPTR7 0xfffeB820 /* 16 bit SCIF */
+# endif
+# define SCSCR_INIT(port)      0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7619)
+# define SCSPTR0 0xf8400020 /* 16 bit SCIF */
+# define SCSPTR1 0xf8410020 /* 16 bit SCIF */
+# define SCSPTR2 0xf8420020 /* 16 bit SCIF */
+# define SCIF_ORER 0x0001  /* overrun error bit */
+# define SCSCR_INIT(port)      0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+#elif defined(CONFIG_CPU_SUBTYPE_SHX3)
+# define SCSPTR0 0xffc30020            /* 16 bit SCIF */
+# define SCSPTR1 0xffc40020            /* 16 bit SCIF */
+# define SCSPTR2 0xffc50020            /* 16 bit SCIF */
+# define SCSPTR3 0xffc60020            /* 16 bit SCIF */
+# define SCIF_ORER 0x0001              /* Overrun error bit */
+# define SCSCR_INIT(port)      0x38    /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+#else
+# error CPU subtype not defined
+#endif
+
+/* SCSCR */
+#define SCI_CTRL_FLAGS_TIE  0x80 /* all */
+#define SCI_CTRL_FLAGS_RIE  0x40 /* all */
+#define SCI_CTRL_FLAGS_TE   0x20 /* all */
+#define SCI_CTRL_FLAGS_RE   0x10 /* all */
+#if defined(CONFIG_CPU_SUBTYPE_SH7750)  || \
+    defined(CONFIG_CPU_SUBTYPE_SH7091)  || \
+    defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7722)  || \
+    defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7751)  || \
+    defined(CONFIG_CPU_SUBTYPE_SH7751R) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7763)  || \
+    defined(CONFIG_CPU_SUBTYPE_SH7780)  || \
+    defined(CONFIG_CPU_SUBTYPE_SH7785)  || \
+    defined(CONFIG_CPU_SUBTYPE_SH7786)  || \
+    defined(CONFIG_CPU_SUBTYPE_SHX3)
+#define SCI_CTRL_FLAGS_REIE 0x08 /* 7750 SCIF */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7724)
+#define SCI_CTRL_FLAGS_REIE ((port)->type == PORT_SCIFA ? 0 : 8)
+#else
+#define SCI_CTRL_FLAGS_REIE 0
+#endif
+/*      SCI_CTRL_FLAGS_MPIE 0x08  * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+/*      SCI_CTRL_FLAGS_TEIE 0x04  * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+/*      SCI_CTRL_FLAGS_CKE1 0x02  * all */
+/*      SCI_CTRL_FLAGS_CKE0 0x01  * 7707 SCI/SCIF, 7708 SCI, 7709 SCI/SCIF, 7750 SCI */
+
+/* SCxSR SCI */
+#define SCI_TDRE  0x80 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+#define SCI_RDRF  0x40 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+#define SCI_ORER  0x20 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+#define SCI_FER   0x10 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+#define SCI_PER   0x08 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+#define SCI_TEND  0x04 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+/*      SCI_MPB   0x02  * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+/*      SCI_MPBT  0x01  * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+
+#define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ORER)
+
+/* SCxSR SCIF */
+#define SCIF_ER    0x0080 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
+#define SCIF_TEND  0x0040 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
+#define SCIF_TDFE  0x0020 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
+#define SCIF_BRK   0x0010 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
+#define SCIF_FER   0x0008 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
+#define SCIF_PER   0x0004 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
+#define SCIF_RDF   0x0002 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
+#define SCIF_DR    0x0001 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+    defined(CONFIG_ARCH_SH73A0) || \
+    defined(CONFIG_ARCH_SH7367) || \
+    defined(CONFIG_ARCH_SH7377) || \
+    defined(CONFIG_ARCH_SH7372)
+# define SCIF_ORER    0x0200
+# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK | SCIF_ORER)
+# define SCIF_RFDC_MASK 0x007f
+# define SCIF_TXROOM_MAX 64
+#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
+# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK )
+# define SCIF_RFDC_MASK 0x007f
+# define SCIF_TXROOM_MAX 64
+/* SH7763 SCIF2 support */
+# define SCIF2_RFDC_MASK 0x001f
+# define SCIF2_TXROOM_MAX 16
+#else
+# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK)
+# define SCIF_RFDC_MASK 0x001f
+# define SCIF_TXROOM_MAX 16
+#endif
+
+#ifndef SCIF_ORER
+#define SCIF_ORER      0x0000
+#endif
+
+#define SCxSR_TEND(port)       (((port)->type == PORT_SCI) ? SCI_TEND   : SCIF_TEND)
+#define SCxSR_ERRORS(port)     (((port)->type == PORT_SCI) ? SCI_ERRORS : SCIF_ERRORS)
+#define SCxSR_RDxF(port)       (((port)->type == PORT_SCI) ? SCI_RDRF   : SCIF_RDF)
+#define SCxSR_TDxE(port)       (((port)->type == PORT_SCI) ? SCI_TDRE   : SCIF_TDFE)
+#define SCxSR_FER(port)                (((port)->type == PORT_SCI) ? SCI_FER    : SCIF_FER)
+#define SCxSR_PER(port)                (((port)->type == PORT_SCI) ? SCI_PER    : SCIF_PER)
+#define SCxSR_BRK(port)                (((port)->type == PORT_SCI) ? 0x00       : SCIF_BRK)
+#define SCxSR_ORER(port)       (((port)->type == PORT_SCI) ? SCI_ORER   : SCIF_ORER)
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+    defined(CONFIG_ARCH_SH73A0) || \
+    defined(CONFIG_ARCH_SH7367) || \
+    defined(CONFIG_ARCH_SH7377) || \
+    defined(CONFIG_ARCH_SH7372)
+# define SCxSR_RDxF_CLEAR(port)         (sci_in(port, SCxSR) & 0xfffc)
+# define SCxSR_ERROR_CLEAR(port) (sci_in(port, SCxSR) & 0xfd73)
+# define SCxSR_TDxE_CLEAR(port)         (sci_in(port, SCxSR) & 0xffdf)
+# define SCxSR_BREAK_CLEAR(port) (sci_in(port, SCxSR) & 0xffe3)
+#else
+# define SCxSR_RDxF_CLEAR(port)         (((port)->type == PORT_SCI) ? 0xbc : 0x00fc)
+# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0073)
+# define SCxSR_TDxE_CLEAR(port)  (((port)->type == PORT_SCI) ? 0x78 : 0x00df)
+# define SCxSR_BREAK_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x00e3)
+#endif
+
+/* SCFCR */
+#define SCFCR_RFRST 0x0002
+#define SCFCR_TFRST 0x0004
+#define SCFCR_TCRST 0x4000
+#define SCFCR_MCE   0x0008
+
+#define SCI_MAJOR              204
+#define SCI_MINOR_START                8
+
+/* Generic serial flags */
+#define SCI_RX_THROTTLE                0x0000001
+
+#define SCI_MAGIC 0xbabeface
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at rs interrupt time.
+ */
+#define SCI_EVENT_WRITE_WAKEUP 0
+
+#define SCI_IN(size, offset)                                   \
+  if ((size) == 8) {                                           \
+    return ioread8(port->membase + (offset));                  \
+  } else {                                                     \
+    return ioread16(port->membase + (offset));                 \
+  }
+#define SCI_OUT(size, offset, value)                           \
+  if ((size) == 8) {                                           \
+    iowrite8(value, port->membase + (offset));                 \
+  } else if ((size) == 16) {                                   \
+    iowrite16(value, port->membase + (offset));                        \
+  }
+
+#define CPU_SCIx_FNS(name, sci_offset, sci_size, scif_offset, scif_size)\
+  static inline unsigned int sci_##name##_in(struct uart_port *port)   \
+  {                                                                    \
+    if (port->type == PORT_SCIF || port->type == PORT_SCIFB) {         \
+      SCI_IN(scif_size, scif_offset)                                   \
+    } else {   /* PORT_SCI or PORT_SCIFA */                            \
+      SCI_IN(sci_size, sci_offset);                                    \
+    }                                                                  \
+  }                                                                    \
+  static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
+  {                                                                    \
+    if (port->type == PORT_SCIF || port->type == PORT_SCIFB) {         \
+      SCI_OUT(scif_size, scif_offset, value)                           \
+    } else {   /* PORT_SCI or PORT_SCIFA */                            \
+      SCI_OUT(sci_size, sci_offset, value);                            \
+    }                                                                  \
+  }
+
+#ifdef CONFIG_H8300
+/* h8300 don't have SCIF */
+#define CPU_SCIF_FNS(name)                                             \
+  static inline unsigned int sci_##name##_in(struct uart_port *port)   \
+  {                                                                    \
+    return 0;                                                          \
+  }                                                                    \
+  static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
+  {                                                                    \
+  }
+#else
+#define CPU_SCIF_FNS(name, scif_offset, scif_size)                     \
+  static inline unsigned int sci_##name##_in(struct uart_port *port)   \
+  {                                                                    \
+    SCI_IN(scif_size, scif_offset);                                    \
+  }                                                                    \
+  static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
+  {                                                                    \
+    SCI_OUT(scif_size, scif_offset, value);                            \
+  }
+#endif
+
+#define CPU_SCI_FNS(name, sci_offset, sci_size)                                \
+  static inline unsigned int sci_##name##_in(struct uart_port* port)   \
+  {                                                                    \
+    SCI_IN(sci_size, sci_offset);                                      \
+  }                                                                    \
+  static inline void sci_##name##_out(struct uart_port* port, unsigned int value) \
+  {                                                                    \
+    SCI_OUT(sci_size, sci_offset, value);                              \
+  }
+
+#if defined(CONFIG_CPU_SH3) || \
+    defined(CONFIG_ARCH_SH73A0) || \
+    defined(CONFIG_ARCH_SH7367) || \
+    defined(CONFIG_ARCH_SH7377) || \
+    defined(CONFIG_ARCH_SH7372)
+#if defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
+#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
+                               sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
+                                h8_sci_offset, h8_sci_size) \
+  CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
+#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
+         CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+      defined(CONFIG_ARCH_SH73A0) || \
+      defined(CONFIG_ARCH_SH7367) || \
+      defined(CONFIG_ARCH_SH7377)
+#define SCIF_FNS(name, scif_offset, scif_size) \
+  CPU_SCIF_FNS(name, scif_offset, scif_size)
+#elif defined(CONFIG_ARCH_SH7372)
+#define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scifb_offset, sh4_scifb_size) \
+  CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scifb_offset, sh4_scifb_size)
+#define SCIF_FNS(name, scif_offset, scif_size) \
+  CPU_SCIF_FNS(name, scif_offset, scif_size)
+#else
+#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
+                sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
+                 h8_sci_offset, h8_sci_size) \
+  CPU_SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh3_scif_offset, sh3_scif_size)
+#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
+  CPU_SCIF_FNS(name, sh3_scif_offset, sh3_scif_size)
+#endif
+#elif defined(__H8300H__) || defined(__H8300S__)
+#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
+                sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
+                 h8_sci_offset, h8_sci_size) \
+  CPU_SCI_FNS(name, h8_sci_offset, h8_sci_size)
+#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
+  CPU_SCIF_FNS(name)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\
+      defined(CONFIG_CPU_SUBTYPE_SH7724)
+        #define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size) \
+                CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size)
+        #define SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) \
+                CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
+#else
+#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
+                sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
+                h8_sci_offset, h8_sci_size) \
+  CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
+#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
+  CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+    defined(CONFIG_ARCH_SH73A0) || \
+    defined(CONFIG_ARCH_SH7367) || \
+    defined(CONFIG_ARCH_SH7377)
+
+SCIF_FNS(SCSMR,  0x00, 16)
+SCIF_FNS(SCBRR,  0x04,  8)
+SCIF_FNS(SCSCR,  0x08, 16)
+SCIF_FNS(SCTDSR, 0x0c,  8)
+SCIF_FNS(SCFER,  0x10, 16)
+SCIF_FNS(SCxSR,  0x14, 16)
+SCIF_FNS(SCFCR,  0x18, 16)
+SCIF_FNS(SCFDR,  0x1c, 16)
+SCIF_FNS(SCxTDR, 0x20,  8)
+SCIF_FNS(SCxRDR, 0x24,  8)
+SCIF_FNS(SCLSR,  0x00,  0)
+#elif defined(CONFIG_ARCH_SH7372)
+SCIF_FNS(SCSMR,  0x00, 16)
+SCIF_FNS(SCBRR,  0x04,  8)
+SCIF_FNS(SCSCR,  0x08, 16)
+SCIF_FNS(SCTDSR, 0x0c, 16)
+SCIF_FNS(SCFER,  0x10, 16)
+SCIF_FNS(SCxSR,  0x14, 16)
+SCIF_FNS(SCFCR,  0x18, 16)
+SCIF_FNS(SCFDR,  0x1c, 16)
+SCIF_FNS(SCTFDR, 0x38, 16)
+SCIF_FNS(SCRFDR, 0x3c, 16)
+SCIx_FNS(SCxTDR, 0x20,  8, 0x40,  8)
+SCIx_FNS(SCxRDR, 0x24,  8, 0x60,  8)
+SCIF_FNS(SCLSR,  0x00,  0)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\
+      defined(CONFIG_CPU_SUBTYPE_SH7724)
+SCIx_FNS(SCSMR,  0x00, 16, 0x00, 16)
+SCIx_FNS(SCBRR,  0x04,  8, 0x04,  8)
+SCIx_FNS(SCSCR,  0x08, 16, 0x08, 16)
+SCIx_FNS(SCxTDR, 0x20,  8, 0x0c,  8)
+SCIx_FNS(SCxSR,  0x14, 16, 0x10, 16)
+SCIx_FNS(SCxRDR, 0x24,  8, 0x14,  8)
+SCIx_FNS(SCSPTR, 0,     0,    0,  0)
+SCIF_FNS(SCTDSR, 0x0c,  8)
+SCIF_FNS(SCFER,  0x10, 16)
+SCIF_FNS(SCFCR,  0x18, 16)
+SCIF_FNS(SCFDR,  0x1c, 16)
+SCIF_FNS(SCLSR,  0x24, 16)
+#else
+/*      reg      SCI/SH3   SCI/SH4  SCIF/SH3   SCIF/SH4  SCI/H8*/
+/*      name     off  sz   off  sz   off  sz   off  sz   off  sz*/
+SCIx_FNS(SCSMR,  0x00,  8, 0x00,  8, 0x00,  8, 0x00, 16, 0x00,  8)
+SCIx_FNS(SCBRR,  0x02,  8, 0x04,  8, 0x02,  8, 0x04,  8, 0x01,  8)
+SCIx_FNS(SCSCR,  0x04,  8, 0x08,  8, 0x04,  8, 0x08, 16, 0x02,  8)
+SCIx_FNS(SCxTDR, 0x06,  8, 0x0c,  8, 0x06,  8, 0x0C,  8, 0x03,  8)
+SCIx_FNS(SCxSR,  0x08,  8, 0x10,  8, 0x08, 16, 0x10, 16, 0x04,  8)
+SCIx_FNS(SCxRDR, 0x0a,  8, 0x14,  8, 0x0A,  8, 0x14,  8, 0x05,  8)
+SCIF_FNS(SCFCR,                      0x0c,  8, 0x18, 16)
+#if defined(CONFIG_CPU_SUBTYPE_SH7760) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7785) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7786)
+SCIF_FNS(SCFDR,                             0x0e, 16, 0x1C, 16)
+SCIF_FNS(SCTFDR,                    0x0e, 16, 0x1C, 16)
+SCIF_FNS(SCRFDR,                    0x0e, 16, 0x20, 16)
+SCIF_FNS(SCSPTR,                       0,  0, 0x24, 16)
+SCIF_FNS(SCLSR,                                0,  0, 0x28, 16)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
+SCIF_FNS(SCFDR,                                0,  0, 0x1C, 16)
+SCIF_FNS(SCSPTR2,                      0,  0, 0x20, 16)
+SCIF_FNS(SCLSR2,                       0,  0, 0x24, 16)
+SCIF_FNS(SCTFDR,                    0x0e, 16, 0x1C, 16)
+SCIF_FNS(SCRFDR,                    0x0e, 16, 0x20, 16)
+SCIF_FNS(SCSPTR,                       0,  0, 0x24, 16)
+SCIF_FNS(SCLSR,                                0,  0, 0x28, 16)
+#else
+SCIF_FNS(SCFDR,                      0x0e, 16, 0x1C, 16)
+#if defined(CONFIG_CPU_SUBTYPE_SH7722)
+SCIF_FNS(SCSPTR,                        0,  0, 0, 0)
+#else
+SCIF_FNS(SCSPTR,                        0,  0, 0x20, 16)
+#endif
+SCIF_FNS(SCLSR,                         0,  0, 0x24, 16)
+#endif
+#endif
+#define sci_in(port, reg) sci_##reg##_in(port)
+#define sci_out(port, reg, value) sci_##reg##_out(port, value)
+
+/* H8/300 series SCI pins assignment */
+#if defined(__H8300H__) || defined(__H8300S__)
+static const struct __attribute__((packed)) {
+       int port;             /* GPIO port no */
+       unsigned short rx,tx; /* GPIO bit no */
+} h8300_sci_pins[] = {
+#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
+       {    /* SCI0 */
+               .port = H8300_GPIO_P9,
+               .rx   = H8300_GPIO_B2,
+               .tx   = H8300_GPIO_B0,
+       },
+       {    /* SCI1 */
+               .port = H8300_GPIO_P9,
+               .rx   = H8300_GPIO_B3,
+               .tx   = H8300_GPIO_B1,
+       },
+       {    /* SCI2 */
+               .port = H8300_GPIO_PB,
+               .rx   = H8300_GPIO_B7,
+               .tx   = H8300_GPIO_B6,
+       }
+#elif defined(CONFIG_H8S2678)
+       {    /* SCI0 */
+               .port = H8300_GPIO_P3,
+               .rx   = H8300_GPIO_B2,
+               .tx   = H8300_GPIO_B0,
+       },
+       {    /* SCI1 */
+               .port = H8300_GPIO_P3,
+               .rx   = H8300_GPIO_B3,
+               .tx   = H8300_GPIO_B1,
+       },
+       {    /* SCI2 */
+               .port = H8300_GPIO_P5,
+               .rx   = H8300_GPIO_B1,
+               .tx   = H8300_GPIO_B0,
+       }
+#endif
+};
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7708) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7709)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+       if (port->mapbase == 0xfffffe80)
+               return __raw_readb(SCPDR)&0x01 ? 1 : 0; /* SCI */
+       return 1;
+}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7750)  || \
+      defined(CONFIG_CPU_SUBTYPE_SH7751)  || \
+      defined(CONFIG_CPU_SUBTYPE_SH7751R) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7091)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+       if (port->mapbase == 0xffe00000)
+               return __raw_readb(SCSPTR1)&0x01 ? 1 : 0; /* SCI */
+       return 1;
+}
+#elif defined(__H8300H__) || defined(__H8300S__)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+       int ch = (port->mapbase - SMR0) >> 3;
+       return (H8300_SCI_DR(ch) & h8300_sci_pins[ch].rx) ? 1 : 0;
+}
+#else /* default case for non-SCI processors */
+static inline int sci_rxd_in(struct uart_port *port)
+{
+       return 1;
+}
+#endif
+
+/*
+ * Values for the BitRate Register (SCBRR)
+ *
+ * The values are actually divisors for a frequency which can
+ * be internal to the SH3 (14.7456MHz) or derived from an external
+ * clock source.  This driver assumes the internal clock is used;
+ * to support using an external clock source, config options or
+ * possibly command-line options would need to be added.
+ *
+ * Also, to support speeds below 2400 (why?) the lower 2 bits of
+ * the SCSMR register would also need to be set to non-zero values.
+ *
+ * -- Greg Banks 27Feb2000
+ *
+ * Answer: The SCBRR register is only eight bits, and the value in
+ * it gets larger with lower baud rates. At around 2400 (depending on
+ * the peripherial module clock) you run out of bits. However the
+ * lower two bits of SCSMR allow the module clock to be divided down,
+ * scaling the value which is needed in SCBRR.
+ *
+ * -- Stuart Menefy - 23 May 2000
+ *
+ * I meant, why would anyone bother with bitrates below 2400.
+ *
+ * -- Greg Banks - 7Jul2000
+ *
+ * You "speedist"!  How will I use my 110bps ASR-33 teletype with paper
+ * tape reader as a console!
+ *
+ * -- Mitch Davis - 15 Jul 2000
+ */
+
+#if (defined(CONFIG_CPU_SUBTYPE_SH7780)  || \
+     defined(CONFIG_CPU_SUBTYPE_SH7785)  || \
+     defined(CONFIG_CPU_SUBTYPE_SH7786)) && \
+    !defined(CONFIG_SH_SH2007)
+#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+      defined(CONFIG_ARCH_SH73A0) || \
+      defined(CONFIG_ARCH_SH7367) || \
+      defined(CONFIG_ARCH_SH7377) || \
+      defined(CONFIG_ARCH_SH7372)
+#define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\
+      defined(CONFIG_CPU_SUBTYPE_SH7724)
+static inline int scbrr_calc(struct uart_port *port, int bps, int clk)
+{
+       if (port->type == PORT_SCIF)
+               return (clk+16*bps)/(32*bps)-1;
+       else
+               return ((clk*2)+16*bps)/(16*bps)-1;
+}
+#define SCBRR_VALUE(bps, clk) scbrr_calc(port, bps, clk)
+#elif defined(__H8300H__) || defined(__H8300S__)
+#define SCBRR_VALUE(bps, clk) (((clk*1000/32)/bps)-1)
+#else /* Generic SH */
+#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(32*bps)-1)
+#endif
diff --git a/drivers/tty/serial/sn_console.c b/drivers/tty/serial/sn_console.c
new file mode 100644 (file)
index 0000000..cff9a30
--- /dev/null
@@ -0,0 +1,1085 @@
+/*
+ * C-Brick Serial Port (and console) driver for SGI Altix machines.
+ *
+ * This driver is NOT suitable for talking to the l1-controller for
+ * anything other than 'console activities' --- please use the l1
+ * driver for that.
+ *
+ *
+ * Copyright (c) 2004-2006 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information:  Silicon Graphics, Inc., 1500 Crittenden Lane,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
+ */
+
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/module.h>
+#include <linux/sysrq.h>
+#include <linux/circ_buf.h>
+#include <linux/serial_reg.h>
+#include <linux/delay.h> /* for mdelay */
+#include <linux/miscdevice.h>
+#include <linux/serial_core.h>
+
+#include <asm/io.h>
+#include <asm/sn/simulator.h>
+#include <asm/sn/sn_sal.h>
+
+/* number of characters we can transmit to the SAL console at a time */
+#define SN_SAL_MAX_CHARS 120
+
+/* 64K, when we're asynch, it must be at least printk's LOG_BUF_LEN to
+ * avoid losing chars, (always has to be a power of 2) */
+#define SN_SAL_BUFFER_SIZE (64 * (1 << 10))
+
+#define SN_SAL_UART_FIFO_DEPTH 16
+#define SN_SAL_UART_FIFO_SPEED_CPS (9600/10)
+
+/* sn_transmit_chars() calling args */
+#define TRANSMIT_BUFFERED      0
+#define TRANSMIT_RAW           1
+
+/* To use dynamic numbers only and not use the assigned major and minor,
+ * define the following.. */
+                                 /* #define USE_DYNAMIC_MINOR 1 *//* use dynamic minor number */
+#define USE_DYNAMIC_MINOR 0    /* Don't rely on misc_register dynamic minor */
+
+/* Device name we're using */
+#define DEVICE_NAME "ttySG"
+#define DEVICE_NAME_DYNAMIC "ttySG0"   /* need full name for misc_register */
+/* The major/minor we are using, ignored for USE_DYNAMIC_MINOR */
+#define DEVICE_MAJOR 204
+#define DEVICE_MINOR 40
+
+#ifdef CONFIG_MAGIC_SYSRQ
+static char sysrq_serial_str[] = "\eSYS";
+static char *sysrq_serial_ptr = sysrq_serial_str;
+static unsigned long sysrq_requested;
+#endif /* CONFIG_MAGIC_SYSRQ */
+
+/*
+ * Port definition - this kinda drives it all
+ */
+struct sn_cons_port {
+       struct timer_list sc_timer;
+       struct uart_port sc_port;
+       struct sn_sal_ops {
+               int (*sal_puts_raw) (const char *s, int len);
+               int (*sal_puts) (const char *s, int len);
+               int (*sal_getc) (void);
+               int (*sal_input_pending) (void);
+               void (*sal_wakeup_transmit) (struct sn_cons_port *, int);
+       } *sc_ops;
+       unsigned long sc_interrupt_timeout;
+       int sc_is_asynch;
+};
+
+static struct sn_cons_port sal_console_port;
+static int sn_process_input;
+
+/* Only used if USE_DYNAMIC_MINOR is set to 1 */
+static struct miscdevice misc; /* used with misc_register for dynamic */
+
+extern void early_sn_setup(void);
+
+#undef DEBUG
+#ifdef DEBUG
+static int sn_debug_printf(const char *fmt, ...);
+#define DPRINTF(x...) sn_debug_printf(x)
+#else
+#define DPRINTF(x...) do { } while (0)
+#endif
+
+/* Prototypes */
+static int snt_hw_puts_raw(const char *, int);
+static int snt_hw_puts_buffered(const char *, int);
+static int snt_poll_getc(void);
+static int snt_poll_input_pending(void);
+static int snt_intr_getc(void);
+static int snt_intr_input_pending(void);
+static void sn_transmit_chars(struct sn_cons_port *, int);
+
+/* A table for polling:
+ */
+static struct sn_sal_ops poll_ops = {
+       .sal_puts_raw = snt_hw_puts_raw,
+       .sal_puts = snt_hw_puts_raw,
+       .sal_getc = snt_poll_getc,
+       .sal_input_pending = snt_poll_input_pending
+};
+
+/* A table for interrupts enabled */
+static struct sn_sal_ops intr_ops = {
+       .sal_puts_raw = snt_hw_puts_raw,
+       .sal_puts = snt_hw_puts_buffered,
+       .sal_getc = snt_intr_getc,
+       .sal_input_pending = snt_intr_input_pending,
+       .sal_wakeup_transmit = sn_transmit_chars
+};
+
+/* the console does output in two distinctly different ways:
+ * synchronous (raw) and asynchronous (buffered).  initally, early_printk
+ * does synchronous output.  any data written goes directly to the SAL
+ * to be output (incidentally, it is internally buffered by the SAL)
+ * after interrupts and timers are initialized and available for use,
+ * the console init code switches to asynchronous output.  this is
+ * also the earliest opportunity to begin polling for console input.
+ * after console initialization, console output and tty (serial port)
+ * output is buffered and sent to the SAL asynchronously (either by
+ * timer callback or by UART interrupt) */
+
+/* routines for running the console in polling mode */
+
+/**
+ * snt_poll_getc - Get a character from the console in polling mode
+ *
+ */
+static int snt_poll_getc(void)
+{
+       int ch;
+
+       ia64_sn_console_getc(&ch);
+       return ch;
+}
+
+/**
+ * snt_poll_input_pending - Check if any input is waiting - polling mode.
+ *
+ */
+static int snt_poll_input_pending(void)
+{
+       int status, input;
+
+       status = ia64_sn_console_check(&input);
+       return !status && input;
+}
+
+/* routines for an interrupt driven console (normal) */
+
+/**
+ * snt_intr_getc - Get a character from the console, interrupt mode
+ *
+ */
+static int snt_intr_getc(void)
+{
+       return ia64_sn_console_readc();
+}
+
+/**
+ * snt_intr_input_pending - Check if input is pending, interrupt mode
+ *
+ */
+static int snt_intr_input_pending(void)
+{
+       return ia64_sn_console_intr_status() & SAL_CONSOLE_INTR_RECV;
+}
+
+/* these functions are polled and interrupt */
+
+/**
+ * snt_hw_puts_raw - Send raw string to the console, polled or interrupt mode
+ * @s: String
+ * @len: Length
+ *
+ */
+static int snt_hw_puts_raw(const char *s, int len)
+{
+       /* this will call the PROM and not return until this is done */
+       return ia64_sn_console_putb(s, len);
+}
+
+/**
+ * snt_hw_puts_buffered - Send string to console, polled or interrupt mode
+ * @s: String
+ * @len: Length
+ *
+ */
+static int snt_hw_puts_buffered(const char *s, int len)
+{
+       /* queue data to the PROM */
+       return ia64_sn_console_xmit_chars((char *)s, len);
+}
+
+/* uart interface structs
+ * These functions are associated with the uart_port that the serial core
+ * infrastructure calls.
+ *
+ * Note: Due to how the console works, many routines are no-ops.
+ */
+
+/**
+ * snp_type - What type of console are we?
+ * @port: Port to operate with (we ignore since we only have one port)
+ *
+ */
+static const char *snp_type(struct uart_port *port)
+{
+       return ("SGI SN L1");
+}
+
+/**
+ * snp_tx_empty - Is the transmitter empty?  We pretend we're always empty
+ * @port: Port to operate on (we ignore since we only have one port)
+ *
+ */
+static unsigned int snp_tx_empty(struct uart_port *port)
+{
+       return 1;
+}
+
+/**
+ * snp_stop_tx - stop the transmitter - no-op for us
+ * @port: Port to operat eon - we ignore - no-op function
+ *
+ */
+static void snp_stop_tx(struct uart_port *port)
+{
+}
+
+/**
+ * snp_release_port - Free i/o and resources for port - no-op for us
+ * @port: Port to operate on - we ignore - no-op function
+ *
+ */
+static void snp_release_port(struct uart_port *port)
+{
+}
+
+/**
+ * snp_enable_ms - Force modem status interrupts on - no-op for us
+ * @port: Port to operate on - we ignore - no-op function
+ *
+ */
+static void snp_enable_ms(struct uart_port *port)
+{
+}
+
+/**
+ * snp_shutdown - shut down the port - free irq and disable - no-op for us
+ * @port: Port to shut down - we ignore
+ *
+ */
+static void snp_shutdown(struct uart_port *port)
+{
+}
+
+/**
+ * snp_set_mctrl - set control lines (dtr, rts, etc) - no-op for our console
+ * @port: Port to operate on - we ignore
+ * @mctrl: Lines to set/unset - we ignore
+ *
+ */
+static void snp_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+/**
+ * snp_get_mctrl - get contorl line info, we just return a static value
+ * @port: port to operate on - we only have one port so we ignore this
+ *
+ */
+static unsigned int snp_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_CAR | TIOCM_RNG | TIOCM_DSR | TIOCM_CTS;
+}
+
+/**
+ * snp_stop_rx - Stop the receiver - we ignor ethis
+ * @port: Port to operate on - we ignore
+ *
+ */
+static void snp_stop_rx(struct uart_port *port)
+{
+}
+
+/**
+ * snp_start_tx - Start transmitter
+ * @port: Port to operate on
+ *
+ */
+static void snp_start_tx(struct uart_port *port)
+{
+       if (sal_console_port.sc_ops->sal_wakeup_transmit)
+               sal_console_port.sc_ops->sal_wakeup_transmit(&sal_console_port,
+                                                            TRANSMIT_BUFFERED);
+
+}
+
+/**
+ * snp_break_ctl - handle breaks - ignored by us
+ * @port: Port to operate on
+ * @break_state: Break state
+ *
+ */
+static void snp_break_ctl(struct uart_port *port, int break_state)
+{
+}
+
+/**
+ * snp_startup - Start up the serial port - always return 0 (We're always on)
+ * @port: Port to operate on
+ *
+ */
+static int snp_startup(struct uart_port *port)
+{
+       return 0;
+}
+
+/**
+ * snp_set_termios - set termios stuff - we ignore these
+ * @port: port to operate on
+ * @termios: New settings
+ * @termios: Old
+ *
+ */
+static void
+snp_set_termios(struct uart_port *port, struct ktermios *termios,
+               struct ktermios *old)
+{
+}
+
+/**
+ * snp_request_port - allocate resources for port - ignored by us
+ * @port: port to operate on
+ *
+ */
+static int snp_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+/**
+ * snp_config_port - allocate resources, set up - we ignore,  we're always on
+ * @port: Port to operate on
+ * @flags: flags used for port setup
+ *
+ */
+static void snp_config_port(struct uart_port *port, int flags)
+{
+}
+
+/* Associate the uart functions above - given to serial core */
+
+static struct uart_ops sn_console_ops = {
+       .tx_empty = snp_tx_empty,
+       .set_mctrl = snp_set_mctrl,
+       .get_mctrl = snp_get_mctrl,
+       .stop_tx = snp_stop_tx,
+       .start_tx = snp_start_tx,
+       .stop_rx = snp_stop_rx,
+       .enable_ms = snp_enable_ms,
+       .break_ctl = snp_break_ctl,
+       .startup = snp_startup,
+       .shutdown = snp_shutdown,
+       .set_termios = snp_set_termios,
+       .pm = NULL,
+       .type = snp_type,
+       .release_port = snp_release_port,
+       .request_port = snp_request_port,
+       .config_port = snp_config_port,
+       .verify_port = NULL,
+};
+
+/* End of uart struct functions and defines */
+
+#ifdef DEBUG
+
+/**
+ * sn_debug_printf - close to hardware debugging printf
+ * @fmt: printf format
+ *
+ * This is as "close to the metal" as we can get, used when the driver
+ * itself may be broken.
+ *
+ */
+static int sn_debug_printf(const char *fmt, ...)
+{
+       static char printk_buf[1024];
+       int printed_len;
+       va_list args;
+
+       va_start(args, fmt);
+       printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
+
+       if (!sal_console_port.sc_ops) {
+               sal_console_port.sc_ops = &poll_ops;
+               early_sn_setup();
+       }
+       sal_console_port.sc_ops->sal_puts_raw(printk_buf, printed_len);
+
+       va_end(args);
+       return printed_len;
+}
+#endif                         /* DEBUG */
+
+/*
+ * Interrupt handling routines.
+ */
+
+/**
+ * sn_receive_chars - Grab characters, pass them to tty layer
+ * @port: Port to operate on
+ * @flags: irq flags
+ *
+ * Note: If we're not registered with the serial core infrastructure yet,
+ * we don't try to send characters to it...
+ *
+ */
+static void
+sn_receive_chars(struct sn_cons_port *port, unsigned long flags)
+{
+       int ch;
+       struct tty_struct *tty;
+
+       if (!port) {
+               printk(KERN_ERR "sn_receive_chars - port NULL so can't receieve\n");
+               return;
+       }
+
+       if (!port->sc_ops) {
+               printk(KERN_ERR "sn_receive_chars - port->sc_ops  NULL so can't receieve\n");
+               return;
+       }
+
+       if (port->sc_port.state) {
+               /* The serial_core stuffs are initialized, use them */
+               tty = port->sc_port.state->port.tty;
+       }
+       else {
+               /* Not registered yet - can't pass to tty layer.  */
+               tty = NULL;
+       }
+
+       while (port->sc_ops->sal_input_pending()) {
+               ch = port->sc_ops->sal_getc();
+               if (ch < 0) {
+                       printk(KERN_ERR "sn_console: An error occured while "
+                              "obtaining data from the console (0x%0x)\n", ch);
+                       break;
+               }
+#ifdef CONFIG_MAGIC_SYSRQ
+                if (sysrq_requested) {
+                        unsigned long sysrq_timeout = sysrq_requested + HZ*5;
+
+                        sysrq_requested = 0;
+                        if (ch && time_before(jiffies, sysrq_timeout)) {
+                                spin_unlock_irqrestore(&port->sc_port.lock, flags);
+                                handle_sysrq(ch);
+                                spin_lock_irqsave(&port->sc_port.lock, flags);
+                                /* ignore actual sysrq command char */
+                                continue;
+                        }
+                }
+                if (ch == *sysrq_serial_ptr) {
+                        if (!(*++sysrq_serial_ptr)) {
+                                sysrq_requested = jiffies;
+                                sysrq_serial_ptr = sysrq_serial_str;
+                        }
+                       /*
+                        * ignore the whole sysrq string except for the
+                        * leading escape
+                        */
+                       if (ch != '\e')
+                               continue;
+                }
+                else
+                       sysrq_serial_ptr = sysrq_serial_str;
+#endif /* CONFIG_MAGIC_SYSRQ */
+
+               /* record the character to pass up to the tty layer */
+               if (tty) {
+                       if(tty_insert_flip_char(tty, ch, TTY_NORMAL) == 0)
+                               break;
+               }
+               port->sc_port.icount.rx++;
+       }
+
+       if (tty)
+               tty_flip_buffer_push(tty);
+}
+
+/**
+ * sn_transmit_chars - grab characters from serial core, send off
+ * @port: Port to operate on
+ * @raw: Transmit raw or buffered
+ *
+ * Note: If we're early, before we're registered with serial core, the
+ * writes are going through sn_sal_console_write because that's how
+ * register_console has been set up.  We currently could have asynch
+ * polls calling this function due to sn_sal_switch_to_asynch but we can
+ * ignore them until we register with the serial core stuffs.
+ *
+ */
+static void sn_transmit_chars(struct sn_cons_port *port, int raw)
+{
+       int xmit_count, tail, head, loops, ii;
+       int result;
+       char *start;
+       struct circ_buf *xmit;
+
+       if (!port)
+               return;
+
+       BUG_ON(!port->sc_is_asynch);
+
+       if (port->sc_port.state) {
+               /* We're initialized, using serial core infrastructure */
+               xmit = &port->sc_port.state->xmit;
+       } else {
+               /* Probably sn_sal_switch_to_asynch has been run but serial core isn't
+                * initialized yet.  Just return.  Writes are going through
+                * sn_sal_console_write (due to register_console) at this time.
+                */
+               return;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&port->sc_port)) {
+               /* Nothing to do. */
+               ia64_sn_console_intr_disable(SAL_CONSOLE_INTR_XMIT);
+               return;
+       }
+
+       head = xmit->head;
+       tail = xmit->tail;
+       start = &xmit->buf[tail];
+
+       /* twice around gets the tail to the end of the buffer and
+        * then to the head, if needed */
+       loops = (head < tail) ? 2 : 1;
+
+       for (ii = 0; ii < loops; ii++) {
+               xmit_count = (head < tail) ?
+                   (UART_XMIT_SIZE - tail) : (head - tail);
+
+               if (xmit_count > 0) {
+                       if (raw == TRANSMIT_RAW)
+                               result =
+                                   port->sc_ops->sal_puts_raw(start,
+                                                              xmit_count);
+                       else
+                               result =
+                                   port->sc_ops->sal_puts(start, xmit_count);
+#ifdef DEBUG
+                       if (!result)
+                               DPRINTF("`");
+#endif
+                       if (result > 0) {
+                               xmit_count -= result;
+                               port->sc_port.icount.tx += result;
+                               tail += result;
+                               tail &= UART_XMIT_SIZE - 1;
+                               xmit->tail = tail;
+                               start = &xmit->buf[tail];
+                       }
+               }
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&port->sc_port);
+
+       if (uart_circ_empty(xmit))
+               snp_stop_tx(&port->sc_port);    /* no-op for us */
+}
+
+/**
+ * sn_sal_interrupt - Handle console interrupts
+ * @irq: irq #, useful for debug statements
+ * @dev_id: our pointer to our port (sn_cons_port which contains the uart port)
+ *
+ */
+static irqreturn_t sn_sal_interrupt(int irq, void *dev_id)
+{
+       struct sn_cons_port *port = (struct sn_cons_port *)dev_id;
+       unsigned long flags;
+       int status = ia64_sn_console_intr_status();
+
+       if (!port)
+               return IRQ_NONE;
+
+       spin_lock_irqsave(&port->sc_port.lock, flags);
+       if (status & SAL_CONSOLE_INTR_RECV) {
+               sn_receive_chars(port, flags);
+       }
+       if (status & SAL_CONSOLE_INTR_XMIT) {
+               sn_transmit_chars(port, TRANSMIT_BUFFERED);
+       }
+       spin_unlock_irqrestore(&port->sc_port.lock, flags);
+       return IRQ_HANDLED;
+}
+
+/**
+ * sn_sal_timer_poll - this function handles polled console mode
+ * @data: A pointer to our sn_cons_port (which contains the uart port)
+ *
+ * data is the pointer that init_timer will store for us.  This function is
+ * associated with init_timer to see if there is any console traffic.
+ * Obviously not used in interrupt mode
+ *
+ */
+static void sn_sal_timer_poll(unsigned long data)
+{
+       struct sn_cons_port *port = (struct sn_cons_port *)data;
+       unsigned long flags;
+
+       if (!port)
+               return;
+
+       if (!port->sc_port.irq) {
+               spin_lock_irqsave(&port->sc_port.lock, flags);
+               if (sn_process_input)
+                       sn_receive_chars(port, flags);
+               sn_transmit_chars(port, TRANSMIT_RAW);
+               spin_unlock_irqrestore(&port->sc_port.lock, flags);
+               mod_timer(&port->sc_timer,
+                         jiffies + port->sc_interrupt_timeout);
+       }
+}
+
+/*
+ * Boot-time initialization code
+ */
+
+/**
+ * sn_sal_switch_to_asynch - Switch to async mode (as opposed to synch)
+ * @port: Our sn_cons_port (which contains the uart port)
+ *
+ * So this is used by sn_sal_serial_console_init (early on, before we're
+ * registered with serial core).  It's also used by sn_sal_module_init
+ * right after we've registered with serial core.  The later only happens
+ * if we didn't already come through here via sn_sal_serial_console_init.
+ *
+ */
+static void __init sn_sal_switch_to_asynch(struct sn_cons_port *port)
+{
+       unsigned long flags;
+
+       if (!port)
+               return;
+
+       DPRINTF("sn_console: about to switch to asynchronous console\n");
+
+       /* without early_printk, we may be invoked late enough to race
+        * with other cpus doing console IO at this point, however
+        * console interrupts will never be enabled */
+       spin_lock_irqsave(&port->sc_port.lock, flags);
+
+       /* early_printk invocation may have done this for us */
+       if (!port->sc_ops)
+               port->sc_ops = &poll_ops;
+
+       /* we can't turn on the console interrupt (as request_irq
+        * calls kmalloc, which isn't set up yet), so we rely on a
+        * timer to poll for input and push data from the console
+        * buffer.
+        */
+       init_timer(&port->sc_timer);
+       port->sc_timer.function = sn_sal_timer_poll;
+       port->sc_timer.data = (unsigned long)port;
+
+       if (IS_RUNNING_ON_SIMULATOR())
+               port->sc_interrupt_timeout = 6;
+       else {
+               /* 960cps / 16 char FIFO = 60HZ
+                * HZ / (SN_SAL_FIFO_SPEED_CPS / SN_SAL_FIFO_DEPTH) */
+               port->sc_interrupt_timeout =
+                   HZ * SN_SAL_UART_FIFO_DEPTH / SN_SAL_UART_FIFO_SPEED_CPS;
+       }
+       mod_timer(&port->sc_timer, jiffies + port->sc_interrupt_timeout);
+
+       port->sc_is_asynch = 1;
+       spin_unlock_irqrestore(&port->sc_port.lock, flags);
+}
+
+/**
+ * sn_sal_switch_to_interrupts - Switch to interrupt driven mode
+ * @port: Our sn_cons_port (which contains the uart port)
+ *
+ * In sn_sal_module_init, after we're registered with serial core and
+ * the port is added, this function is called to switch us to interrupt
+ * mode.  We were previously in asynch/polling mode (using init_timer).
+ *
+ * We attempt to switch to interrupt mode here by calling
+ * request_irq.  If that works out, we enable receive interrupts.
+ */
+static void __init sn_sal_switch_to_interrupts(struct sn_cons_port *port)
+{
+       unsigned long flags;
+
+       if (port) {
+               DPRINTF("sn_console: switching to interrupt driven console\n");
+
+               if (request_irq(SGI_UART_VECTOR, sn_sal_interrupt,
+                               IRQF_DISABLED | IRQF_SHARED,
+                               "SAL console driver", port) >= 0) {
+                       spin_lock_irqsave(&port->sc_port.lock, flags);
+                       port->sc_port.irq = SGI_UART_VECTOR;
+                       port->sc_ops = &intr_ops;
+
+                       /* turn on receive interrupts */
+                       ia64_sn_console_intr_enable(SAL_CONSOLE_INTR_RECV);
+                       spin_unlock_irqrestore(&port->sc_port.lock, flags);
+               }
+               else {
+                       printk(KERN_INFO
+                           "sn_console: console proceeding in polled mode\n");
+               }
+       }
+}
+
+/*
+ * Kernel console definitions
+ */
+
+static void sn_sal_console_write(struct console *, const char *, unsigned);
+static int sn_sal_console_setup(struct console *, char *);
+static struct uart_driver sal_console_uart;
+extern struct tty_driver *uart_console_device(struct console *, int *);
+
+static struct console sal_console = {
+       .name = DEVICE_NAME,
+       .write = sn_sal_console_write,
+       .device = uart_console_device,
+       .setup = sn_sal_console_setup,
+       .index = -1,            /* unspecified */
+       .data = &sal_console_uart,
+};
+
+#define SAL_CONSOLE    &sal_console
+
+static struct uart_driver sal_console_uart = {
+       .owner = THIS_MODULE,
+       .driver_name = "sn_console",
+       .dev_name = DEVICE_NAME,
+       .major = 0,             /* major/minor set at registration time per USE_DYNAMIC_MINOR */
+       .minor = 0,
+       .nr = 1,                /* one port */
+       .cons = SAL_CONSOLE,
+};
+
+/**
+ * sn_sal_module_init - When the kernel loads us, get us rolling w/ serial core
+ *
+ * Before this is called, we've been printing kernel messages in a special
+ * early mode not making use of the serial core infrastructure.  When our
+ * driver is loaded for real, we register the driver and port with serial
+ * core and try to enable interrupt driven mode.
+ *
+ */
+static int __init sn_sal_module_init(void)
+{
+       int retval;
+
+       if (!ia64_platform_is("sn2"))
+               return 0;
+
+       printk(KERN_INFO "sn_console: Console driver init\n");
+
+       if (USE_DYNAMIC_MINOR == 1) {
+               misc.minor = MISC_DYNAMIC_MINOR;
+               misc.name = DEVICE_NAME_DYNAMIC;
+               retval = misc_register(&misc);
+               if (retval != 0) {
+                       printk(KERN_WARNING "Failed to register console "
+                              "device using misc_register.\n");
+                       return -ENODEV;
+               }
+               sal_console_uart.major = MISC_MAJOR;
+               sal_console_uart.minor = misc.minor;
+       } else {
+               sal_console_uart.major = DEVICE_MAJOR;
+               sal_console_uart.minor = DEVICE_MINOR;
+       }
+
+       /* We register the driver and the port before switching to interrupts
+        * or async above so the proper uart structures are populated */
+
+       if (uart_register_driver(&sal_console_uart) < 0) {
+               printk
+                   ("ERROR sn_sal_module_init failed uart_register_driver, line %d\n",
+                    __LINE__);
+               return -ENODEV;
+       }
+
+       spin_lock_init(&sal_console_port.sc_port.lock);
+
+       /* Setup the port struct with the minimum needed */
+       sal_console_port.sc_port.membase = (char *)1;   /* just needs to be non-zero */
+       sal_console_port.sc_port.type = PORT_16550A;
+       sal_console_port.sc_port.fifosize = SN_SAL_MAX_CHARS;
+       sal_console_port.sc_port.ops = &sn_console_ops;
+       sal_console_port.sc_port.line = 0;
+
+       if (uart_add_one_port(&sal_console_uart, &sal_console_port.sc_port) < 0) {
+               /* error - not sure what I'd do - so I'll do nothing */
+               printk(KERN_ERR "%s: unable to add port\n", __func__);
+       }
+
+       /* when this driver is compiled in, the console initialization
+        * will have already switched us into asynchronous operation
+        * before we get here through the module initcalls */
+       if (!sal_console_port.sc_is_asynch) {
+               sn_sal_switch_to_asynch(&sal_console_port);
+       }
+
+       /* at this point (module_init) we can try to turn on interrupts */
+       if (!IS_RUNNING_ON_SIMULATOR()) {
+               sn_sal_switch_to_interrupts(&sal_console_port);
+       }
+       sn_process_input = 1;
+       return 0;
+}
+
+/**
+ * sn_sal_module_exit - When we're unloaded, remove the driver/port
+ *
+ */
+static void __exit sn_sal_module_exit(void)
+{
+       del_timer_sync(&sal_console_port.sc_timer);
+       uart_remove_one_port(&sal_console_uart, &sal_console_port.sc_port);
+       uart_unregister_driver(&sal_console_uart);
+       misc_deregister(&misc);
+}
+
+module_init(sn_sal_module_init);
+module_exit(sn_sal_module_exit);
+
+/**
+ * puts_raw_fixed - sn_sal_console_write helper for adding \r's as required
+ * @puts_raw : puts function to do the writing
+ * @s: input string
+ * @count: length
+ *
+ * We need a \r ahead of every \n for direct writes through
+ * ia64_sn_console_putb (what sal_puts_raw below actually does).
+ *
+ */
+
+static void puts_raw_fixed(int (*puts_raw) (const char *s, int len),
+                          const char *s, int count)
+{
+       const char *s1;
+
+       /* Output '\r' before each '\n' */
+       while ((s1 = memchr(s, '\n', count)) != NULL) {
+               puts_raw(s, s1 - s);
+               puts_raw("\r\n", 2);
+               count -= s1 + 1 - s;
+               s = s1 + 1;
+       }
+       puts_raw(s, count);
+}
+
+/**
+ * sn_sal_console_write - Print statements before serial core available
+ * @console: Console to operate on - we ignore since we have just one
+ * @s: String to send
+ * @count: length
+ *
+ * This is referenced in the console struct.  It is used for early
+ * console printing before we register with serial core and for things
+ * such as kdb.  The console_lock must be held when we get here.
+ *
+ * This function has some code for trying to print output even if the lock
+ * is held.  We try to cover the case where a lock holder could have died.
+ * We don't use this special case code if we're not registered with serial
+ * core yet.  After we're registered with serial core, the only time this
+ * function would be used is for high level kernel output like magic sys req,
+ * kdb, and printk's.
+ */
+static void
+sn_sal_console_write(struct console *co, const char *s, unsigned count)
+{
+       unsigned long flags = 0;
+       struct sn_cons_port *port = &sal_console_port;
+       static int stole_lock = 0;
+
+       BUG_ON(!port->sc_is_asynch);
+
+       /* We can't look at the xmit buffer if we're not registered with serial core
+        *  yet.  So only do the fancy recovery after registering
+        */
+       if (!port->sc_port.state) {
+               /* Not yet registered with serial core - simple case */
+               puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
+               return;
+       }
+
+       /* somebody really wants this output, might be an
+        * oops, kdb, panic, etc.  make sure they get it. */
+       if (spin_is_locked(&port->sc_port.lock)) {
+               int lhead = port->sc_port.state->xmit.head;
+               int ltail = port->sc_port.state->xmit.tail;
+               int counter, got_lock = 0;
+
+               /*
+                * We attempt to determine if someone has died with the
+                * lock. We wait ~20 secs after the head and tail ptrs
+                * stop moving and assume the lock holder is not functional
+                * and plow ahead. If the lock is freed within the time out
+                * period we re-get the lock and go ahead normally. We also
+                * remember if we have plowed ahead so that we don't have
+                * to wait out the time out period again - the asumption
+                * is that we will time out again.
+                */
+
+               for (counter = 0; counter < 150; mdelay(125), counter++) {
+                       if (!spin_is_locked(&port->sc_port.lock)
+                           || stole_lock) {
+                               if (!stole_lock) {
+                                       spin_lock_irqsave(&port->sc_port.lock,
+                                                         flags);
+                                       got_lock = 1;
+                               }
+                               break;
+                       } else {
+                               /* still locked */
+                               if ((lhead != port->sc_port.state->xmit.head)
+                                   || (ltail !=
+                                       port->sc_port.state->xmit.tail)) {
+                                       lhead =
+                                               port->sc_port.state->xmit.head;
+                                       ltail =
+                                               port->sc_port.state->xmit.tail;
+                                       counter = 0;
+                               }
+                       }
+               }
+               /* flush anything in the serial core xmit buffer, raw */
+               sn_transmit_chars(port, 1);
+               if (got_lock) {
+                       spin_unlock_irqrestore(&port->sc_port.lock, flags);
+                       stole_lock = 0;
+               } else {
+                       /* fell thru */
+                       stole_lock = 1;
+               }
+               puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
+       } else {
+               stole_lock = 0;
+               spin_lock_irqsave(&port->sc_port.lock, flags);
+               sn_transmit_chars(port, 1);
+               spin_unlock_irqrestore(&port->sc_port.lock, flags);
+
+               puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
+       }
+}
+
+
+/**
+ * sn_sal_console_setup - Set up console for early printing
+ * @co: Console to work with
+ * @options: Options to set
+ *
+ * Altix console doesn't do anything with baud rates, etc, anyway.
+ *
+ * This isn't required since not providing the setup function in the
+ * console struct is ok.  However, other patches like KDB plop something
+ * here so providing it is easier.
+ *
+ */
+static int sn_sal_console_setup(struct console *co, char *options)
+{
+       return 0;
+}
+
+/**
+ * sn_sal_console_write_early - simple early output routine
+ * @co - console struct
+ * @s - string to print
+ * @count - count
+ *
+ * Simple function to provide early output, before even
+ * sn_sal_serial_console_init is called.  Referenced in the
+ * console struct registerd in sn_serial_console_early_setup.
+ *
+ */
+static void __init
+sn_sal_console_write_early(struct console *co, const char *s, unsigned count)
+{
+       puts_raw_fixed(sal_console_port.sc_ops->sal_puts_raw, s, count);
+}
+
+/* Used for very early console printing - again, before
+ * sn_sal_serial_console_init is run */
+static struct console sal_console_early __initdata = {
+       .name = "sn_sal",
+       .write = sn_sal_console_write_early,
+       .flags = CON_PRINTBUFFER,
+       .index = -1,
+};
+
+/**
+ * sn_serial_console_early_setup - Sets up early console output support
+ *
+ * Register a console early on...  This is for output before even
+ * sn_sal_serial_cosnole_init is called.  This function is called from
+ * setup.c.  This allows us to do really early polled writes. When
+ * sn_sal_serial_console_init is called, this console is unregistered
+ * and a new one registered.
+ */
+int __init sn_serial_console_early_setup(void)
+{
+       if (!ia64_platform_is("sn2"))
+               return -1;
+
+       sal_console_port.sc_ops = &poll_ops;
+       spin_lock_init(&sal_console_port.sc_port.lock);
+       early_sn_setup();       /* Find SAL entry points */
+       register_console(&sal_console_early);
+
+       return 0;
+}
+
+/**
+ * sn_sal_serial_console_init - Early console output - set up for register
+ *
+ * This function is called when regular console init happens.  Because we
+ * support even earlier console output with sn_serial_console_early_setup
+ * (called from setup.c directly), this function unregisters the really
+ * early console.
+ *
+ * Note: Even if setup.c doesn't register sal_console_early, unregistering
+ * it here doesn't hurt anything.
+ *
+ */
+static int __init sn_sal_serial_console_init(void)
+{
+       if (ia64_platform_is("sn2")) {
+               sn_sal_switch_to_asynch(&sal_console_port);
+               DPRINTF("sn_sal_serial_console_init : register console\n");
+               register_console(&sal_console);
+               unregister_console(&sal_console_early);
+       }
+       return 0;
+}
+
+console_initcall(sn_sal_serial_console_init);
diff --git a/drivers/tty/serial/suncore.c b/drivers/tty/serial/suncore.c
new file mode 100644 (file)
index 0000000..6381a02
--- /dev/null
@@ -0,0 +1,247 @@
+/* suncore.c
+ *
+ * Common SUN serial routines.  Based entirely
+ * upon drivers/sbus/char/sunserial.c which is:
+ *
+ * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
+ *
+ * Adaptation to new UART layer is:
+ *
+ * Copyright (C) 2002 David S. Miller (davem@redhat.com)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/serial_core.h>
+#include <linux/init.h>
+
+#include <asm/prom.h>
+
+#include "suncore.h"
+
+static int sunserial_current_minor = 64;
+
+int sunserial_register_minors(struct uart_driver *drv, int count)
+{
+       int err = 0;
+
+       drv->minor = sunserial_current_minor;
+       drv->nr += count;
+       /* Register the driver on the first call */
+       if (drv->nr == count)
+               err = uart_register_driver(drv);
+       if (err == 0) {
+               sunserial_current_minor += count;
+               drv->tty_driver->name_base = drv->minor - 64;
+       }
+       return err;
+}
+EXPORT_SYMBOL(sunserial_register_minors);
+
+void sunserial_unregister_minors(struct uart_driver *drv, int count)
+{
+       drv->nr -= count;
+       sunserial_current_minor -= count;
+
+       if (drv->nr == 0)
+               uart_unregister_driver(drv);
+}
+EXPORT_SYMBOL(sunserial_unregister_minors);
+
+int sunserial_console_match(struct console *con, struct device_node *dp,
+                           struct uart_driver *drv, int line, bool ignore_line)
+{
+       if (!con)
+               return 0;
+
+       drv->cons = con;
+
+       if (of_console_device != dp)
+               return 0;
+
+       if (!ignore_line) {
+               int off = 0;
+
+               if (of_console_options &&
+                   *of_console_options == 'b')
+                       off = 1;
+
+               if ((line & 1) != off)
+                       return 0;
+       }
+
+       if (!console_set_on_cmdline) {
+               con->index = line;
+               add_preferred_console(con->name, line, NULL);
+       }
+       return 1;
+}
+EXPORT_SYMBOL(sunserial_console_match);
+
+void sunserial_console_termios(struct console *con, struct device_node *uart_dp)
+{
+       const char *mode, *s;
+       char mode_prop[] = "ttyX-mode";
+       int baud, bits, stop, cflag;
+       char parity;
+
+       if (!strcmp(uart_dp->name, "rsc") ||
+           !strcmp(uart_dp->name, "rsc-console") ||
+           !strcmp(uart_dp->name, "rsc-control")) {
+               mode = of_get_property(uart_dp,
+                                      "ssp-console-modes", NULL);
+               if (!mode)
+                       mode = "115200,8,n,1,-";
+       } else if (!strcmp(uart_dp->name, "lom-console")) {
+               mode = "9600,8,n,1,-";
+       } else {
+               struct device_node *dp;
+               char c;
+
+               c = 'a';
+               if (of_console_options)
+                       c = *of_console_options;
+
+               mode_prop[3] = c;
+
+               dp = of_find_node_by_path("/options");
+               mode = of_get_property(dp, mode_prop, NULL);
+               if (!mode)
+                       mode = "9600,8,n,1,-";
+       }
+
+       cflag = CREAD | HUPCL | CLOCAL;
+
+       s = mode;
+       baud = simple_strtoul(s, NULL, 0);
+       s = strchr(s, ',');
+       bits = simple_strtoul(++s, NULL, 0);
+       s = strchr(s, ',');
+       parity = *(++s);
+       s = strchr(s, ',');
+       stop = simple_strtoul(++s, NULL, 0);
+       s = strchr(s, ',');
+       /* XXX handshake is not handled here. */
+
+       switch (baud) {
+               case 150: cflag |= B150; break;
+               case 300: cflag |= B300; break;
+               case 600: cflag |= B600; break;
+               case 1200: cflag |= B1200; break;
+               case 2400: cflag |= B2400; break;
+               case 4800: cflag |= B4800; break;
+               case 9600: cflag |= B9600; break;
+               case 19200: cflag |= B19200; break;
+               case 38400: cflag |= B38400; break;
+               case 57600: cflag |= B57600; break;
+               case 115200: cflag |= B115200; break;
+               case 230400: cflag |= B230400; break;
+               case 460800: cflag |= B460800; break;
+               default: baud = 9600; cflag |= B9600; break;
+       }
+
+       switch (bits) {
+               case 5: cflag |= CS5; break;
+               case 6: cflag |= CS6; break;
+               case 7: cflag |= CS7; break;
+               case 8: cflag |= CS8; break;
+               default: cflag |= CS8; break;
+       }
+
+       switch (parity) {
+               case 'o': cflag |= (PARENB | PARODD); break;
+               case 'e': cflag |= PARENB; break;
+               case 'n': default: break;
+       }
+
+       switch (stop) {
+               case 2: cflag |= CSTOPB; break;
+               case 1: default: break;
+       }
+
+       con->cflag = cflag;
+}
+
+/* Sun serial MOUSE auto baud rate detection.  */
+static struct mouse_baud_cflag {
+       int baud;
+       unsigned int cflag;
+} mouse_baud_table[] = {
+       { 1200, B1200 },
+       { 2400, B2400 },
+       { 4800, B4800 },
+       { 9600, B9600 },
+       { -1, ~0 },
+       { -1, ~0 },
+};
+
+unsigned int suncore_mouse_baud_cflag_next(unsigned int cflag, int *new_baud)
+{
+       int i;
+
+       for (i = 0; mouse_baud_table[i].baud != -1; i++)
+               if (mouse_baud_table[i].cflag == (cflag & CBAUD))
+                       break;
+
+       i += 1;
+       if (mouse_baud_table[i].baud == -1)
+               i = 0;
+
+       *new_baud = mouse_baud_table[i].baud;
+       return mouse_baud_table[i].cflag;
+}
+
+EXPORT_SYMBOL(suncore_mouse_baud_cflag_next);
+
+/* Basically, when the baud rate is wrong the mouse spits out
+ * breaks to us.
+ */
+int suncore_mouse_baud_detection(unsigned char ch, int is_break)
+{
+       static int mouse_got_break = 0;
+       static int ctr = 0;
+
+       if (is_break) {
+               /* Let a few normal bytes go by before we jump the gun
+                * and say we need to try another baud rate.
+                */
+               if (mouse_got_break && ctr < 8)
+                       return 1;
+
+               /* Ok, we need to try another baud. */
+               ctr = 0;
+               mouse_got_break = 1;
+               return 2;
+       }
+       if (mouse_got_break) {
+               ctr++;
+               if (ch == 0x87) {
+                       /* Correct baud rate determined. */
+                       mouse_got_break = 0;
+               }
+               return 1;
+       }
+       return 0;
+}
+
+EXPORT_SYMBOL(suncore_mouse_baud_detection);
+
+static int __init suncore_init(void)
+{
+       return 0;
+}
+
+static void __exit suncore_exit(void)
+{
+}
+
+module_init(suncore_init);
+module_exit(suncore_exit);
+
+MODULE_AUTHOR("Eddie C. Dost, David S. Miller");
+MODULE_DESCRIPTION("Sun serial common layer");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/suncore.h b/drivers/tty/serial/suncore.h
new file mode 100644 (file)
index 0000000..db20579
--- /dev/null
@@ -0,0 +1,33 @@
+/* suncore.h
+ *
+ * Generic SUN serial/kbd/ms layer.  Based entirely
+ * upon drivers/sbus/char/sunserial.h which is:
+ *
+ * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
+ *
+ * Port to new UART layer is:
+ *
+ * Copyright (C) 2002 David S. Miller (davem@redhat.com)
+ */
+
+#ifndef _SERIAL_SUN_H
+#define _SERIAL_SUN_H
+
+/* Serial keyboard defines for L1-A processing... */
+#define SUNKBD_RESET           0xff
+#define SUNKBD_L1              0x01
+#define SUNKBD_UP              0x80
+#define SUNKBD_A               0x4d
+
+extern unsigned int suncore_mouse_baud_cflag_next(unsigned int, int *);
+extern int suncore_mouse_baud_detection(unsigned char, int);
+
+extern int sunserial_register_minors(struct uart_driver *, int);
+extern void sunserial_unregister_minors(struct uart_driver *, int);
+
+extern int sunserial_console_match(struct console *, struct device_node *,
+                                  struct uart_driver *, int, bool);
+extern void sunserial_console_termios(struct console *,
+                                     struct device_node *);
+
+#endif /* !(_SERIAL_SUN_H) */
diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c
new file mode 100644 (file)
index 0000000..c901486
--- /dev/null
@@ -0,0 +1,661 @@
+/* sunhv.c: Serial driver for SUN4V hypervisor console.
+ *
+ * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/of_device.h>
+
+#include <asm/hypervisor.h>
+#include <asm/spitfire.h>
+#include <asm/prom.h>
+#include <asm/irq.h>
+
+#if defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#include "suncore.h"
+
+#define CON_BREAK      ((long)-1)
+#define CON_HUP                ((long)-2)
+
+#define IGNORE_BREAK   0x1
+#define IGNORE_ALL     0x2
+
+static char *con_write_page;
+static char *con_read_page;
+
+static int hung_up = 0;
+
+static void transmit_chars_putchar(struct uart_port *port, struct circ_buf *xmit)
+{
+       while (!uart_circ_empty(xmit)) {
+               long status = sun4v_con_putchar(xmit->buf[xmit->tail]);
+
+               if (status != HV_EOK)
+                       break;
+
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+       }
+}
+
+static void transmit_chars_write(struct uart_port *port, struct circ_buf *xmit)
+{
+       while (!uart_circ_empty(xmit)) {
+               unsigned long ra = __pa(xmit->buf + xmit->tail);
+               unsigned long len, status, sent;
+
+               len = CIRC_CNT_TO_END(xmit->head, xmit->tail,
+                                     UART_XMIT_SIZE);
+               status = sun4v_con_write(ra, len, &sent);
+               if (status != HV_EOK)
+                       break;
+               xmit->tail = (xmit->tail + sent) & (UART_XMIT_SIZE - 1);
+               port->icount.tx += sent;
+       }
+}
+
+static int receive_chars_getchar(struct uart_port *port, struct tty_struct *tty)
+{
+       int saw_console_brk = 0;
+       int limit = 10000;
+
+       while (limit-- > 0) {
+               long status;
+               long c = sun4v_con_getchar(&status);
+
+               if (status == HV_EWOULDBLOCK)
+                       break;
+
+               if (c == CON_BREAK) {
+                       if (uart_handle_break(port))
+                               continue;
+                       saw_console_brk = 1;
+                       c = 0;
+               }
+
+               if (c == CON_HUP) {
+                       hung_up = 1;
+                       uart_handle_dcd_change(port, 0);
+               } else if (hung_up) {
+                       hung_up = 0;
+                       uart_handle_dcd_change(port, 1);
+               }
+
+               if (tty == NULL) {
+                       uart_handle_sysrq_char(port, c);
+                       continue;
+               }
+
+               port->icount.rx++;
+
+               if (uart_handle_sysrq_char(port, c))
+                       continue;
+
+               tty_insert_flip_char(tty, c, TTY_NORMAL);
+       }
+
+       return saw_console_brk;
+}
+
+static int receive_chars_read(struct uart_port *port, struct tty_struct *tty)
+{
+       int saw_console_brk = 0;
+       int limit = 10000;
+
+       while (limit-- > 0) {
+               unsigned long ra = __pa(con_read_page);
+               unsigned long bytes_read, i;
+               long stat = sun4v_con_read(ra, PAGE_SIZE, &bytes_read);
+
+               if (stat != HV_EOK) {
+                       bytes_read = 0;
+
+                       if (stat == CON_BREAK) {
+                               if (uart_handle_break(port))
+                                       continue;
+                               saw_console_brk = 1;
+                               *con_read_page = 0;
+                               bytes_read = 1;
+                       } else if (stat == CON_HUP) {
+                               hung_up = 1;
+                               uart_handle_dcd_change(port, 0);
+                               continue;
+                       } else {
+                               /* HV_EWOULDBLOCK, etc.  */
+                               break;
+                       }
+               }
+
+               if (hung_up) {
+                       hung_up = 0;
+                       uart_handle_dcd_change(port, 1);
+               }
+
+               for (i = 0; i < bytes_read; i++)
+                       uart_handle_sysrq_char(port, con_read_page[i]);
+
+               if (tty == NULL)
+                       continue;
+
+               port->icount.rx += bytes_read;
+
+               tty_insert_flip_string(tty, con_read_page, bytes_read);
+       }
+
+       return saw_console_brk;
+}
+
+struct sunhv_ops {
+       void (*transmit_chars)(struct uart_port *port, struct circ_buf *xmit);
+       int (*receive_chars)(struct uart_port *port, struct tty_struct *tty);
+};
+
+static struct sunhv_ops bychar_ops = {
+       .transmit_chars = transmit_chars_putchar,
+       .receive_chars = receive_chars_getchar,
+};
+
+static struct sunhv_ops bywrite_ops = {
+       .transmit_chars = transmit_chars_write,
+       .receive_chars = receive_chars_read,
+};
+
+static struct sunhv_ops *sunhv_ops = &bychar_ops;
+
+static struct tty_struct *receive_chars(struct uart_port *port)
+{
+       struct tty_struct *tty = NULL;
+
+       if (port->state != NULL)                /* Unopened serial console */
+               tty = port->state->port.tty;
+
+       if (sunhv_ops->receive_chars(port, tty))
+               sun_do_break();
+
+       return tty;
+}
+
+static void transmit_chars(struct uart_port *port)
+{
+       struct circ_buf *xmit;
+
+       if (!port->state)
+               return;
+
+       xmit = &port->state->xmit;
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+               return;
+
+       sunhv_ops->transmit_chars(port, xmit);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+}
+
+static irqreturn_t sunhv_interrupt(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       struct tty_struct *tty;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       tty = receive_chars(port);
+       transmit_chars(port);
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       if (tty)
+               tty_flip_buffer_push(tty);
+
+       return IRQ_HANDLED;
+}
+
+/* port->lock is not held.  */
+static unsigned int sunhv_tx_empty(struct uart_port *port)
+{
+       /* Transmitter is always empty for us.  If the circ buffer
+        * is non-empty or there is an x_char pending, our caller
+        * will do the right thing and ignore what we return here.
+        */
+       return TIOCSER_TEMT;
+}
+
+/* port->lock held by caller.  */
+static void sunhv_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       return;
+}
+
+/* port->lock is held by caller and interrupts are disabled.  */
+static unsigned int sunhv_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS;
+}
+
+/* port->lock held by caller.  */
+static void sunhv_stop_tx(struct uart_port *port)
+{
+       return;
+}
+
+/* port->lock held by caller.  */
+static void sunhv_start_tx(struct uart_port *port)
+{
+       transmit_chars(port);
+}
+
+/* port->lock is not held.  */
+static void sunhv_send_xchar(struct uart_port *port, char ch)
+{
+       unsigned long flags;
+       int limit = 10000;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       while (limit-- > 0) {
+               long status = sun4v_con_putchar(ch);
+               if (status == HV_EOK)
+                       break;
+               udelay(1);
+       }
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* port->lock held by caller.  */
+static void sunhv_stop_rx(struct uart_port *port)
+{
+}
+
+/* port->lock held by caller.  */
+static void sunhv_enable_ms(struct uart_port *port)
+{
+}
+
+/* port->lock is not held.  */
+static void sunhv_break_ctl(struct uart_port *port, int break_state)
+{
+       if (break_state) {
+               unsigned long flags;
+               int limit = 10000;
+
+               spin_lock_irqsave(&port->lock, flags);
+
+               while (limit-- > 0) {
+                       long status = sun4v_con_putchar(CON_BREAK);
+                       if (status == HV_EOK)
+                               break;
+                       udelay(1);
+               }
+
+               spin_unlock_irqrestore(&port->lock, flags);
+       }
+}
+
+/* port->lock is not held.  */
+static int sunhv_startup(struct uart_port *port)
+{
+       return 0;
+}
+
+/* port->lock is not held.  */
+static void sunhv_shutdown(struct uart_port *port)
+{
+}
+
+/* port->lock is not held.  */
+static void sunhv_set_termios(struct uart_port *port, struct ktermios *termios,
+                             struct ktermios *old)
+{
+       unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
+       unsigned int quot = uart_get_divisor(port, baud);
+       unsigned int iflag, cflag;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       iflag = termios->c_iflag;
+       cflag = termios->c_cflag;
+
+       port->ignore_status_mask = 0;
+       if (iflag & IGNBRK)
+               port->ignore_status_mask |= IGNORE_BREAK;
+       if ((cflag & CREAD) == 0)
+               port->ignore_status_mask |= IGNORE_ALL;
+
+       /* XXX */
+       uart_update_timeout(port, cflag,
+                           (port->uartclk / (16 * quot)));
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *sunhv_type(struct uart_port *port)
+{
+       return "SUN4V HCONS";
+}
+
+static void sunhv_release_port(struct uart_port *port)
+{
+}
+
+static int sunhv_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static void sunhv_config_port(struct uart_port *port, int flags)
+{
+}
+
+static int sunhv_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       return -EINVAL;
+}
+
+static struct uart_ops sunhv_pops = {
+       .tx_empty       = sunhv_tx_empty,
+       .set_mctrl      = sunhv_set_mctrl,
+       .get_mctrl      = sunhv_get_mctrl,
+       .stop_tx        = sunhv_stop_tx,
+       .start_tx       = sunhv_start_tx,
+       .send_xchar     = sunhv_send_xchar,
+       .stop_rx        = sunhv_stop_rx,
+       .enable_ms      = sunhv_enable_ms,
+       .break_ctl      = sunhv_break_ctl,
+       .startup        = sunhv_startup,
+       .shutdown       = sunhv_shutdown,
+       .set_termios    = sunhv_set_termios,
+       .type           = sunhv_type,
+       .release_port   = sunhv_release_port,
+       .request_port   = sunhv_request_port,
+       .config_port    = sunhv_config_port,
+       .verify_port    = sunhv_verify_port,
+};
+
+static struct uart_driver sunhv_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "sunhv",
+       .dev_name               = "ttyS",
+       .major                  = TTY_MAJOR,
+};
+
+static struct uart_port *sunhv_port;
+
+/* Copy 's' into the con_write_page, decoding "\n" into
+ * "\r\n" along the way.  We have to return two lengths
+ * because the caller needs to know how much to advance
+ * 's' and also how many bytes to output via con_write_page.
+ */
+static int fill_con_write_page(const char *s, unsigned int n,
+                              unsigned long *page_bytes)
+{
+       const char *orig_s = s;
+       char *p = con_write_page;
+       int left = PAGE_SIZE;
+
+       while (n--) {
+               if (*s == '\n') {
+                       if (left < 2)
+                               break;
+                       *p++ = '\r';
+                       left--;
+               } else if (left < 1)
+                       break;
+               *p++ = *s++;
+               left--;
+       }
+       *page_bytes = p - con_write_page;
+       return s - orig_s;
+}
+
+static void sunhv_console_write_paged(struct console *con, const char *s, unsigned n)
+{
+       struct uart_port *port = sunhv_port;
+       unsigned long flags;
+       int locked = 1;
+
+       local_irq_save(flags);
+       if (port->sysrq) {
+               locked = 0;
+       } else if (oops_in_progress) {
+               locked = spin_trylock(&port->lock);
+       } else
+               spin_lock(&port->lock);
+
+       while (n > 0) {
+               unsigned long ra = __pa(con_write_page);
+               unsigned long page_bytes;
+               unsigned int cpy = fill_con_write_page(s, n,
+                                                      &page_bytes);
+
+               n -= cpy;
+               s += cpy;
+               while (page_bytes > 0) {
+                       unsigned long written;
+                       int limit = 1000000;
+
+                       while (limit--) {
+                               unsigned long stat;
+
+                               stat = sun4v_con_write(ra, page_bytes,
+                                                      &written);
+                               if (stat == HV_EOK)
+                                       break;
+                               udelay(1);
+                       }
+                       if (limit < 0)
+                               break;
+                       page_bytes -= written;
+                       ra += written;
+               }
+       }
+
+       if (locked)
+               spin_unlock(&port->lock);
+       local_irq_restore(flags);
+}
+
+static inline void sunhv_console_putchar(struct uart_port *port, char c)
+{
+       int limit = 1000000;
+
+       while (limit-- > 0) {
+               long status = sun4v_con_putchar(c);
+               if (status == HV_EOK)
+                       break;
+               udelay(1);
+       }
+}
+
+static void sunhv_console_write_bychar(struct console *con, const char *s, unsigned n)
+{
+       struct uart_port *port = sunhv_port;
+       unsigned long flags;
+       int i, locked = 1;
+
+       local_irq_save(flags);
+       if (port->sysrq) {
+               locked = 0;
+       } else if (oops_in_progress) {
+               locked = spin_trylock(&port->lock);
+       } else
+               spin_lock(&port->lock);
+
+       for (i = 0; i < n; i++) {
+               if (*s == '\n')
+                       sunhv_console_putchar(port, '\r');
+               sunhv_console_putchar(port, *s++);
+       }
+
+       if (locked)
+               spin_unlock(&port->lock);
+       local_irq_restore(flags);
+}
+
+static struct console sunhv_console = {
+       .name   =       "ttyHV",
+       .write  =       sunhv_console_write_bychar,
+       .device =       uart_console_device,
+       .flags  =       CON_PRINTBUFFER,
+       .index  =       -1,
+       .data   =       &sunhv_reg,
+};
+
+static int __devinit hv_probe(struct platform_device *op, const struct of_device_id *match)
+{
+       struct uart_port *port;
+       unsigned long minor;
+       int err;
+
+       if (op->archdata.irqs[0] == 0xffffffff)
+               return -ENODEV;
+
+       port = kzalloc(sizeof(struct uart_port), GFP_KERNEL);
+       if (unlikely(!port))
+               return -ENOMEM;
+
+       minor = 1;
+       if (sun4v_hvapi_register(HV_GRP_CORE, 1, &minor) == 0 &&
+           minor >= 1) {
+               err = -ENOMEM;
+               con_write_page = kzalloc(PAGE_SIZE, GFP_KERNEL);
+               if (!con_write_page)
+                       goto out_free_port;
+
+               con_read_page = kzalloc(PAGE_SIZE, GFP_KERNEL);
+               if (!con_read_page)
+                       goto out_free_con_write_page;
+
+               sunhv_console.write = sunhv_console_write_paged;
+               sunhv_ops = &bywrite_ops;
+       }
+
+       sunhv_port = port;
+
+       port->line = 0;
+       port->ops = &sunhv_pops;
+       port->type = PORT_SUNHV;
+       port->uartclk = ( 29491200 / 16 ); /* arbitrary */
+
+       port->membase = (unsigned char __iomem *) __pa(port);
+
+       port->irq = op->archdata.irqs[0];
+
+       port->dev = &op->dev;
+
+       err = sunserial_register_minors(&sunhv_reg, 1);
+       if (err)
+               goto out_free_con_read_page;
+
+       sunserial_console_match(&sunhv_console, op->dev.of_node,
+                               &sunhv_reg, port->line, false);
+
+       err = uart_add_one_port(&sunhv_reg, port);
+       if (err)
+               goto out_unregister_driver;
+
+       err = request_irq(port->irq, sunhv_interrupt, 0, "hvcons", port);
+       if (err)
+               goto out_remove_port;
+
+       dev_set_drvdata(&op->dev, port);
+
+       return 0;
+
+out_remove_port:
+       uart_remove_one_port(&sunhv_reg, port);
+
+out_unregister_driver:
+       sunserial_unregister_minors(&sunhv_reg, 1);
+
+out_free_con_read_page:
+       kfree(con_read_page);
+
+out_free_con_write_page:
+       kfree(con_write_page);
+
+out_free_port:
+       kfree(port);
+       sunhv_port = NULL;
+       return err;
+}
+
+static int __devexit hv_remove(struct platform_device *dev)
+{
+       struct uart_port *port = dev_get_drvdata(&dev->dev);
+
+       free_irq(port->irq, port);
+
+       uart_remove_one_port(&sunhv_reg, port);
+
+       sunserial_unregister_minors(&sunhv_reg, 1);
+
+       kfree(port);
+       sunhv_port = NULL;
+
+       dev_set_drvdata(&dev->dev, NULL);
+
+       return 0;
+}
+
+static const struct of_device_id hv_match[] = {
+       {
+               .name = "console",
+               .compatible = "qcn",
+       },
+       {
+               .name = "console",
+               .compatible = "SUNW,sun4v-console",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, hv_match);
+
+static struct of_platform_driver hv_driver = {
+       .driver = {
+               .name = "hv",
+               .owner = THIS_MODULE,
+               .of_match_table = hv_match,
+       },
+       .probe          = hv_probe,
+       .remove         = __devexit_p(hv_remove),
+};
+
+static int __init sunhv_init(void)
+{
+       if (tlb_type != hypervisor)
+               return -ENODEV;
+
+       return of_register_platform_driver(&hv_driver);
+}
+
+static void __exit sunhv_exit(void)
+{
+       of_unregister_platform_driver(&hv_driver);
+}
+
+module_init(sunhv_init);
+module_exit(sunhv_exit);
+
+MODULE_AUTHOR("David S. Miller");
+MODULE_DESCRIPTION("SUN4V Hypervisor console driver");
+MODULE_VERSION("2.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c
new file mode 100644 (file)
index 0000000..5b246b1
--- /dev/null
@@ -0,0 +1,1152 @@
+/* sunsab.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
+ *
+ * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
+ * Copyright (C) 2002, 2006  David S. Miller (davem@davemloft.net)
+ *
+ * Rewrote buffer handling to use CIRC(Circular Buffer) macros.
+ *   Maxim Krasnyanskiy <maxk@qualcomm.com>
+ *
+ * Fixed to use tty_get_baud_rate, and to allow for arbitrary baud
+ * rates to be programmed into the UART.  Also eliminated a lot of
+ * duplicated code in the console setup.
+ *   Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12
+ *
+ * Ported to new 2.5.x UART layer.
+ *   David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/of_device.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+
+#if defined(CONFIG_SERIAL_SUNSAB_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#include "suncore.h"
+#include "sunsab.h"
+
+struct uart_sunsab_port {
+       struct uart_port                port;           /* Generic UART port    */
+       union sab82532_async_regs       __iomem *regs;  /* Chip registers       */
+       unsigned long                   irqflags;       /* IRQ state flags      */
+       int                             dsr;            /* Current DSR state    */
+       unsigned int                    cec_timeout;    /* Chip poll timeout... */
+       unsigned int                    tec_timeout;    /* likewise             */
+       unsigned char                   interrupt_mask0;/* ISR0 masking         */
+       unsigned char                   interrupt_mask1;/* ISR1 masking         */
+       unsigned char                   pvr_dtr_bit;    /* Which PVR bit is DTR */
+       unsigned char                   pvr_dsr_bit;    /* Which PVR bit is DSR */
+       unsigned int                    gis_shift;
+       int                             type;           /* SAB82532 version     */
+
+       /* Setting configuration bits while the transmitter is active
+        * can cause garbage characters to get emitted by the chip.
+        * Therefore, we cache such writes here and do the real register
+        * write the next time the transmitter becomes idle.
+        */
+       unsigned int                    cached_ebrg;
+       unsigned char                   cached_mode;
+       unsigned char                   cached_pvr;
+       unsigned char                   cached_dafo;
+};
+
+/*
+ * This assumes you have a 29.4912 MHz clock for your UART.
+ */
+#define SAB_BASE_BAUD ( 29491200 / 16 )
+
+static char *sab82532_version[16] = {
+       "V1.0", "V2.0", "V3.2", "V(0x03)",
+       "V(0x04)", "V(0x05)", "V(0x06)", "V(0x07)",
+       "V(0x08)", "V(0x09)", "V(0x0a)", "V(0x0b)",
+       "V(0x0c)", "V(0x0d)", "V(0x0e)", "V(0x0f)"
+};
+
+#define SAB82532_MAX_TEC_TIMEOUT 200000        /* 1 character time (at 50 baud) */
+#define SAB82532_MAX_CEC_TIMEOUT  50000        /* 2.5 TX CLKs (at 50 baud) */
+
+#define SAB82532_RECV_FIFO_SIZE        32      /* Standard async fifo sizes */
+#define SAB82532_XMIT_FIFO_SIZE        32
+
+static __inline__ void sunsab_tec_wait(struct uart_sunsab_port *up)
+{
+       int timeout = up->tec_timeout;
+
+       while ((readb(&up->regs->r.star) & SAB82532_STAR_TEC) && --timeout)
+               udelay(1);
+}
+
+static __inline__ void sunsab_cec_wait(struct uart_sunsab_port *up)
+{
+       int timeout = up->cec_timeout;
+
+       while ((readb(&up->regs->r.star) & SAB82532_STAR_CEC) && --timeout)
+               udelay(1);
+}
+
+static struct tty_struct *
+receive_chars(struct uart_sunsab_port *up,
+             union sab82532_irq_status *stat)
+{
+       struct tty_struct *tty = NULL;
+       unsigned char buf[32];
+       int saw_console_brk = 0;
+       int free_fifo = 0;
+       int count = 0;
+       int i;
+
+       if (up->port.state != NULL)             /* Unopened serial console */
+               tty = up->port.state->port.tty;
+
+       /* Read number of BYTES (Character + Status) available. */
+       if (stat->sreg.isr0 & SAB82532_ISR0_RPF) {
+               count = SAB82532_RECV_FIFO_SIZE;
+               free_fifo++;
+       }
+
+       if (stat->sreg.isr0 & SAB82532_ISR0_TCD) {
+               count = readb(&up->regs->r.rbcl) & (SAB82532_RECV_FIFO_SIZE - 1);
+               free_fifo++;
+       }
+
+       /* Issue a FIFO read command in case we where idle. */
+       if (stat->sreg.isr0 & SAB82532_ISR0_TIME) {
+               sunsab_cec_wait(up);
+               writeb(SAB82532_CMDR_RFRD, &up->regs->w.cmdr);
+               return tty;
+       }
+
+       if (stat->sreg.isr0 & SAB82532_ISR0_RFO)
+               free_fifo++;
+
+       /* Read the FIFO. */
+       for (i = 0; i < count; i++)
+               buf[i] = readb(&up->regs->r.rfifo[i]);
+
+       /* Issue Receive Message Complete command. */
+       if (free_fifo) {
+               sunsab_cec_wait(up);
+               writeb(SAB82532_CMDR_RMC, &up->regs->w.cmdr);
+       }
+
+       /* Count may be zero for BRK, so we check for it here */
+       if ((stat->sreg.isr1 & SAB82532_ISR1_BRK) &&
+           (up->port.line == up->port.cons->index))
+               saw_console_brk = 1;
+
+       for (i = 0; i < count; i++) {
+               unsigned char ch = buf[i], flag;
+
+               if (tty == NULL) {
+                       uart_handle_sysrq_char(&up->port, ch);
+                       continue;
+               }
+
+               flag = TTY_NORMAL;
+               up->port.icount.rx++;
+
+               if (unlikely(stat->sreg.isr0 & (SAB82532_ISR0_PERR |
+                                               SAB82532_ISR0_FERR |
+                                               SAB82532_ISR0_RFO)) ||
+                   unlikely(stat->sreg.isr1 & SAB82532_ISR1_BRK)) {
+                       /*
+                        * For statistics only
+                        */
+                       if (stat->sreg.isr1 & SAB82532_ISR1_BRK) {
+                               stat->sreg.isr0 &= ~(SAB82532_ISR0_PERR |
+                                                    SAB82532_ISR0_FERR);
+                               up->port.icount.brk++;
+                               /*
+                                * We do the SysRQ and SAK checking
+                                * here because otherwise the break
+                                * may get masked by ignore_status_mask
+                                * or read_status_mask.
+                                */
+                               if (uart_handle_break(&up->port))
+                                       continue;
+                       } else if (stat->sreg.isr0 & SAB82532_ISR0_PERR)
+                               up->port.icount.parity++;
+                       else if (stat->sreg.isr0 & SAB82532_ISR0_FERR)
+                               up->port.icount.frame++;
+                       if (stat->sreg.isr0 & SAB82532_ISR0_RFO)
+                               up->port.icount.overrun++;
+
+                       /*
+                        * Mask off conditions which should be ingored.
+                        */
+                       stat->sreg.isr0 &= (up->port.read_status_mask & 0xff);
+                       stat->sreg.isr1 &= ((up->port.read_status_mask >> 8) & 0xff);
+
+                       if (stat->sreg.isr1 & SAB82532_ISR1_BRK) {
+                               flag = TTY_BREAK;
+                       } else if (stat->sreg.isr0 & SAB82532_ISR0_PERR)
+                               flag = TTY_PARITY;
+                       else if (stat->sreg.isr0 & SAB82532_ISR0_FERR)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(&up->port, ch))
+                       continue;
+
+               if ((stat->sreg.isr0 & (up->port.ignore_status_mask & 0xff)) == 0 &&
+                   (stat->sreg.isr1 & ((up->port.ignore_status_mask >> 8) & 0xff)) == 0)
+                       tty_insert_flip_char(tty, ch, flag);
+               if (stat->sreg.isr0 & SAB82532_ISR0_RFO)
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+       }
+
+       if (saw_console_brk)
+               sun_do_break();
+
+       return tty;
+}
+
+static void sunsab_stop_tx(struct uart_port *);
+static void sunsab_tx_idle(struct uart_sunsab_port *);
+
+static void transmit_chars(struct uart_sunsab_port *up,
+                          union sab82532_irq_status *stat)
+{
+       struct circ_buf *xmit = &up->port.state->xmit;
+       int i;
+
+       if (stat->sreg.isr1 & SAB82532_ISR1_ALLS) {
+               up->interrupt_mask1 |= SAB82532_IMR1_ALLS;
+               writeb(up->interrupt_mask1, &up->regs->w.imr1);
+               set_bit(SAB82532_ALLS, &up->irqflags);
+       }
+
+#if 0 /* bde@nwlink.com says this check causes problems */
+       if (!(stat->sreg.isr1 & SAB82532_ISR1_XPR))
+               return;
+#endif
+
+       if (!(readb(&up->regs->r.star) & SAB82532_STAR_XFW))
+               return;
+
+       set_bit(SAB82532_XPR, &up->irqflags);
+       sunsab_tx_idle(up);
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+               up->interrupt_mask1 |= SAB82532_IMR1_XPR;
+               writeb(up->interrupt_mask1, &up->regs->w.imr1);
+               return;
+       }
+
+       up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR);
+       writeb(up->interrupt_mask1, &up->regs->w.imr1);
+       clear_bit(SAB82532_ALLS, &up->irqflags);
+
+       /* Stuff 32 bytes into Transmit FIFO. */
+       clear_bit(SAB82532_XPR, &up->irqflags);
+       for (i = 0; i < up->port.fifosize; i++) {
+               writeb(xmit->buf[xmit->tail],
+                      &up->regs->w.xfifo[i]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               up->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       }
+
+       /* Issue a Transmit Frame command. */
+       sunsab_cec_wait(up);
+       writeb(SAB82532_CMDR_XF, &up->regs->w.cmdr);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+       if (uart_circ_empty(xmit))
+               sunsab_stop_tx(&up->port);
+}
+
+static void check_status(struct uart_sunsab_port *up,
+                        union sab82532_irq_status *stat)
+{
+       if (stat->sreg.isr0 & SAB82532_ISR0_CDSC)
+               uart_handle_dcd_change(&up->port,
+                                      !(readb(&up->regs->r.vstr) & SAB82532_VSTR_CD));
+
+       if (stat->sreg.isr1 & SAB82532_ISR1_CSC)
+               uart_handle_cts_change(&up->port,
+                                      (readb(&up->regs->r.star) & SAB82532_STAR_CTS));
+
+       if ((readb(&up->regs->r.pvr) & up->pvr_dsr_bit) ^ up->dsr) {
+               up->dsr = (readb(&up->regs->r.pvr) & up->pvr_dsr_bit) ? 0 : 1;
+               up->port.icount.dsr++;
+       }
+
+       wake_up_interruptible(&up->port.state->port.delta_msr_wait);
+}
+
+static irqreturn_t sunsab_interrupt(int irq, void *dev_id)
+{
+       struct uart_sunsab_port *up = dev_id;
+       struct tty_struct *tty;
+       union sab82532_irq_status status;
+       unsigned long flags;
+       unsigned char gis;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       status.stat = 0;
+       gis = readb(&up->regs->r.gis) >> up->gis_shift;
+       if (gis & 1)
+               status.sreg.isr0 = readb(&up->regs->r.isr0);
+       if (gis & 2)
+               status.sreg.isr1 = readb(&up->regs->r.isr1);
+
+       tty = NULL;
+       if (status.stat) {
+               if ((status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME |
+                                        SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) ||
+                   (status.sreg.isr1 & SAB82532_ISR1_BRK))
+                       tty = receive_chars(up, &status);
+               if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) ||
+                   (status.sreg.isr1 & SAB82532_ISR1_CSC))
+                       check_status(up, &status);
+               if (status.sreg.isr1 & (SAB82532_ISR1_ALLS | SAB82532_ISR1_XPR))
+                       transmit_chars(up, &status);
+       }
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       if (tty)
+               tty_flip_buffer_push(tty);
+
+       return IRQ_HANDLED;
+}
+
+/* port->lock is not held.  */
+static unsigned int sunsab_tx_empty(struct uart_port *port)
+{
+       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
+       int ret;
+
+       /* Do not need a lock for a state test like this.  */
+       if (test_bit(SAB82532_ALLS, &up->irqflags))
+               ret = TIOCSER_TEMT;
+       else
+               ret = 0;
+
+       return ret;
+}
+
+/* port->lock held by caller.  */
+static void sunsab_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
+
+       if (mctrl & TIOCM_RTS) {
+               up->cached_mode &= ~SAB82532_MODE_FRTS;
+               up->cached_mode |= SAB82532_MODE_RTS;
+       } else {
+               up->cached_mode |= (SAB82532_MODE_FRTS |
+                                   SAB82532_MODE_RTS);
+       }
+       if (mctrl & TIOCM_DTR) {
+               up->cached_pvr &= ~(up->pvr_dtr_bit);
+       } else {
+               up->cached_pvr |= up->pvr_dtr_bit;
+       }
+
+       set_bit(SAB82532_REGS_PENDING, &up->irqflags);
+       if (test_bit(SAB82532_XPR, &up->irqflags))
+               sunsab_tx_idle(up);
+}
+
+/* port->lock is held by caller and interrupts are disabled.  */
+static unsigned int sunsab_get_mctrl(struct uart_port *port)
+{
+       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
+       unsigned char val;
+       unsigned int result;
+
+       result = 0;
+
+       val = readb(&up->regs->r.pvr);
+       result |= (val & up->pvr_dsr_bit) ? 0 : TIOCM_DSR;
+
+       val = readb(&up->regs->r.vstr);
+       result |= (val & SAB82532_VSTR_CD) ? 0 : TIOCM_CAR;
+
+       val = readb(&up->regs->r.star);
+       result |= (val & SAB82532_STAR_CTS) ? TIOCM_CTS : 0;
+
+       return result;
+}
+
+/* port->lock held by caller.  */
+static void sunsab_stop_tx(struct uart_port *port)
+{
+       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
+
+       up->interrupt_mask1 |= SAB82532_IMR1_XPR;
+       writeb(up->interrupt_mask1, &up->regs->w.imr1);
+}
+
+/* port->lock held by caller.  */
+static void sunsab_tx_idle(struct uart_sunsab_port *up)
+{
+       if (test_bit(SAB82532_REGS_PENDING, &up->irqflags)) {
+               u8 tmp;
+
+               clear_bit(SAB82532_REGS_PENDING, &up->irqflags);
+               writeb(up->cached_mode, &up->regs->rw.mode);
+               writeb(up->cached_pvr, &up->regs->rw.pvr);
+               writeb(up->cached_dafo, &up->regs->w.dafo);
+
+               writeb(up->cached_ebrg & 0xff, &up->regs->w.bgr);
+               tmp = readb(&up->regs->rw.ccr2);
+               tmp &= ~0xc0;
+               tmp |= (up->cached_ebrg >> 2) & 0xc0;
+               writeb(tmp, &up->regs->rw.ccr2);
+       }
+}
+
+/* port->lock held by caller.  */
+static void sunsab_start_tx(struct uart_port *port)
+{
+       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
+       struct circ_buf *xmit = &up->port.state->xmit;
+       int i;
+
+       up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR);
+       writeb(up->interrupt_mask1, &up->regs->w.imr1);
+       
+       if (!test_bit(SAB82532_XPR, &up->irqflags))
+               return;
+
+       clear_bit(SAB82532_ALLS, &up->irqflags);
+       clear_bit(SAB82532_XPR, &up->irqflags);
+
+       for (i = 0; i < up->port.fifosize; i++) {
+               writeb(xmit->buf[xmit->tail],
+                      &up->regs->w.xfifo[i]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               up->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       }
+
+       /* Issue a Transmit Frame command.  */
+       sunsab_cec_wait(up);
+       writeb(SAB82532_CMDR_XF, &up->regs->w.cmdr);
+}
+
+/* port->lock is not held.  */
+static void sunsab_send_xchar(struct uart_port *port, char ch)
+{
+       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       sunsab_tec_wait(up);
+       writeb(ch, &up->regs->w.tic);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+/* port->lock held by caller.  */
+static void sunsab_stop_rx(struct uart_port *port)
+{
+       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
+
+       up->interrupt_mask0 |= SAB82532_IMR0_TCD;
+       writeb(up->interrupt_mask1, &up->regs->w.imr0);
+}
+
+/* port->lock held by caller.  */
+static void sunsab_enable_ms(struct uart_port *port)
+{
+       /* For now we always receive these interrupts.  */
+}
+
+/* port->lock is not held.  */
+static void sunsab_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
+       unsigned long flags;
+       unsigned char val;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       val = up->cached_dafo;
+       if (break_state)
+               val |= SAB82532_DAFO_XBRK;
+       else
+               val &= ~SAB82532_DAFO_XBRK;
+       up->cached_dafo = val;
+
+       set_bit(SAB82532_REGS_PENDING, &up->irqflags);
+       if (test_bit(SAB82532_XPR, &up->irqflags))
+               sunsab_tx_idle(up);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+/* port->lock is not held.  */
+static int sunsab_startup(struct uart_port *port)
+{
+       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
+       unsigned long flags;
+       unsigned char tmp;
+       int err = request_irq(up->port.irq, sunsab_interrupt,
+                             IRQF_SHARED, "sab", up);
+       if (err)
+               return err;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       /*
+        * Wait for any commands or immediate characters
+        */
+       sunsab_cec_wait(up);
+       sunsab_tec_wait(up);
+
+       /*
+        * Clear the FIFO buffers.
+        */
+       writeb(SAB82532_CMDR_RRES, &up->regs->w.cmdr);
+       sunsab_cec_wait(up);
+       writeb(SAB82532_CMDR_XRES, &up->regs->w.cmdr);
+
+       /*
+        * Clear the interrupt registers.
+        */
+       (void) readb(&up->regs->r.isr0);
+       (void) readb(&up->regs->r.isr1);
+
+       /*
+        * Now, initialize the UART 
+        */
+       writeb(0, &up->regs->w.ccr0);                           /* power-down */
+       writeb(SAB82532_CCR0_MCE | SAB82532_CCR0_SC_NRZ |
+              SAB82532_CCR0_SM_ASYNC, &up->regs->w.ccr0);
+       writeb(SAB82532_CCR1_ODS | SAB82532_CCR1_BCR | 7, &up->regs->w.ccr1);
+       writeb(SAB82532_CCR2_BDF | SAB82532_CCR2_SSEL |
+              SAB82532_CCR2_TOE, &up->regs->w.ccr2);
+       writeb(0, &up->regs->w.ccr3);
+       writeb(SAB82532_CCR4_MCK4 | SAB82532_CCR4_EBRG, &up->regs->w.ccr4);
+       up->cached_mode = (SAB82532_MODE_RTS | SAB82532_MODE_FCTS |
+                          SAB82532_MODE_RAC);
+       writeb(up->cached_mode, &up->regs->w.mode);
+       writeb(SAB82532_RFC_DPS|SAB82532_RFC_RFTH_32, &up->regs->w.rfc);
+       
+       tmp = readb(&up->regs->rw.ccr0);
+       tmp |= SAB82532_CCR0_PU;        /* power-up */
+       writeb(tmp, &up->regs->rw.ccr0);
+
+       /*
+        * Finally, enable interrupts
+        */
+       up->interrupt_mask0 = (SAB82532_IMR0_PERR | SAB82532_IMR0_FERR |
+                              SAB82532_IMR0_PLLA);
+       writeb(up->interrupt_mask0, &up->regs->w.imr0);
+       up->interrupt_mask1 = (SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS |
+                              SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN |
+                              SAB82532_IMR1_CSC | SAB82532_IMR1_XON |
+                              SAB82532_IMR1_XPR);
+       writeb(up->interrupt_mask1, &up->regs->w.imr1);
+       set_bit(SAB82532_ALLS, &up->irqflags);
+       set_bit(SAB82532_XPR, &up->irqflags);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       return 0;
+}
+
+/* port->lock is not held.  */
+static void sunsab_shutdown(struct uart_port *port)
+{
+       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       /* Disable Interrupts */
+       up->interrupt_mask0 = 0xff;
+       writeb(up->interrupt_mask0, &up->regs->w.imr0);
+       up->interrupt_mask1 = 0xff;
+       writeb(up->interrupt_mask1, &up->regs->w.imr1);
+
+       /* Disable break condition */
+       up->cached_dafo = readb(&up->regs->rw.dafo);
+       up->cached_dafo &= ~SAB82532_DAFO_XBRK;
+       writeb(up->cached_dafo, &up->regs->rw.dafo);
+
+       /* Disable Receiver */  
+       up->cached_mode &= ~SAB82532_MODE_RAC;
+       writeb(up->cached_mode, &up->regs->rw.mode);
+
+       /*
+        * XXX FIXME
+        *
+        * If the chip is powered down here the system hangs/crashes during
+        * reboot or shutdown.  This needs to be investigated further,
+        * similar behaviour occurs in 2.4 when the driver is configured
+        * as a module only.  One hint may be that data is sometimes
+        * transmitted at 9600 baud during shutdown (regardless of the
+        * speed the chip was configured for when the port was open).
+        */
+#if 0
+       /* Power Down */        
+       tmp = readb(&up->regs->rw.ccr0);
+       tmp &= ~SAB82532_CCR0_PU;
+       writeb(tmp, &up->regs->rw.ccr0);
+#endif
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+       free_irq(up->port.irq, up);
+}
+
+/*
+ * This is used to figure out the divisor speeds.
+ *
+ * The formula is:    Baud = SAB_BASE_BAUD / ((N + 1) * (1 << M)),
+ *
+ * with               0 <= N < 64 and 0 <= M < 16
+ */
+
+static void calc_ebrg(int baud, int *n_ret, int *m_ret)
+{
+       int     n, m;
+
+       if (baud == 0) {
+               *n_ret = 0;
+               *m_ret = 0;
+               return;
+       }
+     
+       /*
+        * We scale numbers by 10 so that we get better accuracy
+        * without having to use floating point.  Here we increment m
+        * until n is within the valid range.
+        */
+       n = (SAB_BASE_BAUD * 10) / baud;
+       m = 0;
+       while (n >= 640) {
+               n = n / 2;
+               m++;
+       }
+       n = (n+5) / 10;
+       /*
+        * We try very hard to avoid speeds with M == 0 since they may
+        * not work correctly for XTAL frequences above 10 MHz.
+        */
+       if ((m == 0) && ((n & 1) == 0)) {
+               n = n / 2;
+               m++;
+       }
+       *n_ret = n - 1;
+       *m_ret = m;
+}
+
+/* Internal routine, port->lock is held and local interrupts are disabled.  */
+static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cflag,
+                                 unsigned int iflag, unsigned int baud,
+                                 unsigned int quot)
+{
+       unsigned char dafo;
+       int bits, n, m;
+
+       /* Byte size and parity */
+       switch (cflag & CSIZE) {
+             case CS5: dafo = SAB82532_DAFO_CHL5; bits = 7; break;
+             case CS6: dafo = SAB82532_DAFO_CHL6; bits = 8; break;
+             case CS7: dafo = SAB82532_DAFO_CHL7; bits = 9; break;
+             case CS8: dafo = SAB82532_DAFO_CHL8; bits = 10; break;
+             /* Never happens, but GCC is too dumb to figure it out */
+             default:  dafo = SAB82532_DAFO_CHL5; bits = 7; break;
+       }
+
+       if (cflag & CSTOPB) {
+               dafo |= SAB82532_DAFO_STOP;
+               bits++;
+       }
+
+       if (cflag & PARENB) {
+               dafo |= SAB82532_DAFO_PARE;
+               bits++;
+       }
+
+       if (cflag & PARODD) {
+               dafo |= SAB82532_DAFO_PAR_ODD;
+       } else {
+               dafo |= SAB82532_DAFO_PAR_EVEN;
+       }
+       up->cached_dafo = dafo;
+
+       calc_ebrg(baud, &n, &m);
+
+       up->cached_ebrg = n | (m << 6);
+
+       up->tec_timeout = (10 * 1000000) / baud;
+       up->cec_timeout = up->tec_timeout >> 2;
+
+       /* CTS flow control flags */
+       /* We encode read_status_mask and ignore_status_mask like so:
+        *
+        * ---------------------
+        * | ... | ISR1 | ISR0 |
+        * ---------------------
+        *  ..    15   8 7    0
+        */
+
+       up->port.read_status_mask = (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME |
+                                    SAB82532_ISR0_RFO | SAB82532_ISR0_RPF |
+                                    SAB82532_ISR0_CDSC);
+       up->port.read_status_mask |= (SAB82532_ISR1_CSC |
+                                     SAB82532_ISR1_ALLS |
+                                     SAB82532_ISR1_XPR) << 8;
+       if (iflag & INPCK)
+               up->port.read_status_mask |= (SAB82532_ISR0_PERR |
+                                             SAB82532_ISR0_FERR);
+       if (iflag & (BRKINT | PARMRK))
+               up->port.read_status_mask |= (SAB82532_ISR1_BRK << 8);
+
+       /*
+        * Characteres to ignore
+        */
+       up->port.ignore_status_mask = 0;
+       if (iflag & IGNPAR)
+               up->port.ignore_status_mask |= (SAB82532_ISR0_PERR |
+                                               SAB82532_ISR0_FERR);
+       if (iflag & IGNBRK) {
+               up->port.ignore_status_mask |= (SAB82532_ISR1_BRK << 8);
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (iflag & IGNPAR)
+                       up->port.ignore_status_mask |= SAB82532_ISR0_RFO;
+       }
+
+       /*
+        * ignore all characters if CREAD is not set
+        */
+       if ((cflag & CREAD) == 0)
+               up->port.ignore_status_mask |= (SAB82532_ISR0_RPF |
+                                               SAB82532_ISR0_TCD);
+
+       uart_update_timeout(&up->port, cflag,
+                           (up->port.uartclk / (16 * quot)));
+
+       /* Now schedule a register update when the chip's
+        * transmitter is idle.
+        */
+       up->cached_mode |= SAB82532_MODE_RAC;
+       set_bit(SAB82532_REGS_PENDING, &up->irqflags);
+       if (test_bit(SAB82532_XPR, &up->irqflags))
+               sunsab_tx_idle(up);
+}
+
+/* port->lock is not held.  */
+static void sunsab_set_termios(struct uart_port *port, struct ktermios *termios,
+                              struct ktermios *old)
+{
+       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
+       unsigned long flags;
+       unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
+       unsigned int quot = uart_get_divisor(port, baud);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       sunsab_convert_to_sab(up, termios->c_cflag, termios->c_iflag, baud, quot);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static const char *sunsab_type(struct uart_port *port)
+{
+       struct uart_sunsab_port *up = (void *)port;
+       static char buf[36];
+       
+       sprintf(buf, "SAB82532 %s", sab82532_version[up->type]);
+       return buf;
+}
+
+static void sunsab_release_port(struct uart_port *port)
+{
+}
+
+static int sunsab_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static void sunsab_config_port(struct uart_port *port, int flags)
+{
+}
+
+static int sunsab_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       return -EINVAL;
+}
+
+static struct uart_ops sunsab_pops = {
+       .tx_empty       = sunsab_tx_empty,
+       .set_mctrl      = sunsab_set_mctrl,
+       .get_mctrl      = sunsab_get_mctrl,
+       .stop_tx        = sunsab_stop_tx,
+       .start_tx       = sunsab_start_tx,
+       .send_xchar     = sunsab_send_xchar,
+       .stop_rx        = sunsab_stop_rx,
+       .enable_ms      = sunsab_enable_ms,
+       .break_ctl      = sunsab_break_ctl,
+       .startup        = sunsab_startup,
+       .shutdown       = sunsab_shutdown,
+       .set_termios    = sunsab_set_termios,
+       .type           = sunsab_type,
+       .release_port   = sunsab_release_port,
+       .request_port   = sunsab_request_port,
+       .config_port    = sunsab_config_port,
+       .verify_port    = sunsab_verify_port,
+};
+
+static struct uart_driver sunsab_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "sunsab",
+       .dev_name               = "ttyS",
+       .major                  = TTY_MAJOR,
+};
+
+static struct uart_sunsab_port *sunsab_ports;
+
+#ifdef CONFIG_SERIAL_SUNSAB_CONSOLE
+
+static void sunsab_console_putchar(struct uart_port *port, int c)
+{
+       struct uart_sunsab_port *up = (struct uart_sunsab_port *)port;
+
+       sunsab_tec_wait(up);
+       writeb(c, &up->regs->w.tic);
+}
+
+static void sunsab_console_write(struct console *con, const char *s, unsigned n)
+{
+       struct uart_sunsab_port *up = &sunsab_ports[con->index];
+       unsigned long flags;
+       int locked = 1;
+
+       local_irq_save(flags);
+       if (up->port.sysrq) {
+               locked = 0;
+       } else if (oops_in_progress) {
+               locked = spin_trylock(&up->port.lock);
+       } else
+               spin_lock(&up->port.lock);
+
+       uart_console_write(&up->port, s, n, sunsab_console_putchar);
+       sunsab_tec_wait(up);
+
+       if (locked)
+               spin_unlock(&up->port.lock);
+       local_irq_restore(flags);
+}
+
+static int sunsab_console_setup(struct console *con, char *options)
+{
+       struct uart_sunsab_port *up = &sunsab_ports[con->index];
+       unsigned long flags;
+       unsigned int baud, quot;
+
+       /*
+        * The console framework calls us for each and every port
+        * registered. Defer the console setup until the requested
+        * port has been properly discovered. A bit of a hack,
+        * though...
+        */
+       if (up->port.type != PORT_SUNSAB)
+               return -1;
+
+       printk("Console: ttyS%d (SAB82532)\n",
+              (sunsab_reg.minor - 64) + con->index);
+
+       sunserial_console_termios(con, up->port.dev->of_node);
+
+       switch (con->cflag & CBAUD) {
+       case B150: baud = 150; break;
+       case B300: baud = 300; break;
+       case B600: baud = 600; break;
+       case B1200: baud = 1200; break;
+       case B2400: baud = 2400; break;
+       case B4800: baud = 4800; break;
+       default: case B9600: baud = 9600; break;
+       case B19200: baud = 19200; break;
+       case B38400: baud = 38400; break;
+       case B57600: baud = 57600; break;
+       case B115200: baud = 115200; break;
+       case B230400: baud = 230400; break;
+       case B460800: baud = 460800; break;
+       };
+
+       /*
+        * Temporary fix.
+        */
+       spin_lock_init(&up->port.lock);
+
+       /*
+        * Initialize the hardware
+        */
+       sunsab_startup(&up->port);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       /*
+        * Finally, enable interrupts
+        */
+       up->interrupt_mask0 = SAB82532_IMR0_PERR | SAB82532_IMR0_FERR |
+                               SAB82532_IMR0_PLLA | SAB82532_IMR0_CDSC;
+       writeb(up->interrupt_mask0, &up->regs->w.imr0);
+       up->interrupt_mask1 = SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS |
+                               SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN |
+                               SAB82532_IMR1_CSC | SAB82532_IMR1_XON |
+                               SAB82532_IMR1_XPR;
+       writeb(up->interrupt_mask1, &up->regs->w.imr1);
+
+       quot = uart_get_divisor(&up->port, baud);
+       sunsab_convert_to_sab(up, con->cflag, 0, baud, quot);
+       sunsab_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+       
+       return 0;
+}
+
+static struct console sunsab_console = {
+       .name   =       "ttyS",
+       .write  =       sunsab_console_write,
+       .device =       uart_console_device,
+       .setup  =       sunsab_console_setup,
+       .flags  =       CON_PRINTBUFFER,
+       .index  =       -1,
+       .data   =       &sunsab_reg,
+};
+
+static inline struct console *SUNSAB_CONSOLE(void)
+{
+       return &sunsab_console;
+}
+#else
+#define SUNSAB_CONSOLE()       (NULL)
+#define sunsab_console_init()  do { } while (0)
+#endif
+
+static int __devinit sunsab_init_one(struct uart_sunsab_port *up,
+                                    struct platform_device *op,
+                                    unsigned long offset,
+                                    int line)
+{
+       up->port.line = line;
+       up->port.dev = &op->dev;
+
+       up->port.mapbase = op->resource[0].start + offset;
+       up->port.membase = of_ioremap(&op->resource[0], offset,
+                                     sizeof(union sab82532_async_regs),
+                                     "sab");
+       if (!up->port.membase)
+               return -ENOMEM;
+       up->regs = (union sab82532_async_regs __iomem *) up->port.membase;
+
+       up->port.irq = op->archdata.irqs[0];
+
+       up->port.fifosize = SAB82532_XMIT_FIFO_SIZE;
+       up->port.iotype = UPIO_MEM;
+
+       writeb(SAB82532_IPC_IC_ACT_LOW, &up->regs->w.ipc);
+
+       up->port.ops = &sunsab_pops;
+       up->port.type = PORT_SUNSAB;
+       up->port.uartclk = SAB_BASE_BAUD;
+
+       up->type = readb(&up->regs->r.vstr) & 0x0f;
+       writeb(~((1 << 1) | (1 << 2) | (1 << 4)), &up->regs->w.pcr);
+       writeb(0xff, &up->regs->w.pim);
+       if ((up->port.line & 0x1) == 0) {
+               up->pvr_dsr_bit = (1 << 0);
+               up->pvr_dtr_bit = (1 << 1);
+               up->gis_shift = 2;
+       } else {
+               up->pvr_dsr_bit = (1 << 3);
+               up->pvr_dtr_bit = (1 << 2);
+               up->gis_shift = 0;
+       }
+       up->cached_pvr = (1 << 1) | (1 << 2) | (1 << 4);
+       writeb(up->cached_pvr, &up->regs->w.pvr);
+       up->cached_mode = readb(&up->regs->rw.mode);
+       up->cached_mode |= SAB82532_MODE_FRTS;
+       writeb(up->cached_mode, &up->regs->rw.mode);
+       up->cached_mode |= SAB82532_MODE_RTS;
+       writeb(up->cached_mode, &up->regs->rw.mode);
+
+       up->tec_timeout = SAB82532_MAX_TEC_TIMEOUT;
+       up->cec_timeout = SAB82532_MAX_CEC_TIMEOUT;
+
+       return 0;
+}
+
+static int __devinit sab_probe(struct platform_device *op, const struct of_device_id *match)
+{
+       static int inst;
+       struct uart_sunsab_port *up;
+       int err;
+
+       up = &sunsab_ports[inst * 2];
+
+       err = sunsab_init_one(&up[0], op,
+                             0,
+                             (inst * 2) + 0);
+       if (err)
+               goto out;
+
+       err = sunsab_init_one(&up[1], op,
+                             sizeof(union sab82532_async_regs),
+                             (inst * 2) + 1);
+       if (err)
+               goto out1;
+
+       sunserial_console_match(SUNSAB_CONSOLE(), op->dev.of_node,
+                               &sunsab_reg, up[0].port.line,
+                               false);
+
+       sunserial_console_match(SUNSAB_CONSOLE(), op->dev.of_node,
+                               &sunsab_reg, up[1].port.line,
+                               false);
+
+       err = uart_add_one_port(&sunsab_reg, &up[0].port);
+       if (err)
+               goto out2;
+
+       err = uart_add_one_port(&sunsab_reg, &up[1].port);
+       if (err)
+               goto out3;
+
+       dev_set_drvdata(&op->dev, &up[0]);
+
+       inst++;
+
+       return 0;
+
+out3:
+       uart_remove_one_port(&sunsab_reg, &up[0].port);
+out2:
+       of_iounmap(&op->resource[0],
+                  up[1].port.membase,
+                  sizeof(union sab82532_async_regs));
+out1:
+       of_iounmap(&op->resource[0],
+                  up[0].port.membase,
+                  sizeof(union sab82532_async_regs));
+out:
+       return err;
+}
+
+static int __devexit sab_remove(struct platform_device *op)
+{
+       struct uart_sunsab_port *up = dev_get_drvdata(&op->dev);
+
+       uart_remove_one_port(&sunsab_reg, &up[1].port);
+       uart_remove_one_port(&sunsab_reg, &up[0].port);
+       of_iounmap(&op->resource[0],
+                  up[1].port.membase,
+                  sizeof(union sab82532_async_regs));
+       of_iounmap(&op->resource[0],
+                  up[0].port.membase,
+                  sizeof(union sab82532_async_regs));
+
+       dev_set_drvdata(&op->dev, NULL);
+
+       return 0;
+}
+
+static const struct of_device_id sab_match[] = {
+       {
+               .name = "se",
+       },
+       {
+               .name = "serial",
+               .compatible = "sab82532",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, sab_match);
+
+static struct of_platform_driver sab_driver = {
+       .driver = {
+               .name = "sab",
+               .owner = THIS_MODULE,
+               .of_match_table = sab_match,
+       },
+       .probe          = sab_probe,
+       .remove         = __devexit_p(sab_remove),
+};
+
+static int __init sunsab_init(void)
+{
+       struct device_node *dp;
+       int err;
+       int num_channels = 0;
+
+       for_each_node_by_name(dp, "se")
+               num_channels += 2;
+       for_each_node_by_name(dp, "serial") {
+               if (of_device_is_compatible(dp, "sab82532"))
+                       num_channels += 2;
+       }
+
+       if (num_channels) {
+               sunsab_ports = kzalloc(sizeof(struct uart_sunsab_port) *
+                                      num_channels, GFP_KERNEL);
+               if (!sunsab_ports)
+                       return -ENOMEM;
+
+               err = sunserial_register_minors(&sunsab_reg, num_channels);
+               if (err) {
+                       kfree(sunsab_ports);
+                       sunsab_ports = NULL;
+
+                       return err;
+               }
+       }
+
+       return of_register_platform_driver(&sab_driver);
+}
+
+static void __exit sunsab_exit(void)
+{
+       of_unregister_platform_driver(&sab_driver);
+       if (sunsab_reg.nr) {
+               sunserial_unregister_minors(&sunsab_reg, sunsab_reg.nr);
+       }
+
+       kfree(sunsab_ports);
+       sunsab_ports = NULL;
+}
+
+module_init(sunsab_init);
+module_exit(sunsab_exit);
+
+MODULE_AUTHOR("Eddie C. Dost and David S. Miller");
+MODULE_DESCRIPTION("Sun SAB82532 serial port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/sunsab.h b/drivers/tty/serial/sunsab.h
new file mode 100644 (file)
index 0000000..b78e1f7
--- /dev/null
@@ -0,0 +1,322 @@
+/* sunsab.h: Register Definitions for the Siemens SAB82532 DUSCC
+ *
+ * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
+ */
+
+#ifndef _SUNSAB_H
+#define _SUNSAB_H
+
+struct sab82532_async_rd_regs {
+       u8      rfifo[0x20];    /* Receive FIFO                         */
+       u8      star;           /* Status Register                      */
+       u8      __pad1;
+       u8      mode;           /* Mode Register                        */
+       u8      timr;           /* Timer Register                       */
+       u8      xon;            /* XON Character                        */
+       u8      xoff;           /* XOFF Character                       */
+       u8      tcr;            /* Termination Character Register       */
+       u8      dafo;           /* Data Format                          */
+       u8      rfc;            /* RFIFO Control Register               */
+       u8      __pad2;
+       u8      rbcl;           /* Receive Byte Count Low               */
+       u8      rbch;           /* Receive Byte Count High              */
+       u8      ccr0;           /* Channel Configuration Register 0     */
+       u8      ccr1;           /* Channel Configuration Register 1     */
+       u8      ccr2;           /* Channel Configuration Register 2     */
+       u8      ccr3;           /* Channel Configuration Register 3     */
+       u8      __pad3[4];
+       u8      vstr;           /* Version Status Register              */
+       u8      __pad4[3];
+       u8      gis;            /* Global Interrupt Status              */
+       u8      ipc;            /* Interrupt Port Configuration         */
+       u8      isr0;           /* Interrupt Status 0                   */
+       u8      isr1;           /* Interrupt Status 1                   */
+       u8      pvr;            /* Port Value Register                  */
+       u8      pis;            /* Port Interrupt Status                */
+       u8      pcr;            /* Port Configuration Register          */
+       u8      ccr4;           /* Channel Configuration Register 4     */
+};
+
+struct sab82532_async_wr_regs {
+       u8      xfifo[0x20];    /* Transmit FIFO                        */
+       u8      cmdr;           /* Command Register                     */
+       u8      __pad1;
+       u8      mode;
+       u8      timr;
+       u8      xon;
+       u8      xoff;
+       u8      tcr;
+       u8      dafo;
+       u8      rfc;
+       u8      __pad2;
+       u8      xbcl;           /* Transmit Byte Count Low              */
+       u8      xbch;           /* Transmit Byte Count High             */
+       u8      ccr0;
+       u8      ccr1;
+       u8      ccr2;
+       u8      ccr3;
+       u8      tsax;           /* Time-Slot Assignment Reg. Transmit   */
+       u8      tsar;           /* Time-Slot Assignment Reg. Receive    */
+       u8      xccr;           /* Transmit Channel Capacity Register   */
+       u8      rccr;           /* Receive Channel Capacity Register    */
+       u8      bgr;            /* Baud Rate Generator Register         */
+       u8      tic;            /* Transmit Immediate Character         */
+       u8      mxn;            /* Mask XON Character                   */
+       u8      mxf;            /* Mask XOFF Character                  */
+       u8      iva;            /* Interrupt Vector Address             */
+       u8      ipc;
+       u8      imr0;           /* Interrupt Mask Register 0            */
+       u8      imr1;           /* Interrupt Mask Register 1            */
+       u8      pvr;
+       u8      pim;            /* Port Interrupt Mask                  */
+       u8      pcr;
+       u8      ccr4;
+};
+
+struct sab82532_async_rw_regs {        /* Read/Write registers                 */
+       u8      __pad1[0x20];
+       u8      __pad2;
+       u8      __pad3;
+       u8      mode;
+       u8      timr;
+       u8      xon;
+       u8      xoff;
+       u8      tcr;
+       u8      dafo;
+       u8      rfc;
+       u8      __pad4;
+       u8      __pad5;
+       u8      __pad6;
+       u8      ccr0;
+       u8      ccr1;
+       u8      ccr2;
+       u8      ccr3;
+       u8      __pad7;
+       u8      __pad8;
+       u8      __pad9;
+       u8      __pad10;
+       u8      __pad11;
+       u8      __pad12;
+       u8      __pad13;
+       u8      __pad14;
+       u8      __pad15;
+       u8      ipc;
+       u8      __pad16;
+       u8      __pad17;
+       u8      pvr;
+       u8      __pad18;
+       u8      pcr;
+       u8      ccr4;
+};
+
+union sab82532_async_regs {
+       __volatile__ struct sab82532_async_rd_regs      r;
+       __volatile__ struct sab82532_async_wr_regs      w;
+       __volatile__ struct sab82532_async_rw_regs      rw;
+};
+
+union sab82532_irq_status {
+       unsigned short                   stat;
+       struct {
+               unsigned char            isr0;
+               unsigned char            isr1;
+       } sreg;
+};
+
+/* irqflags bits */
+#define SAB82532_ALLS                  0x00000001
+#define SAB82532_XPR                   0x00000002
+#define SAB82532_REGS_PENDING          0x00000004
+
+/* RFIFO Status Byte */
+#define SAB82532_RSTAT_PE              0x80
+#define SAB82532_RSTAT_FE              0x40
+#define SAB82532_RSTAT_PARITY          0x01
+
+/* Status Register (STAR) */
+#define SAB82532_STAR_XDOV             0x80
+#define SAB82532_STAR_XFW              0x40
+#define SAB82532_STAR_RFNE             0x20
+#define SAB82532_STAR_FCS              0x10
+#define SAB82532_STAR_TEC              0x08
+#define SAB82532_STAR_CEC              0x04
+#define SAB82532_STAR_CTS              0x02
+
+/* Command Register (CMDR) */
+#define SAB82532_CMDR_RMC              0x80
+#define SAB82532_CMDR_RRES             0x40
+#define SAB82532_CMDR_RFRD             0x20
+#define SAB82532_CMDR_STI              0x10
+#define SAB82532_CMDR_XF               0x08
+#define SAB82532_CMDR_XRES             0x01
+
+/* Mode Register (MODE) */
+#define SAB82532_MODE_FRTS             0x40
+#define SAB82532_MODE_FCTS             0x20
+#define SAB82532_MODE_FLON             0x10
+#define SAB82532_MODE_RAC              0x08
+#define SAB82532_MODE_RTS              0x04
+#define SAB82532_MODE_TRS              0x02
+#define SAB82532_MODE_TLP              0x01
+
+/* Timer Register (TIMR) */
+#define SAB82532_TIMR_CNT_MASK         0xe0
+#define SAB82532_TIMR_VALUE_MASK       0x1f
+
+/* Data Format (DAFO) */
+#define SAB82532_DAFO_XBRK             0x40
+#define SAB82532_DAFO_STOP             0x20
+#define SAB82532_DAFO_PAR_SPACE                0x00
+#define SAB82532_DAFO_PAR_ODD          0x08
+#define SAB82532_DAFO_PAR_EVEN         0x10
+#define SAB82532_DAFO_PAR_MARK         0x18
+#define SAB82532_DAFO_PARE             0x04
+#define SAB82532_DAFO_CHL8             0x00
+#define SAB82532_DAFO_CHL7             0x01
+#define SAB82532_DAFO_CHL6             0x02
+#define SAB82532_DAFO_CHL5             0x03
+
+/* RFIFO Control Register (RFC) */
+#define SAB82532_RFC_DPS               0x40
+#define SAB82532_RFC_DXS               0x20
+#define SAB82532_RFC_RFDF              0x10
+#define SAB82532_RFC_RFTH_1            0x00
+#define SAB82532_RFC_RFTH_4            0x04
+#define SAB82532_RFC_RFTH_16           0x08
+#define SAB82532_RFC_RFTH_32           0x0c
+#define SAB82532_RFC_TCDE              0x01
+
+/* Received Byte Count High (RBCH) */
+#define SAB82532_RBCH_DMA              0x80
+#define SAB82532_RBCH_CAS              0x20
+
+/* Transmit Byte Count High (XBCH) */
+#define SAB82532_XBCH_DMA              0x80
+#define SAB82532_XBCH_CAS              0x20
+#define SAB82532_XBCH_XC               0x10
+
+/* Channel Configuration Register 0 (CCR0) */
+#define SAB82532_CCR0_PU               0x80
+#define SAB82532_CCR0_MCE              0x40
+#define SAB82532_CCR0_SC_NRZ           0x00
+#define SAB82532_CCR0_SC_NRZI          0x08
+#define SAB82532_CCR0_SC_FM0           0x10
+#define SAB82532_CCR0_SC_FM1           0x14
+#define SAB82532_CCR0_SC_MANCH         0x18
+#define SAB82532_CCR0_SM_HDLC          0x00
+#define SAB82532_CCR0_SM_SDLC_LOOP     0x01
+#define SAB82532_CCR0_SM_BISYNC                0x02
+#define SAB82532_CCR0_SM_ASYNC         0x03
+
+/* Channel Configuration Register 1 (CCR1) */
+#define SAB82532_CCR1_ODS              0x10
+#define SAB82532_CCR1_BCR              0x08
+#define SAB82532_CCR1_CM_MASK          0x07
+
+/* Channel Configuration Register 2 (CCR2) */
+#define SAB82532_CCR2_SOC1             0x80
+#define SAB82532_CCR2_SOC0             0x40
+#define SAB82532_CCR2_BR9              0x80
+#define SAB82532_CCR2_BR8              0x40
+#define SAB82532_CCR2_BDF              0x20
+#define SAB82532_CCR2_SSEL             0x10
+#define SAB82532_CCR2_XCS0             0x20
+#define SAB82532_CCR2_RCS0             0x10
+#define SAB82532_CCR2_TOE              0x08
+#define SAB82532_CCR2_RWX              0x04
+#define SAB82532_CCR2_DIV              0x01
+
+/* Channel Configuration Register 3 (CCR3) */
+#define SAB82532_CCR3_PSD              0x01
+
+/* Time Slot Assignment Register Transmit (TSAX) */
+#define SAB82532_TSAX_TSNX_MASK                0xfc
+#define SAB82532_TSAX_XCS2             0x02    /* see also CCR2 */
+#define SAB82532_TSAX_XCS1             0x01
+
+/* Time Slot Assignment Register Receive (TSAR) */
+#define SAB82532_TSAR_TSNR_MASK                0xfc
+#define SAB82532_TSAR_RCS2             0x02    /* see also CCR2 */
+#define SAB82532_TSAR_RCS1             0x01
+
+/* Version Status Register (VSTR) */
+#define SAB82532_VSTR_CD               0x80
+#define SAB82532_VSTR_DPLA             0x40
+#define SAB82532_VSTR_VN_MASK          0x0f
+#define SAB82532_VSTR_VN_1             0x00
+#define SAB82532_VSTR_VN_2             0x01
+#define SAB82532_VSTR_VN_3_2           0x02
+
+/* Global Interrupt Status Register (GIS) */
+#define SAB82532_GIS_PI                        0x80
+#define SAB82532_GIS_ISA1              0x08
+#define SAB82532_GIS_ISA0              0x04
+#define SAB82532_GIS_ISB1              0x02
+#define SAB82532_GIS_ISB0              0x01
+
+/* Interrupt Vector Address (IVA) */
+#define SAB82532_IVA_MASK              0xf1
+
+/* Interrupt Port Configuration (IPC) */
+#define SAB82532_IPC_VIS               0x80
+#define SAB82532_IPC_SLA1              0x10
+#define SAB82532_IPC_SLA0              0x08
+#define SAB82532_IPC_CASM              0x04
+#define SAB82532_IPC_IC_OPEN_DRAIN     0x00
+#define SAB82532_IPC_IC_ACT_LOW                0x01
+#define SAB82532_IPC_IC_ACT_HIGH       0x03
+
+/* Interrupt Status Register 0 (ISR0) */
+#define SAB82532_ISR0_TCD              0x80
+#define SAB82532_ISR0_TIME             0x40
+#define SAB82532_ISR0_PERR             0x20
+#define SAB82532_ISR0_FERR             0x10
+#define SAB82532_ISR0_PLLA             0x08
+#define SAB82532_ISR0_CDSC             0x04
+#define SAB82532_ISR0_RFO              0x02
+#define SAB82532_ISR0_RPF              0x01
+
+/* Interrupt Status Register 1 (ISR1) */
+#define SAB82532_ISR1_BRK              0x80
+#define SAB82532_ISR1_BRKT             0x40
+#define SAB82532_ISR1_ALLS             0x20
+#define SAB82532_ISR1_XOFF             0x10
+#define SAB82532_ISR1_TIN              0x08
+#define SAB82532_ISR1_CSC              0x04
+#define SAB82532_ISR1_XON              0x02
+#define SAB82532_ISR1_XPR              0x01
+
+/* Interrupt Mask Register 0 (IMR0) */
+#define SAB82532_IMR0_TCD              0x80
+#define SAB82532_IMR0_TIME             0x40
+#define SAB82532_IMR0_PERR             0x20
+#define SAB82532_IMR0_FERR             0x10
+#define SAB82532_IMR0_PLLA             0x08
+#define SAB82532_IMR0_CDSC             0x04
+#define SAB82532_IMR0_RFO              0x02
+#define SAB82532_IMR0_RPF              0x01
+
+/* Interrupt Mask Register 1 (IMR1) */
+#define SAB82532_IMR1_BRK              0x80
+#define SAB82532_IMR1_BRKT             0x40
+#define SAB82532_IMR1_ALLS             0x20
+#define SAB82532_IMR1_XOFF             0x10
+#define SAB82532_IMR1_TIN              0x08
+#define SAB82532_IMR1_CSC              0x04
+#define SAB82532_IMR1_XON              0x02
+#define SAB82532_IMR1_XPR              0x01
+
+/* Port Interrupt Status Register (PIS) */
+#define SAB82532_PIS_SYNC_B            0x08
+#define SAB82532_PIS_DTR_B             0x04
+#define SAB82532_PIS_DTR_A             0x02
+#define SAB82532_PIS_SYNC_A            0x01
+
+/* Channel Configuration Register 4 (CCR4) */
+#define SAB82532_CCR4_MCK4             0x80
+#define SAB82532_CCR4_EBRG             0x40
+#define SAB82532_CCR4_TST1             0x20
+#define SAB82532_CCR4_ICD              0x10
+
+
+#endif /* !(_SUNSAB_H) */
diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c
new file mode 100644 (file)
index 0000000..551ebfe
--- /dev/null
@@ -0,0 +1,1608 @@
+/*
+ * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
+ *
+ * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
+ * Copyright (C) 1998-1999  Pete Zaitcev   (zaitcev@yahoo.com)
+ *
+ * This is mainly a variation of 8250.c, credits go to authors mentioned
+ * therein.  In fact this driver should be merged into the generic 8250.c
+ * infrastructure perhaps using a 8250_sparc.c module.
+ *
+ * Fixed to use tty_get_baud_rate().
+ *   Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12
+ *
+ * Converted to new 2.5.x UART layer.
+ *   David S. Miller (davem@davemloft.net), 2002-Jul-29
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <linux/slab.h>
+#ifdef CONFIG_SERIO
+#include <linux/serio.h>
+#endif
+#include <linux/serial_reg.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+
+#if defined(CONFIG_SERIAL_SUNSU_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#include "suncore.h"
+
+/* We are on a NS PC87303 clocked with 24.0 MHz, which results
+ * in a UART clock of 1.8462 MHz.
+ */
+#define SU_BASE_BAUD   (1846200 / 16)
+
+enum su_type { SU_PORT_NONE, SU_PORT_MS, SU_PORT_KBD, SU_PORT_PORT };
+static char *su_typev[] = { "su(???)", "su(mouse)", "su(kbd)", "su(serial)" };
+
+/*
+ * Here we define the default xmit fifo size used for each type of UART.
+ */
+static const struct serial_uart_config uart_config[PORT_MAX_8250+1] = {
+       { "unknown",    1,      0 },
+       { "8250",       1,      0 },
+       { "16450",      1,      0 },
+       { "16550",      1,      0 },
+       { "16550A",     16,     UART_CLEAR_FIFO | UART_USE_FIFO },
+       { "Cirrus",     1,      0 },
+       { "ST16650",    1,      UART_CLEAR_FIFO | UART_STARTECH },
+       { "ST16650V2",  32,     UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
+       { "TI16750",    64,     UART_CLEAR_FIFO | UART_USE_FIFO },
+       { "Startech",   1,      0 },
+       { "16C950/954", 128,    UART_CLEAR_FIFO | UART_USE_FIFO },
+       { "ST16654",    64,     UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
+       { "XR16850",    128,    UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
+       { "RSA",        2048,   UART_CLEAR_FIFO | UART_USE_FIFO }
+};
+
+struct uart_sunsu_port {
+       struct uart_port        port;
+       unsigned char           acr;
+       unsigned char           ier;
+       unsigned short          rev;
+       unsigned char           lcr;
+       unsigned int            lsr_break_flag;
+       unsigned int            cflag;
+
+       /* Probing information.  */
+       enum su_type            su_type;
+       unsigned int            type_probed;    /* XXX Stupid */
+       unsigned long           reg_size;
+
+#ifdef CONFIG_SERIO
+       struct serio            serio;
+       int                     serio_open;
+#endif
+};
+
+static unsigned int serial_in(struct uart_sunsu_port *up, int offset)
+{
+       offset <<= up->port.regshift;
+
+       switch (up->port.iotype) {
+       case UPIO_HUB6:
+               outb(up->port.hub6 - 1 + offset, up->port.iobase);
+               return inb(up->port.iobase + 1);
+
+       case UPIO_MEM:
+               return readb(up->port.membase + offset);
+
+       default:
+               return inb(up->port.iobase + offset);
+       }
+}
+
+static void serial_out(struct uart_sunsu_port *up, int offset, int value)
+{
+#ifndef CONFIG_SPARC64
+       /*
+        * MrCoffee has weird schematics: IRQ4 & P10(?) pins of SuperIO are
+        * connected with a gate then go to SlavIO. When IRQ4 goes tristated
+        * gate outputs a logical one. Since we use level triggered interrupts
+        * we have lockup and watchdog reset. We cannot mask IRQ because
+        * keyboard shares IRQ with us (Word has it as Bob Smelik's design).
+        * This problem is similar to what Alpha people suffer, see serial.c.
+        */
+       if (offset == UART_MCR)
+               value |= UART_MCR_OUT2;
+#endif
+       offset <<= up->port.regshift;
+
+       switch (up->port.iotype) {
+       case UPIO_HUB6:
+               outb(up->port.hub6 - 1 + offset, up->port.iobase);
+               outb(value, up->port.iobase + 1);
+               break;
+
+       case UPIO_MEM:
+               writeb(value, up->port.membase + offset);
+               break;
+
+       default:
+               outb(value, up->port.iobase + offset);
+       }
+}
+
+/*
+ * We used to support using pause I/O for certain machines.  We
+ * haven't supported this for a while, but just in case it's badly
+ * needed for certain old 386 machines, I've left these #define's
+ * in....
+ */
+#define serial_inp(up, offset)         serial_in(up, offset)
+#define serial_outp(up, offset, value) serial_out(up, offset, value)
+
+
+/*
+ * For the 16C950
+ */
+static void serial_icr_write(struct uart_sunsu_port *up, int offset, int value)
+{
+       serial_out(up, UART_SCR, offset);
+       serial_out(up, UART_ICR, value);
+}
+
+#if 0 /* Unused currently */
+static unsigned int serial_icr_read(struct uart_sunsu_port *up, int offset)
+{
+       unsigned int value;
+
+       serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD);
+       serial_out(up, UART_SCR, offset);
+       value = serial_in(up, UART_ICR);
+       serial_icr_write(up, UART_ACR, up->acr);
+
+       return value;
+}
+#endif
+
+#ifdef CONFIG_SERIAL_8250_RSA
+/*
+ * Attempts to turn on the RSA FIFO.  Returns zero on failure.
+ * We set the port uart clock rate if we succeed.
+ */
+static int __enable_rsa(struct uart_sunsu_port *up)
+{
+       unsigned char mode;
+       int result;
+
+       mode = serial_inp(up, UART_RSA_MSR);
+       result = mode & UART_RSA_MSR_FIFO;
+
+       if (!result) {
+               serial_outp(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
+               mode = serial_inp(up, UART_RSA_MSR);
+               result = mode & UART_RSA_MSR_FIFO;
+       }
+
+       if (result)
+               up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16;
+
+       return result;
+}
+
+static void enable_rsa(struct uart_sunsu_port *up)
+{
+       if (up->port.type == PORT_RSA) {
+               if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) {
+                       spin_lock_irq(&up->port.lock);
+                       __enable_rsa(up);
+                       spin_unlock_irq(&up->port.lock);
+               }
+               if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16)
+                       serial_outp(up, UART_RSA_FRR, 0);
+       }
+}
+
+/*
+ * Attempts to turn off the RSA FIFO.  Returns zero on failure.
+ * It is unknown why interrupts were disabled in here.  However,
+ * the caller is expected to preserve this behaviour by grabbing
+ * the spinlock before calling this function.
+ */
+static void disable_rsa(struct uart_sunsu_port *up)
+{
+       unsigned char mode;
+       int result;
+
+       if (up->port.type == PORT_RSA &&
+           up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) {
+               spin_lock_irq(&up->port.lock);
+
+               mode = serial_inp(up, UART_RSA_MSR);
+               result = !(mode & UART_RSA_MSR_FIFO);
+
+               if (!result) {
+                       serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
+                       mode = serial_inp(up, UART_RSA_MSR);
+                       result = !(mode & UART_RSA_MSR_FIFO);
+               }
+
+               if (result)
+                       up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16;
+               spin_unlock_irq(&up->port.lock);
+       }
+}
+#endif /* CONFIG_SERIAL_8250_RSA */
+
+static inline void __stop_tx(struct uart_sunsu_port *p)
+{
+       if (p->ier & UART_IER_THRI) {
+               p->ier &= ~UART_IER_THRI;
+               serial_out(p, UART_IER, p->ier);
+       }
+}
+
+static void sunsu_stop_tx(struct uart_port *port)
+{
+       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
+
+       __stop_tx(up);
+
+       /*
+        * We really want to stop the transmitter from sending.
+        */
+       if (up->port.type == PORT_16C950) {
+               up->acr |= UART_ACR_TXDIS;
+               serial_icr_write(up, UART_ACR, up->acr);
+       }
+}
+
+static void sunsu_start_tx(struct uart_port *port)
+{
+       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
+
+       if (!(up->ier & UART_IER_THRI)) {
+               up->ier |= UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+       }
+
+       /*
+        * Re-enable the transmitter if we disabled it.
+        */
+       if (up->port.type == PORT_16C950 && up->acr & UART_ACR_TXDIS) {
+               up->acr &= ~UART_ACR_TXDIS;
+               serial_icr_write(up, UART_ACR, up->acr);
+       }
+}
+
+static void sunsu_stop_rx(struct uart_port *port)
+{
+       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
+
+       up->ier &= ~UART_IER_RLSI;
+       up->port.read_status_mask &= ~UART_LSR_DR;
+       serial_out(up, UART_IER, up->ier);
+}
+
+static void sunsu_enable_ms(struct uart_port *port)
+{
+       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       up->ier |= UART_IER_MSI;
+       serial_out(up, UART_IER, up->ier);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static struct tty_struct *
+receive_chars(struct uart_sunsu_port *up, unsigned char *status)
+{
+       struct tty_struct *tty = up->port.state->port.tty;
+       unsigned char ch, flag;
+       int max_count = 256;
+       int saw_console_brk = 0;
+
+       do {
+               ch = serial_inp(up, UART_RX);
+               flag = TTY_NORMAL;
+               up->port.icount.rx++;
+
+               if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
+                                      UART_LSR_FE | UART_LSR_OE))) {
+                       /*
+                        * For statistics only
+                        */
+                       if (*status & UART_LSR_BI) {
+                               *status &= ~(UART_LSR_FE | UART_LSR_PE);
+                               up->port.icount.brk++;
+                               if (up->port.cons != NULL &&
+                                   up->port.line == up->port.cons->index)
+                                       saw_console_brk = 1;
+                               /*
+                                * We do the SysRQ and SAK checking
+                                * here because otherwise the break
+                                * may get masked by ignore_status_mask
+                                * or read_status_mask.
+                                */
+                               if (uart_handle_break(&up->port))
+                                       goto ignore_char;
+                       } else if (*status & UART_LSR_PE)
+                               up->port.icount.parity++;
+                       else if (*status & UART_LSR_FE)
+                               up->port.icount.frame++;
+                       if (*status & UART_LSR_OE)
+                               up->port.icount.overrun++;
+
+                       /*
+                        * Mask off conditions which should be ingored.
+                        */
+                       *status &= up->port.read_status_mask;
+
+                       if (up->port.cons != NULL &&
+                           up->port.line == up->port.cons->index) {
+                               /* Recover the break flag from console xmit */
+                               *status |= up->lsr_break_flag;
+                               up->lsr_break_flag = 0;
+                       }
+
+                       if (*status & UART_LSR_BI) {
+                               flag = TTY_BREAK;
+                       } else if (*status & UART_LSR_PE)
+                               flag = TTY_PARITY;
+                       else if (*status & UART_LSR_FE)
+                               flag = TTY_FRAME;
+               }
+               if (uart_handle_sysrq_char(&up->port, ch))
+                       goto ignore_char;
+               if ((*status & up->port.ignore_status_mask) == 0)
+                       tty_insert_flip_char(tty, ch, flag);
+               if (*status & UART_LSR_OE)
+                       /*
+                        * Overrun is special, since it's reported
+                        * immediately, and doesn't affect the current
+                        * character.
+                        */
+                        tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+       ignore_char:
+               *status = serial_inp(up, UART_LSR);
+       } while ((*status & UART_LSR_DR) && (max_count-- > 0));
+
+       if (saw_console_brk)
+               sun_do_break();
+
+       return tty;
+}
+
+static void transmit_chars(struct uart_sunsu_port *up)
+{
+       struct circ_buf *xmit = &up->port.state->xmit;
+       int count;
+
+       if (up->port.x_char) {
+               serial_outp(up, UART_TX, up->port.x_char);
+               up->port.icount.tx++;
+               up->port.x_char = 0;
+               return;
+       }
+       if (uart_tx_stopped(&up->port)) {
+               sunsu_stop_tx(&up->port);
+               return;
+       }
+       if (uart_circ_empty(xmit)) {
+               __stop_tx(up);
+               return;
+       }
+
+       count = up->port.fifosize;
+       do {
+               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               up->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (--count > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+       if (uart_circ_empty(xmit))
+               __stop_tx(up);
+}
+
+static void check_modem_status(struct uart_sunsu_port *up)
+{
+       int status;
+
+       status = serial_in(up, UART_MSR);
+
+       if ((status & UART_MSR_ANY_DELTA) == 0)
+               return;
+
+       if (status & UART_MSR_TERI)
+               up->port.icount.rng++;
+       if (status & UART_MSR_DDSR)
+               up->port.icount.dsr++;
+       if (status & UART_MSR_DDCD)
+               uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
+       if (status & UART_MSR_DCTS)
+               uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
+
+       wake_up_interruptible(&up->port.state->port.delta_msr_wait);
+}
+
+static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id)
+{
+       struct uart_sunsu_port *up = dev_id;
+       unsigned long flags;
+       unsigned char status;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       do {
+               struct tty_struct *tty;
+
+               status = serial_inp(up, UART_LSR);
+               tty = NULL;
+               if (status & UART_LSR_DR)
+                       tty = receive_chars(up, &status);
+               check_modem_status(up);
+               if (status & UART_LSR_THRE)
+                       transmit_chars(up);
+
+               spin_unlock_irqrestore(&up->port.lock, flags);
+
+               if (tty)
+                       tty_flip_buffer_push(tty);
+
+               spin_lock_irqsave(&up->port.lock, flags);
+
+       } while (!(serial_in(up, UART_IIR) & UART_IIR_NO_INT));
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+/* Separate interrupt handling path for keyboard/mouse ports.  */
+
+static void
+sunsu_change_speed(struct uart_port *port, unsigned int cflag,
+                  unsigned int iflag, unsigned int quot);
+
+static void sunsu_change_mouse_baud(struct uart_sunsu_port *up)
+{
+       unsigned int cur_cflag = up->cflag;
+       int quot, new_baud;
+
+       up->cflag &= ~CBAUD;
+       up->cflag |= suncore_mouse_baud_cflag_next(cur_cflag, &new_baud);
+
+       quot = up->port.uartclk / (16 * new_baud);
+
+       sunsu_change_speed(&up->port, up->cflag, 0, quot);
+}
+
+static void receive_kbd_ms_chars(struct uart_sunsu_port *up, int is_break)
+{
+       do {
+               unsigned char ch = serial_inp(up, UART_RX);
+
+               /* Stop-A is handled by drivers/char/keyboard.c now. */
+               if (up->su_type == SU_PORT_KBD) {
+#ifdef CONFIG_SERIO
+                       serio_interrupt(&up->serio, ch, 0);
+#endif
+               } else if (up->su_type == SU_PORT_MS) {
+                       int ret = suncore_mouse_baud_detection(ch, is_break);
+
+                       switch (ret) {
+                       case 2:
+                               sunsu_change_mouse_baud(up);
+                               /* fallthru */
+                       case 1:
+                               break;
+
+                       case 0:
+#ifdef CONFIG_SERIO
+                               serio_interrupt(&up->serio, ch, 0);
+#endif
+                               break;
+                       };
+               }
+       } while (serial_in(up, UART_LSR) & UART_LSR_DR);
+}
+
+static irqreturn_t sunsu_kbd_ms_interrupt(int irq, void *dev_id)
+{
+       struct uart_sunsu_port *up = dev_id;
+
+       if (!(serial_in(up, UART_IIR) & UART_IIR_NO_INT)) {
+               unsigned char status = serial_inp(up, UART_LSR);
+
+               if ((status & UART_LSR_DR) || (status & UART_LSR_BI))
+                       receive_kbd_ms_chars(up, (status & UART_LSR_BI) != 0);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static unsigned int sunsu_tx_empty(struct uart_port *port)
+{
+       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
+       unsigned long flags;
+       unsigned int ret;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       return ret;
+}
+
+static unsigned int sunsu_get_mctrl(struct uart_port *port)
+{
+       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
+       unsigned char status;
+       unsigned int ret;
+
+       status = serial_in(up, UART_MSR);
+
+       ret = 0;
+       if (status & UART_MSR_DCD)
+               ret |= TIOCM_CAR;
+       if (status & UART_MSR_RI)
+               ret |= TIOCM_RNG;
+       if (status & UART_MSR_DSR)
+               ret |= TIOCM_DSR;
+       if (status & UART_MSR_CTS)
+               ret |= TIOCM_CTS;
+       return ret;
+}
+
+static void sunsu_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
+       unsigned char mcr = 0;
+
+       if (mctrl & TIOCM_RTS)
+               mcr |= UART_MCR_RTS;
+       if (mctrl & TIOCM_DTR)
+               mcr |= UART_MCR_DTR;
+       if (mctrl & TIOCM_OUT1)
+               mcr |= UART_MCR_OUT1;
+       if (mctrl & TIOCM_OUT2)
+               mcr |= UART_MCR_OUT2;
+       if (mctrl & TIOCM_LOOP)
+               mcr |= UART_MCR_LOOP;
+
+       serial_out(up, UART_MCR, mcr);
+}
+
+static void sunsu_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       if (break_state == -1)
+               up->lcr |= UART_LCR_SBC;
+       else
+               up->lcr &= ~UART_LCR_SBC;
+       serial_out(up, UART_LCR, up->lcr);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static int sunsu_startup(struct uart_port *port)
+{
+       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
+       unsigned long flags;
+       int retval;
+
+       if (up->port.type == PORT_16C950) {
+               /* Wake up and initialize UART */
+               up->acr = 0;
+               serial_outp(up, UART_LCR, 0xBF);
+               serial_outp(up, UART_EFR, UART_EFR_ECB);
+               serial_outp(up, UART_IER, 0);
+               serial_outp(up, UART_LCR, 0);
+               serial_icr_write(up, UART_CSR, 0); /* Reset the UART */
+               serial_outp(up, UART_LCR, 0xBF);
+               serial_outp(up, UART_EFR, UART_EFR_ECB);
+               serial_outp(up, UART_LCR, 0);
+       }
+
+#ifdef CONFIG_SERIAL_8250_RSA
+       /*
+        * If this is an RSA port, see if we can kick it up to the
+        * higher speed clock.
+        */
+       enable_rsa(up);
+#endif
+
+       /*
+        * Clear the FIFO buffers and disable them.
+        * (they will be reenabled in set_termios())
+        */
+       if (uart_config[up->port.type].flags & UART_CLEAR_FIFO) {
+               serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+               serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+                               UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+               serial_outp(up, UART_FCR, 0);
+       }
+
+       /*
+        * Clear the interrupt registers.
+        */
+       (void) serial_inp(up, UART_LSR);
+       (void) serial_inp(up, UART_RX);
+       (void) serial_inp(up, UART_IIR);
+       (void) serial_inp(up, UART_MSR);
+
+       /*
+        * At this point, there's no way the LSR could still be 0xff;
+        * if it is, then bail out, because there's likely no UART
+        * here.
+        */
+       if (!(up->port.flags & UPF_BUGGY_UART) &&
+           (serial_inp(up, UART_LSR) == 0xff)) {
+               printk("ttyS%d: LSR safety check engaged!\n", up->port.line);
+               return -ENODEV;
+       }
+
+       if (up->su_type != SU_PORT_PORT) {
+               retval = request_irq(up->port.irq, sunsu_kbd_ms_interrupt,
+                                    IRQF_SHARED, su_typev[up->su_type], up);
+       } else {
+               retval = request_irq(up->port.irq, sunsu_serial_interrupt,
+                                    IRQF_SHARED, su_typev[up->su_type], up);
+       }
+       if (retval) {
+               printk("su: Cannot register IRQ %d\n", up->port.irq);
+               return retval;
+       }
+
+       /*
+        * Now, initialize the UART
+        */
+       serial_outp(up, UART_LCR, UART_LCR_WLEN8);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       up->port.mctrl |= TIOCM_OUT2;
+
+       sunsu_set_mctrl(&up->port, up->port.mctrl);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       /*
+        * Finally, enable interrupts.  Note: Modem status interrupts
+        * are set via set_termios(), which will be occurring imminently
+        * anyway, so we don't enable them here.
+        */
+       up->ier = UART_IER_RLSI | UART_IER_RDI;
+       serial_outp(up, UART_IER, up->ier);
+
+       if (up->port.flags & UPF_FOURPORT) {
+               unsigned int icp;
+               /*
+                * Enable interrupts on the AST Fourport board
+                */
+               icp = (up->port.iobase & 0xfe0) | 0x01f;
+               outb_p(0x80, icp);
+               (void) inb_p(icp);
+       }
+
+       /*
+        * And clear the interrupt registers again for luck.
+        */
+       (void) serial_inp(up, UART_LSR);
+       (void) serial_inp(up, UART_RX);
+       (void) serial_inp(up, UART_IIR);
+       (void) serial_inp(up, UART_MSR);
+
+       return 0;
+}
+
+static void sunsu_shutdown(struct uart_port *port)
+{
+       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
+       unsigned long flags;
+
+       /*
+        * Disable interrupts from this port
+        */
+       up->ier = 0;
+       serial_outp(up, UART_IER, 0);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       if (up->port.flags & UPF_FOURPORT) {
+               /* reset interrupts on the AST Fourport board */
+               inb((up->port.iobase & 0xfe0) | 0x1f);
+               up->port.mctrl |= TIOCM_OUT1;
+       } else
+               up->port.mctrl &= ~TIOCM_OUT2;
+
+       sunsu_set_mctrl(&up->port, up->port.mctrl);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       /*
+        * Disable break condition and FIFOs
+        */
+       serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC);
+       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+                                 UART_FCR_CLEAR_RCVR |
+                                 UART_FCR_CLEAR_XMIT);
+       serial_outp(up, UART_FCR, 0);
+
+#ifdef CONFIG_SERIAL_8250_RSA
+       /*
+        * Reset the RSA board back to 115kbps compat mode.
+        */
+       disable_rsa(up);
+#endif
+
+       /*
+        * Read data port to reset things.
+        */
+       (void) serial_in(up, UART_RX);
+
+       free_irq(up->port.irq, up);
+}
+
+static void
+sunsu_change_speed(struct uart_port *port, unsigned int cflag,
+                  unsigned int iflag, unsigned int quot)
+{
+       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
+       unsigned char cval, fcr = 0;
+       unsigned long flags;
+
+       switch (cflag & CSIZE) {
+       case CS5:
+               cval = 0x00;
+               break;
+       case CS6:
+               cval = 0x01;
+               break;
+       case CS7:
+               cval = 0x02;
+               break;
+       default:
+       case CS8:
+               cval = 0x03;
+               break;
+       }
+
+       if (cflag & CSTOPB)
+               cval |= 0x04;
+       if (cflag & PARENB)
+               cval |= UART_LCR_PARITY;
+       if (!(cflag & PARODD))
+               cval |= UART_LCR_EPAR;
+#ifdef CMSPAR
+       if (cflag & CMSPAR)
+               cval |= UART_LCR_SPAR;
+#endif
+
+       /*
+        * Work around a bug in the Oxford Semiconductor 952 rev B
+        * chip which causes it to seriously miscalculate baud rates
+        * when DLL is 0.
+        */
+       if ((quot & 0xff) == 0 && up->port.type == PORT_16C950 &&
+           up->rev == 0x5201)
+               quot ++;
+
+       if (uart_config[up->port.type].flags & UART_USE_FIFO) {
+               if ((up->port.uartclk / quot) < (2400 * 16))
+                       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
+#ifdef CONFIG_SERIAL_8250_RSA
+               else if (up->port.type == PORT_RSA)
+                       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14;
+#endif
+               else
+                       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
+       }
+       if (up->port.type == PORT_16750)
+               fcr |= UART_FCR7_64BYTE;
+
+       /*
+        * Ok, we're now changing the port state.  Do it with
+        * interrupts disabled.
+        */
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, cflag, (port->uartclk / (16 * quot)));
+
+       up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+       if (iflag & INPCK)
+               up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+       if (iflag & (BRKINT | PARMRK))
+               up->port.read_status_mask |= UART_LSR_BI;
+
+       /*
+        * Characteres to ignore
+        */
+       up->port.ignore_status_mask = 0;
+       if (iflag & IGNPAR)
+               up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+       if (iflag & IGNBRK) {
+               up->port.ignore_status_mask |= UART_LSR_BI;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (iflag & IGNPAR)
+                       up->port.ignore_status_mask |= UART_LSR_OE;
+       }
+
+       /*
+        * ignore all characters if CREAD is not set
+        */
+       if ((cflag & CREAD) == 0)
+               up->port.ignore_status_mask |= UART_LSR_DR;
+
+       /*
+        * CTS flow control flag and modem status interrupts
+        */
+       up->ier &= ~UART_IER_MSI;
+       if (UART_ENABLE_MS(&up->port, cflag))
+               up->ier |= UART_IER_MSI;
+
+       serial_out(up, UART_IER, up->ier);
+
+       if (uart_config[up->port.type].flags & UART_STARTECH) {
+               serial_outp(up, UART_LCR, 0xBF);
+               serial_outp(up, UART_EFR, cflag & CRTSCTS ? UART_EFR_CTS :0);
+       }
+       serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
+       serial_outp(up, UART_DLL, quot & 0xff);         /* LS of divisor */
+       serial_outp(up, UART_DLM, quot >> 8);           /* MS of divisor */
+       if (up->port.type == PORT_16750)
+               serial_outp(up, UART_FCR, fcr);         /* set fcr */
+       serial_outp(up, UART_LCR, cval);                /* reset DLAB */
+       up->lcr = cval;                                 /* Save LCR */
+       if (up->port.type != PORT_16750) {
+               if (fcr & UART_FCR_ENABLE_FIFO) {
+                       /* emulated UARTs (Lucent Venus 167x) need two steps */
+                       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+               }
+               serial_outp(up, UART_FCR, fcr);         /* set fcr */
+       }
+
+       up->cflag = cflag;
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static void
+sunsu_set_termios(struct uart_port *port, struct ktermios *termios,
+                 struct ktermios *old)
+{
+       unsigned int baud, quot;
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
+       quot = uart_get_divisor(port, baud);
+
+       sunsu_change_speed(port, termios->c_cflag, termios->c_iflag, quot);
+}
+
+static void sunsu_release_port(struct uart_port *port)
+{
+}
+
+static int sunsu_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static void sunsu_config_port(struct uart_port *port, int flags)
+{
+       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
+
+       if (flags & UART_CONFIG_TYPE) {
+               /*
+                * We are supposed to call autoconfig here, but this requires
+                * splitting all the OBP probing crap from the UART probing.
+                * We'll do it when we kill sunsu.c altogether.
+                */
+               port->type = up->type_probed;   /* XXX */
+       }
+}
+
+static int
+sunsu_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       return -EINVAL;
+}
+
+static const char *
+sunsu_type(struct uart_port *port)
+{
+       int type = port->type;
+
+       if (type >= ARRAY_SIZE(uart_config))
+               type = 0;
+       return uart_config[type].name;
+}
+
+static struct uart_ops sunsu_pops = {
+       .tx_empty       = sunsu_tx_empty,
+       .set_mctrl      = sunsu_set_mctrl,
+       .get_mctrl      = sunsu_get_mctrl,
+       .stop_tx        = sunsu_stop_tx,
+       .start_tx       = sunsu_start_tx,
+       .stop_rx        = sunsu_stop_rx,
+       .enable_ms      = sunsu_enable_ms,
+       .break_ctl      = sunsu_break_ctl,
+       .startup        = sunsu_startup,
+       .shutdown       = sunsu_shutdown,
+       .set_termios    = sunsu_set_termios,
+       .type           = sunsu_type,
+       .release_port   = sunsu_release_port,
+       .request_port   = sunsu_request_port,
+       .config_port    = sunsu_config_port,
+       .verify_port    = sunsu_verify_port,
+};
+
+#define UART_NR        4
+
+static struct uart_sunsu_port sunsu_ports[UART_NR];
+
+#ifdef CONFIG_SERIO
+
+static DEFINE_SPINLOCK(sunsu_serio_lock);
+
+static int sunsu_serio_write(struct serio *serio, unsigned char ch)
+{
+       struct uart_sunsu_port *up = serio->port_data;
+       unsigned long flags;
+       int lsr;
+
+       spin_lock_irqsave(&sunsu_serio_lock, flags);
+
+       do {
+               lsr = serial_in(up, UART_LSR);
+       } while (!(lsr & UART_LSR_THRE));
+
+       /* Send the character out. */
+       serial_out(up, UART_TX, ch);
+
+       spin_unlock_irqrestore(&sunsu_serio_lock, flags);
+
+       return 0;
+}
+
+static int sunsu_serio_open(struct serio *serio)
+{
+       struct uart_sunsu_port *up = serio->port_data;
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&sunsu_serio_lock, flags);
+       if (!up->serio_open) {
+               up->serio_open = 1;
+               ret = 0;
+       } else
+               ret = -EBUSY;
+       spin_unlock_irqrestore(&sunsu_serio_lock, flags);
+
+       return ret;
+}
+
+static void sunsu_serio_close(struct serio *serio)
+{
+       struct uart_sunsu_port *up = serio->port_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sunsu_serio_lock, flags);
+       up->serio_open = 0;
+       spin_unlock_irqrestore(&sunsu_serio_lock, flags);
+}
+
+#endif /* CONFIG_SERIO */
+
+static void sunsu_autoconfig(struct uart_sunsu_port *up)
+{
+       unsigned char status1, status2, scratch, scratch2, scratch3;
+       unsigned char save_lcr, save_mcr;
+       unsigned long flags;
+
+       if (up->su_type == SU_PORT_NONE)
+               return;
+
+       up->type_probed = PORT_UNKNOWN;
+       up->port.iotype = UPIO_MEM;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       if (!(up->port.flags & UPF_BUGGY_UART)) {
+               /*
+                * Do a simple existence test first; if we fail this, there's
+                * no point trying anything else.
+                *
+                * 0x80 is used as a nonsense port to prevent against false
+                * positives due to ISA bus float.  The assumption is that
+                * 0x80 is a non-existent port; which should be safe since
+                * include/asm/io.h also makes this assumption.
+                */
+               scratch = serial_inp(up, UART_IER);
+               serial_outp(up, UART_IER, 0);
+#ifdef __i386__
+               outb(0xff, 0x080);
+#endif
+               scratch2 = serial_inp(up, UART_IER);
+               serial_outp(up, UART_IER, 0x0f);
+#ifdef __i386__
+               outb(0, 0x080);
+#endif
+               scratch3 = serial_inp(up, UART_IER);
+               serial_outp(up, UART_IER, scratch);
+               if (scratch2 != 0 || scratch3 != 0x0F)
+                       goto out;       /* We failed; there's nothing here */
+       }
+
+       save_mcr = serial_in(up, UART_MCR);
+       save_lcr = serial_in(up, UART_LCR);
+
+       /* 
+        * Check to see if a UART is really there.  Certain broken
+        * internal modems based on the Rockwell chipset fail this
+        * test, because they apparently don't implement the loopback
+        * test mode.  So this test is skipped on the COM 1 through
+        * COM 4 ports.  This *should* be safe, since no board
+        * manufacturer would be stupid enough to design a board
+        * that conflicts with COM 1-4 --- we hope!
+        */
+       if (!(up->port.flags & UPF_SKIP_TEST)) {
+               serial_outp(up, UART_MCR, UART_MCR_LOOP | 0x0A);
+               status1 = serial_inp(up, UART_MSR) & 0xF0;
+               serial_outp(up, UART_MCR, save_mcr);
+               if (status1 != 0x90)
+                       goto out;       /* We failed loopback test */
+       }
+       serial_outp(up, UART_LCR, 0xBF);        /* set up for StarTech test */
+       serial_outp(up, UART_EFR, 0);           /* EFR is the same as FCR */
+       serial_outp(up, UART_LCR, 0);
+       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+       scratch = serial_in(up, UART_IIR) >> 6;
+       switch (scratch) {
+               case 0:
+                       up->port.type = PORT_16450;
+                       break;
+               case 1:
+                       up->port.type = PORT_UNKNOWN;
+                       break;
+               case 2:
+                       up->port.type = PORT_16550;
+                       break;
+               case 3:
+                       up->port.type = PORT_16550A;
+                       break;
+       }
+       if (up->port.type == PORT_16550A) {
+               /* Check for Startech UART's */
+               serial_outp(up, UART_LCR, UART_LCR_DLAB);
+               if (serial_in(up, UART_EFR) == 0) {
+                       up->port.type = PORT_16650;
+               } else {
+                       serial_outp(up, UART_LCR, 0xBF);
+                       if (serial_in(up, UART_EFR) == 0)
+                               up->port.type = PORT_16650V2;
+               }
+       }
+       if (up->port.type == PORT_16550A) {
+               /* Check for TI 16750 */
+               serial_outp(up, UART_LCR, save_lcr | UART_LCR_DLAB);
+               serial_outp(up, UART_FCR,
+                           UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
+               scratch = serial_in(up, UART_IIR) >> 5;
+               if (scratch == 7) {
+                       /*
+                        * If this is a 16750, and not a cheap UART
+                        * clone, then it should only go into 64 byte
+                        * mode if the UART_FCR7_64BYTE bit was set
+                        * while UART_LCR_DLAB was latched.
+                        */
+                       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+                       serial_outp(up, UART_LCR, 0);
+                       serial_outp(up, UART_FCR,
+                                   UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
+                       scratch = serial_in(up, UART_IIR) >> 5;
+                       if (scratch == 6)
+                               up->port.type = PORT_16750;
+               }
+               serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+       }
+       serial_outp(up, UART_LCR, save_lcr);
+       if (up->port.type == PORT_16450) {
+               scratch = serial_in(up, UART_SCR);
+               serial_outp(up, UART_SCR, 0xa5);
+               status1 = serial_in(up, UART_SCR);
+               serial_outp(up, UART_SCR, 0x5a);
+               status2 = serial_in(up, UART_SCR);
+               serial_outp(up, UART_SCR, scratch);
+
+               if ((status1 != 0xa5) || (status2 != 0x5a))
+                       up->port.type = PORT_8250;
+       }
+
+       up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size;
+
+       if (up->port.type == PORT_UNKNOWN)
+               goto out;
+       up->type_probed = up->port.type;        /* XXX */
+
+       /*
+        * Reset the UART.
+        */
+#ifdef CONFIG_SERIAL_8250_RSA
+       if (up->port.type == PORT_RSA)
+               serial_outp(up, UART_RSA_FRR, 0);
+#endif
+       serial_outp(up, UART_MCR, save_mcr);
+       serial_outp(up, UART_FCR, (UART_FCR_ENABLE_FIFO |
+                                    UART_FCR_CLEAR_RCVR |
+                                    UART_FCR_CLEAR_XMIT));
+       serial_outp(up, UART_FCR, 0);
+       (void)serial_in(up, UART_RX);
+       serial_outp(up, UART_IER, 0);
+
+out:
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static struct uart_driver sunsu_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "sunsu",
+       .dev_name               = "ttyS",
+       .major                  = TTY_MAJOR,
+};
+
+static int __devinit sunsu_kbd_ms_init(struct uart_sunsu_port *up)
+{
+       int quot, baud;
+#ifdef CONFIG_SERIO
+       struct serio *serio;
+#endif
+
+       if (up->su_type == SU_PORT_KBD) {
+               up->cflag = B1200 | CS8 | CLOCAL | CREAD;
+               baud = 1200;
+       } else {
+               up->cflag = B4800 | CS8 | CLOCAL | CREAD;
+               baud = 4800;
+       }
+       quot = up->port.uartclk / (16 * baud);
+
+       sunsu_autoconfig(up);
+       if (up->port.type == PORT_UNKNOWN)
+               return -ENODEV;
+
+       printk("%s: %s port at %llx, irq %u\n",
+              up->port.dev->of_node->full_name,
+              (up->su_type == SU_PORT_KBD) ? "Keyboard" : "Mouse",
+              (unsigned long long) up->port.mapbase,
+              up->port.irq);
+
+#ifdef CONFIG_SERIO
+       serio = &up->serio;
+       serio->port_data = up;
+
+       serio->id.type = SERIO_RS232;
+       if (up->su_type == SU_PORT_KBD) {
+               serio->id.proto = SERIO_SUNKBD;
+               strlcpy(serio->name, "sukbd", sizeof(serio->name));
+       } else {
+               serio->id.proto = SERIO_SUN;
+               serio->id.extra = 1;
+               strlcpy(serio->name, "sums", sizeof(serio->name));
+       }
+       strlcpy(serio->phys,
+               (!(up->port.line & 1) ? "su/serio0" : "su/serio1"),
+               sizeof(serio->phys));
+
+       serio->write = sunsu_serio_write;
+       serio->open = sunsu_serio_open;
+       serio->close = sunsu_serio_close;
+       serio->dev.parent = up->port.dev;
+
+       serio_register_port(serio);
+#endif
+
+       sunsu_change_speed(&up->port, up->cflag, 0, quot);
+
+       sunsu_startup(&up->port);
+       return 0;
+}
+
+/*
+ * ------------------------------------------------------------
+ * Serial console driver
+ * ------------------------------------------------------------
+ */
+
+#ifdef CONFIG_SERIAL_SUNSU_CONSOLE
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+/*
+ *     Wait for transmitter & holding register to empty
+ */
+static __inline__ void wait_for_xmitr(struct uart_sunsu_port *up)
+{
+       unsigned int status, tmout = 10000;
+
+       /* Wait up to 10ms for the character(s) to be sent. */
+       do {
+               status = serial_in(up, UART_LSR);
+
+               if (status & UART_LSR_BI)
+                       up->lsr_break_flag = UART_LSR_BI;
+
+               if (--tmout == 0)
+                       break;
+               udelay(1);
+       } while ((status & BOTH_EMPTY) != BOTH_EMPTY);
+
+       /* Wait up to 1s for flow control if necessary */
+       if (up->port.flags & UPF_CONS_FLOW) {
+               tmout = 1000000;
+               while (--tmout &&
+                      ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
+                       udelay(1);
+       }
+}
+
+static void sunsu_console_putchar(struct uart_port *port, int ch)
+{
+       struct uart_sunsu_port *up = (struct uart_sunsu_port *)port;
+
+       wait_for_xmitr(up);
+       serial_out(up, UART_TX, ch);
+}
+
+/*
+ *     Print a string to the serial port trying not to disturb
+ *     any possible real use of the port...
+ */
+static void sunsu_console_write(struct console *co, const char *s,
+                               unsigned int count)
+{
+       struct uart_sunsu_port *up = &sunsu_ports[co->index];
+       unsigned long flags;
+       unsigned int ier;
+       int locked = 1;
+
+       local_irq_save(flags);
+       if (up->port.sysrq) {
+               locked = 0;
+       } else if (oops_in_progress) {
+               locked = spin_trylock(&up->port.lock);
+       } else
+               spin_lock(&up->port.lock);
+
+       /*
+        *      First save the UER then disable the interrupts
+        */
+       ier = serial_in(up, UART_IER);
+       serial_out(up, UART_IER, 0);
+
+       uart_console_write(&up->port, s, count, sunsu_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the IER
+        */
+       wait_for_xmitr(up);
+       serial_out(up, UART_IER, ier);
+
+       if (locked)
+               spin_unlock(&up->port.lock);
+       local_irq_restore(flags);
+}
+
+/*
+ *     Setup initial baud/bits/parity. We do two things here:
+ *     - construct a cflag setting for the first su_open()
+ *     - initialize the serial port
+ *     Return non-zero if we didn't find a serial port.
+ */
+static int __init sunsu_console_setup(struct console *co, char *options)
+{
+       static struct ktermios dummy;
+       struct ktermios termios;
+       struct uart_port *port;
+
+       printk("Console: ttyS%d (SU)\n",
+              (sunsu_reg.minor - 64) + co->index);
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index >= UART_NR)
+               co->index = 0;
+       port = &sunsu_ports[co->index].port;
+
+       /*
+        * Temporary fix.
+        */
+       spin_lock_init(&port->lock);
+
+       /* Get firmware console settings.  */
+       sunserial_console_termios(co, port->dev->of_node);
+
+       memset(&termios, 0, sizeof(struct ktermios));
+       termios.c_cflag = co->cflag;
+       port->mctrl |= TIOCM_DTR;
+       port->ops->set_termios(port, &termios, &dummy);
+
+       return 0;
+}
+
+static struct console sunsu_console = {
+       .name   =       "ttyS",
+       .write  =       sunsu_console_write,
+       .device =       uart_console_device,
+       .setup  =       sunsu_console_setup,
+       .flags  =       CON_PRINTBUFFER,
+       .index  =       -1,
+       .data   =       &sunsu_reg,
+};
+
+/*
+ *     Register console.
+ */
+
+static inline struct console *SUNSU_CONSOLE(void)
+{
+       return &sunsu_console;
+}
+#else
+#define SUNSU_CONSOLE()                        (NULL)
+#define sunsu_serial_console_init()    do { } while (0)
+#endif
+
+static enum su_type __devinit su_get_type(struct device_node *dp)
+{
+       struct device_node *ap = of_find_node_by_path("/aliases");
+
+       if (ap) {
+               const char *keyb = of_get_property(ap, "keyboard", NULL);
+               const char *ms = of_get_property(ap, "mouse", NULL);
+
+               if (keyb) {
+                       if (dp == of_find_node_by_path(keyb))
+                               return SU_PORT_KBD;
+               }
+               if (ms) {
+                       if (dp == of_find_node_by_path(ms))
+                               return SU_PORT_MS;
+               }
+       }
+
+       return SU_PORT_PORT;
+}
+
+static int __devinit su_probe(struct platform_device *op, const struct of_device_id *match)
+{
+       static int inst;
+       struct device_node *dp = op->dev.of_node;
+       struct uart_sunsu_port *up;
+       struct resource *rp;
+       enum su_type type;
+       bool ignore_line;
+       int err;
+
+       type = su_get_type(dp);
+       if (type == SU_PORT_PORT) {
+               if (inst >= UART_NR)
+                       return -EINVAL;
+               up = &sunsu_ports[inst];
+       } else {
+               up = kzalloc(sizeof(*up), GFP_KERNEL);
+               if (!up)
+                       return -ENOMEM;
+       }
+
+       up->port.line = inst;
+
+       spin_lock_init(&up->port.lock);
+
+       up->su_type = type;
+
+       rp = &op->resource[0];
+       up->port.mapbase = rp->start;
+       up->reg_size = (rp->end - rp->start) + 1;
+       up->port.membase = of_ioremap(rp, 0, up->reg_size, "su");
+       if (!up->port.membase) {
+               if (type != SU_PORT_PORT)
+                       kfree(up);
+               return -ENOMEM;
+       }
+
+       up->port.irq = op->archdata.irqs[0];
+
+       up->port.dev = &op->dev;
+
+       up->port.type = PORT_UNKNOWN;
+       up->port.uartclk = (SU_BASE_BAUD * 16);
+
+       err = 0;
+       if (up->su_type == SU_PORT_KBD || up->su_type == SU_PORT_MS) {
+               err = sunsu_kbd_ms_init(up);
+               if (err) {
+                       of_iounmap(&op->resource[0],
+                                  up->port.membase, up->reg_size);
+                       kfree(up);
+                       return err;
+               }
+               dev_set_drvdata(&op->dev, up);
+
+               return 0;
+       }
+
+       up->port.flags |= UPF_BOOT_AUTOCONF;
+
+       sunsu_autoconfig(up);
+
+       err = -ENODEV;
+       if (up->port.type == PORT_UNKNOWN)
+               goto out_unmap;
+
+       up->port.ops = &sunsu_pops;
+
+       ignore_line = false;
+       if (!strcmp(dp->name, "rsc-console") ||
+           !strcmp(dp->name, "lom-console"))
+               ignore_line = true;
+
+       sunserial_console_match(SUNSU_CONSOLE(), dp,
+                               &sunsu_reg, up->port.line,
+                               ignore_line);
+       err = uart_add_one_port(&sunsu_reg, &up->port);
+       if (err)
+               goto out_unmap;
+
+       dev_set_drvdata(&op->dev, up);
+
+       inst++;
+
+       return 0;
+
+out_unmap:
+       of_iounmap(&op->resource[0], up->port.membase, up->reg_size);
+       return err;
+}
+
+static int __devexit su_remove(struct platform_device *op)
+{
+       struct uart_sunsu_port *up = dev_get_drvdata(&op->dev);
+       bool kbdms = false;
+
+       if (up->su_type == SU_PORT_MS ||
+           up->su_type == SU_PORT_KBD)
+               kbdms = true;
+
+       if (kbdms) {
+#ifdef CONFIG_SERIO
+               serio_unregister_port(&up->serio);
+#endif
+       } else if (up->port.type != PORT_UNKNOWN)
+               uart_remove_one_port(&sunsu_reg, &up->port);
+
+       if (up->port.membase)
+               of_iounmap(&op->resource[0], up->port.membase, up->reg_size);
+
+       if (kbdms)
+               kfree(up);
+
+       dev_set_drvdata(&op->dev, NULL);
+
+       return 0;
+}
+
+static const struct of_device_id su_match[] = {
+       {
+               .name = "su",
+       },
+       {
+               .name = "su_pnp",
+       },
+       {
+               .name = "serial",
+               .compatible = "su",
+       },
+       {
+               .type = "serial",
+               .compatible = "su",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, su_match);
+
+static struct of_platform_driver su_driver = {
+       .driver = {
+               .name = "su",
+               .owner = THIS_MODULE,
+               .of_match_table = su_match,
+       },
+       .probe          = su_probe,
+       .remove         = __devexit_p(su_remove),
+};
+
+static int __init sunsu_init(void)
+{
+       struct device_node *dp;
+       int err;
+       int num_uart = 0;
+
+       for_each_node_by_name(dp, "su") {
+               if (su_get_type(dp) == SU_PORT_PORT)
+                       num_uart++;
+       }
+       for_each_node_by_name(dp, "su_pnp") {
+               if (su_get_type(dp) == SU_PORT_PORT)
+                       num_uart++;
+       }
+       for_each_node_by_name(dp, "serial") {
+               if (of_device_is_compatible(dp, "su")) {
+                       if (su_get_type(dp) == SU_PORT_PORT)
+                               num_uart++;
+               }
+       }
+       for_each_node_by_type(dp, "serial") {
+               if (of_device_is_compatible(dp, "su")) {
+                       if (su_get_type(dp) == SU_PORT_PORT)
+                               num_uart++;
+               }
+       }
+
+       if (num_uart) {
+               err = sunserial_register_minors(&sunsu_reg, num_uart);
+               if (err)
+                       return err;
+       }
+
+       err = of_register_platform_driver(&su_driver);
+       if (err && num_uart)
+               sunserial_unregister_minors(&sunsu_reg, num_uart);
+
+       return err;
+}
+
+static void __exit sunsu_exit(void)
+{
+       if (sunsu_reg.nr)
+               sunserial_unregister_minors(&sunsu_reg, sunsu_reg.nr);
+}
+
+module_init(sunsu_init);
+module_exit(sunsu_exit);
+
+MODULE_AUTHOR("Eddie C. Dost, Peter Zaitcev, and David S. Miller");
+MODULE_DESCRIPTION("Sun SU serial port driver");
+MODULE_VERSION("2.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c
new file mode 100644 (file)
index 0000000..c1967ac
--- /dev/null
@@ -0,0 +1,1655 @@
+/* sunzilog.c: Zilog serial driver for Sparc systems.
+ *
+ * Driver for Zilog serial chips found on Sun workstations and
+ * servers.  This driver could actually be made more generic.
+ *
+ * This is based on the old drivers/sbus/char/zs.c code.  A lot
+ * of code has been simply moved over directly from there but
+ * much has been rewritten.  Credits therefore go out to Eddie
+ * C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell for their
+ * work there.
+ *
+ * Copyright (C) 2002, 2006, 2007 David S. Miller (davem@davemloft.net)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <linux/spinlock.h>
+#ifdef CONFIG_SERIO
+#include <linux/serio.h>
+#endif
+#include <linux/init.h>
+#include <linux/of_device.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+
+#if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#include "suncore.h"
+#include "sunzilog.h"
+
+/* On 32-bit sparcs we need to delay after register accesses
+ * to accommodate sun4 systems, but we do not need to flush writes.
+ * On 64-bit sparc we only need to flush single writes to ensure
+ * completion.
+ */
+#ifndef CONFIG_SPARC64
+#define ZSDELAY()              udelay(5)
+#define ZSDELAY_LONG()         udelay(20)
+#define ZS_WSYNC(channel)      do { } while (0)
+#else
+#define ZSDELAY()
+#define ZSDELAY_LONG()
+#define ZS_WSYNC(__channel) \
+       readb(&((__channel)->control))
+#endif
+
+#define ZS_CLOCK               4915200 /* Zilog input clock rate. */
+#define ZS_CLOCK_DIVISOR       16      /* Divisor this driver uses. */
+
+/*
+ * We wrap our port structure around the generic uart_port.
+ */
+struct uart_sunzilog_port {
+       struct uart_port                port;
+
+       /* IRQ servicing chain.  */
+       struct uart_sunzilog_port       *next;
+
+       /* Current values of Zilog write registers.  */
+       unsigned char                   curregs[NUM_ZSREGS];
+
+       unsigned int                    flags;
+#define SUNZILOG_FLAG_CONS_KEYB                0x00000001
+#define SUNZILOG_FLAG_CONS_MOUSE       0x00000002
+#define SUNZILOG_FLAG_IS_CONS          0x00000004
+#define SUNZILOG_FLAG_IS_KGDB          0x00000008
+#define SUNZILOG_FLAG_MODEM_STATUS     0x00000010
+#define SUNZILOG_FLAG_IS_CHANNEL_A     0x00000020
+#define SUNZILOG_FLAG_REGS_HELD                0x00000040
+#define SUNZILOG_FLAG_TX_STOPPED       0x00000080
+#define SUNZILOG_FLAG_TX_ACTIVE                0x00000100
+#define SUNZILOG_FLAG_ESCC             0x00000200
+#define SUNZILOG_FLAG_ISR_HANDLER      0x00000400
+
+       unsigned int cflag;
+
+       unsigned char                   parity_mask;
+       unsigned char                   prev_status;
+
+#ifdef CONFIG_SERIO
+       struct serio                    serio;
+       int                             serio_open;
+#endif
+};
+
+static void sunzilog_putchar(struct uart_port *port, int ch);
+
+#define ZILOG_CHANNEL_FROM_PORT(PORT)  ((struct zilog_channel __iomem *)((PORT)->membase))
+#define UART_ZILOG(PORT)               ((struct uart_sunzilog_port *)(PORT))
+
+#define ZS_IS_KEYB(UP) ((UP)->flags & SUNZILOG_FLAG_CONS_KEYB)
+#define ZS_IS_MOUSE(UP)        ((UP)->flags & SUNZILOG_FLAG_CONS_MOUSE)
+#define ZS_IS_CONS(UP) ((UP)->flags & SUNZILOG_FLAG_IS_CONS)
+#define ZS_IS_KGDB(UP) ((UP)->flags & SUNZILOG_FLAG_IS_KGDB)
+#define ZS_WANTS_MODEM_STATUS(UP)      ((UP)->flags & SUNZILOG_FLAG_MODEM_STATUS)
+#define ZS_IS_CHANNEL_A(UP)    ((UP)->flags & SUNZILOG_FLAG_IS_CHANNEL_A)
+#define ZS_REGS_HELD(UP)       ((UP)->flags & SUNZILOG_FLAG_REGS_HELD)
+#define ZS_TX_STOPPED(UP)      ((UP)->flags & SUNZILOG_FLAG_TX_STOPPED)
+#define ZS_TX_ACTIVE(UP)       ((UP)->flags & SUNZILOG_FLAG_TX_ACTIVE)
+
+/* Reading and writing Zilog8530 registers.  The delays are to make this
+ * driver work on the Sun4 which needs a settling delay after each chip
+ * register access, other machines handle this in hardware via auxiliary
+ * flip-flops which implement the settle time we do in software.
+ *
+ * The port lock must be held and local IRQs must be disabled
+ * when {read,write}_zsreg is invoked.
+ */
+static unsigned char read_zsreg(struct zilog_channel __iomem *channel,
+                               unsigned char reg)
+{
+       unsigned char retval;
+
+       writeb(reg, &channel->control);
+       ZSDELAY();
+       retval = readb(&channel->control);
+       ZSDELAY();
+
+       return retval;
+}
+
+static void write_zsreg(struct zilog_channel __iomem *channel,
+                       unsigned char reg, unsigned char value)
+{
+       writeb(reg, &channel->control);
+       ZSDELAY();
+       writeb(value, &channel->control);
+       ZSDELAY();
+}
+
+static void sunzilog_clear_fifo(struct zilog_channel __iomem *channel)
+{
+       int i;
+
+       for (i = 0; i < 32; i++) {
+               unsigned char regval;
+
+               regval = readb(&channel->control);
+               ZSDELAY();
+               if (regval & Rx_CH_AV)
+                       break;
+
+               regval = read_zsreg(channel, R1);
+               readb(&channel->data);
+               ZSDELAY();
+
+               if (regval & (PAR_ERR | Rx_OVR | CRC_ERR)) {
+                       writeb(ERR_RES, &channel->control);
+                       ZSDELAY();
+                       ZS_WSYNC(channel);
+               }
+       }
+}
+
+/* This function must only be called when the TX is not busy.  The UART
+ * port lock must be held and local interrupts disabled.
+ */
+static int __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *regs)
+{
+       int i;
+       int escc;
+       unsigned char r15;
+
+       /* Let pending transmits finish.  */
+       for (i = 0; i < 1000; i++) {
+               unsigned char stat = read_zsreg(channel, R1);
+               if (stat & ALL_SNT)
+                       break;
+               udelay(100);
+       }
+
+       writeb(ERR_RES, &channel->control);
+       ZSDELAY();
+       ZS_WSYNC(channel);
+
+       sunzilog_clear_fifo(channel);
+
+       /* Disable all interrupts.  */
+       write_zsreg(channel, R1,
+                   regs[R1] & ~(RxINT_MASK | TxINT_ENAB | EXT_INT_ENAB));
+
+       /* Set parity, sync config, stop bits, and clock divisor.  */
+       write_zsreg(channel, R4, regs[R4]);
+
+       /* Set misc. TX/RX control bits.  */
+       write_zsreg(channel, R10, regs[R10]);
+
+       /* Set TX/RX controls sans the enable bits.  */
+       write_zsreg(channel, R3, regs[R3] & ~RxENAB);
+       write_zsreg(channel, R5, regs[R5] & ~TxENAB);
+
+       /* Synchronous mode config.  */
+       write_zsreg(channel, R6, regs[R6]);
+       write_zsreg(channel, R7, regs[R7]);
+
+       /* Don't mess with the interrupt vector (R2, unused by us) and
+        * master interrupt control (R9).  We make sure this is setup
+        * properly at probe time then never touch it again.
+        */
+
+       /* Disable baud generator.  */
+       write_zsreg(channel, R14, regs[R14] & ~BRENAB);
+
+       /* Clock mode control.  */
+       write_zsreg(channel, R11, regs[R11]);
+
+       /* Lower and upper byte of baud rate generator divisor.  */
+       write_zsreg(channel, R12, regs[R12]);
+       write_zsreg(channel, R13, regs[R13]);
+       
+       /* Now rewrite R14, with BRENAB (if set).  */
+       write_zsreg(channel, R14, regs[R14]);
+
+       /* External status interrupt control.  */
+       write_zsreg(channel, R15, (regs[R15] | WR7pEN) & ~FIFOEN);
+
+       /* ESCC Extension Register */
+       r15 = read_zsreg(channel, R15);
+       if (r15 & 0x01) {
+               write_zsreg(channel, R7,  regs[R7p]);
+
+               /* External status interrupt and FIFO control.  */
+               write_zsreg(channel, R15, regs[R15] & ~WR7pEN);
+               escc = 1;
+       } else {
+                /* Clear FIFO bit case it is an issue */
+               regs[R15] &= ~FIFOEN;
+               escc = 0;
+       }
+
+       /* Reset external status interrupts.  */
+       write_zsreg(channel, R0, RES_EXT_INT); /* First Latch  */
+       write_zsreg(channel, R0, RES_EXT_INT); /* Second Latch */
+
+       /* Rewrite R3/R5, this time without enables masked.  */
+       write_zsreg(channel, R3, regs[R3]);
+       write_zsreg(channel, R5, regs[R5]);
+
+       /* Rewrite R1, this time without IRQ enabled masked.  */
+       write_zsreg(channel, R1, regs[R1]);
+
+       return escc;
+}
+
+/* Reprogram the Zilog channel HW registers with the copies found in the
+ * software state struct.  If the transmitter is busy, we defer this update
+ * until the next TX complete interrupt.  Else, we do it right now.
+ *
+ * The UART port lock must be held and local interrupts disabled.
+ */
+static void sunzilog_maybe_update_regs(struct uart_sunzilog_port *up,
+                                      struct zilog_channel __iomem *channel)
+{
+       if (!ZS_REGS_HELD(up)) {
+               if (ZS_TX_ACTIVE(up)) {
+                       up->flags |= SUNZILOG_FLAG_REGS_HELD;
+               } else {
+                       __load_zsregs(channel, up->curregs);
+               }
+       }
+}
+
+static void sunzilog_change_mouse_baud(struct uart_sunzilog_port *up)
+{
+       unsigned int cur_cflag = up->cflag;
+       int brg, new_baud;
+
+       up->cflag &= ~CBAUD;
+       up->cflag |= suncore_mouse_baud_cflag_next(cur_cflag, &new_baud);
+
+       brg = BPS_TO_BRG(new_baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
+       up->curregs[R12] = (brg & 0xff);
+       up->curregs[R13] = (brg >> 8) & 0xff;
+       sunzilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(&up->port));
+}
+
+static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up,
+                                        unsigned char ch, int is_break)
+{
+       if (ZS_IS_KEYB(up)) {
+               /* Stop-A is handled by drivers/char/keyboard.c now. */
+#ifdef CONFIG_SERIO
+               if (up->serio_open)
+                       serio_interrupt(&up->serio, ch, 0);
+#endif
+       } else if (ZS_IS_MOUSE(up)) {
+               int ret = suncore_mouse_baud_detection(ch, is_break);
+
+               switch (ret) {
+               case 2:
+                       sunzilog_change_mouse_baud(up);
+                       /* fallthru */
+               case 1:
+                       break;
+
+               case 0:
+#ifdef CONFIG_SERIO
+                       if (up->serio_open)
+                               serio_interrupt(&up->serio, ch, 0);
+#endif
+                       break;
+               };
+       }
+}
+
+static struct tty_struct *
+sunzilog_receive_chars(struct uart_sunzilog_port *up,
+                      struct zilog_channel __iomem *channel)
+{
+       struct tty_struct *tty;
+       unsigned char ch, r1, flag;
+
+       tty = NULL;
+       if (up->port.state != NULL &&           /* Unopened serial console */
+           up->port.state->port.tty != NULL)   /* Keyboard || mouse */
+               tty = up->port.state->port.tty;
+
+       for (;;) {
+
+               r1 = read_zsreg(channel, R1);
+               if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
+                       writeb(ERR_RES, &channel->control);
+                       ZSDELAY();
+                       ZS_WSYNC(channel);
+               }
+
+               ch = readb(&channel->control);
+               ZSDELAY();
+
+               /* This funny hack depends upon BRK_ABRT not interfering
+                * with the other bits we care about in R1.
+                */
+               if (ch & BRK_ABRT)
+                       r1 |= BRK_ABRT;
+
+               if (!(ch & Rx_CH_AV))
+                       break;
+
+               ch = readb(&channel->data);
+               ZSDELAY();
+
+               ch &= up->parity_mask;
+
+               if (unlikely(ZS_IS_KEYB(up)) || unlikely(ZS_IS_MOUSE(up))) {
+                       sunzilog_kbdms_receive_chars(up, ch, 0);
+                       continue;
+               }
+
+               if (tty == NULL) {
+                       uart_handle_sysrq_char(&up->port, ch);
+                       continue;
+               }
+
+               /* A real serial line, record the character and status.  */
+               flag = TTY_NORMAL;
+               up->port.icount.rx++;
+               if (r1 & (BRK_ABRT | PAR_ERR | Rx_OVR | CRC_ERR)) {
+                       if (r1 & BRK_ABRT) {
+                               r1 &= ~(PAR_ERR | CRC_ERR);
+                               up->port.icount.brk++;
+                               if (uart_handle_break(&up->port))
+                                       continue;
+                       }
+                       else if (r1 & PAR_ERR)
+                               up->port.icount.parity++;
+                       else if (r1 & CRC_ERR)
+                               up->port.icount.frame++;
+                       if (r1 & Rx_OVR)
+                               up->port.icount.overrun++;
+                       r1 &= up->port.read_status_mask;
+                       if (r1 & BRK_ABRT)
+                               flag = TTY_BREAK;
+                       else if (r1 & PAR_ERR)
+                               flag = TTY_PARITY;
+                       else if (r1 & CRC_ERR)
+                               flag = TTY_FRAME;
+               }
+               if (uart_handle_sysrq_char(&up->port, ch))
+                       continue;
+
+               if (up->port.ignore_status_mask == 0xff ||
+                   (r1 & up->port.ignore_status_mask) == 0) {
+                       tty_insert_flip_char(tty, ch, flag);
+               }
+               if (r1 & Rx_OVR)
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+       }
+
+       return tty;
+}
+
+static void sunzilog_status_handle(struct uart_sunzilog_port *up,
+                                  struct zilog_channel __iomem *channel)
+{
+       unsigned char status;
+
+       status = readb(&channel->control);
+       ZSDELAY();
+
+       writeb(RES_EXT_INT, &channel->control);
+       ZSDELAY();
+       ZS_WSYNC(channel);
+
+       if (status & BRK_ABRT) {
+               if (ZS_IS_MOUSE(up))
+                       sunzilog_kbdms_receive_chars(up, 0, 1);
+               if (ZS_IS_CONS(up)) {
+                       /* Wait for BREAK to deassert to avoid potentially
+                        * confusing the PROM.
+                        */
+                       while (1) {
+                               status = readb(&channel->control);
+                               ZSDELAY();
+                               if (!(status & BRK_ABRT))
+                                       break;
+                       }
+                       sun_do_break();
+                       return;
+               }
+       }
+
+       if (ZS_WANTS_MODEM_STATUS(up)) {
+               if (status & SYNC)
+                       up->port.icount.dsr++;
+
+               /* The Zilog just gives us an interrupt when DCD/CTS/etc. change.
+                * But it does not tell us which bit has changed, we have to keep
+                * track of this ourselves.
+                */
+               if ((status ^ up->prev_status) ^ DCD)
+                       uart_handle_dcd_change(&up->port,
+                                              (status & DCD));
+               if ((status ^ up->prev_status) ^ CTS)
+                       uart_handle_cts_change(&up->port,
+                                              (status & CTS));
+
+               wake_up_interruptible(&up->port.state->port.delta_msr_wait);
+       }
+
+       up->prev_status = status;
+}
+
+static void sunzilog_transmit_chars(struct uart_sunzilog_port *up,
+                                   struct zilog_channel __iomem *channel)
+{
+       struct circ_buf *xmit;
+
+       if (ZS_IS_CONS(up)) {
+               unsigned char status = readb(&channel->control);
+               ZSDELAY();
+
+               /* TX still busy?  Just wait for the next TX done interrupt.
+                *
+                * It can occur because of how we do serial console writes.  It would
+                * be nice to transmit console writes just like we normally would for
+                * a TTY line. (ie. buffered and TX interrupt driven).  That is not
+                * easy because console writes cannot sleep.  One solution might be
+                * to poll on enough port->xmit space becomming free.  -DaveM
+                */
+               if (!(status & Tx_BUF_EMP))
+                       return;
+       }
+
+       up->flags &= ~SUNZILOG_FLAG_TX_ACTIVE;
+
+       if (ZS_REGS_HELD(up)) {
+               __load_zsregs(channel, up->curregs);
+               up->flags &= ~SUNZILOG_FLAG_REGS_HELD;
+       }
+
+       if (ZS_TX_STOPPED(up)) {
+               up->flags &= ~SUNZILOG_FLAG_TX_STOPPED;
+               goto ack_tx_int;
+       }
+
+       if (up->port.x_char) {
+               up->flags |= SUNZILOG_FLAG_TX_ACTIVE;
+               writeb(up->port.x_char, &channel->data);
+               ZSDELAY();
+               ZS_WSYNC(channel);
+
+               up->port.icount.tx++;
+               up->port.x_char = 0;
+               return;
+       }
+
+       if (up->port.state == NULL)
+               goto ack_tx_int;
+       xmit = &up->port.state->xmit;
+       if (uart_circ_empty(xmit))
+               goto ack_tx_int;
+
+       if (uart_tx_stopped(&up->port))
+               goto ack_tx_int;
+
+       up->flags |= SUNZILOG_FLAG_TX_ACTIVE;
+       writeb(xmit->buf[xmit->tail], &channel->data);
+       ZSDELAY();
+       ZS_WSYNC(channel);
+
+       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+       up->port.icount.tx++;
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+       return;
+
+ack_tx_int:
+       writeb(RES_Tx_P, &channel->control);
+       ZSDELAY();
+       ZS_WSYNC(channel);
+}
+
+static irqreturn_t sunzilog_interrupt(int irq, void *dev_id)
+{
+       struct uart_sunzilog_port *up = dev_id;
+
+       while (up) {
+               struct zilog_channel __iomem *channel
+                       = ZILOG_CHANNEL_FROM_PORT(&up->port);
+               struct tty_struct *tty;
+               unsigned char r3;
+
+               spin_lock(&up->port.lock);
+               r3 = read_zsreg(channel, R3);
+
+               /* Channel A */
+               tty = NULL;
+               if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
+                       writeb(RES_H_IUS, &channel->control);
+                       ZSDELAY();
+                       ZS_WSYNC(channel);
+
+                       if (r3 & CHARxIP)
+                               tty = sunzilog_receive_chars(up, channel);
+                       if (r3 & CHAEXT)
+                               sunzilog_status_handle(up, channel);
+                       if (r3 & CHATxIP)
+                               sunzilog_transmit_chars(up, channel);
+               }
+               spin_unlock(&up->port.lock);
+
+               if (tty)
+                       tty_flip_buffer_push(tty);
+
+               /* Channel B */
+               up = up->next;
+               channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+
+               spin_lock(&up->port.lock);
+               tty = NULL;
+               if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
+                       writeb(RES_H_IUS, &channel->control);
+                       ZSDELAY();
+                       ZS_WSYNC(channel);
+
+                       if (r3 & CHBRxIP)
+                               tty = sunzilog_receive_chars(up, channel);
+                       if (r3 & CHBEXT)
+                               sunzilog_status_handle(up, channel);
+                       if (r3 & CHBTxIP)
+                               sunzilog_transmit_chars(up, channel);
+               }
+               spin_unlock(&up->port.lock);
+
+               if (tty)
+                       tty_flip_buffer_push(tty);
+
+               up = up->next;
+       }
+
+       return IRQ_HANDLED;
+}
+
+/* A convenient way to quickly get R0 status.  The caller must _not_ hold the
+ * port lock, it is acquired here.
+ */
+static __inline__ unsigned char sunzilog_read_channel_status(struct uart_port *port)
+{
+       struct zilog_channel __iomem *channel;
+       unsigned char status;
+
+       channel = ZILOG_CHANNEL_FROM_PORT(port);
+       status = readb(&channel->control);
+       ZSDELAY();
+
+       return status;
+}
+
+/* The port lock is not held.  */
+static unsigned int sunzilog_tx_empty(struct uart_port *port)
+{
+       unsigned long flags;
+       unsigned char status;
+       unsigned int ret;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       status = sunzilog_read_channel_status(port);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       if (status & Tx_BUF_EMP)
+               ret = TIOCSER_TEMT;
+       else
+               ret = 0;
+
+       return ret;
+}
+
+/* The port lock is held and interrupts are disabled.  */
+static unsigned int sunzilog_get_mctrl(struct uart_port *port)
+{
+       unsigned char status;
+       unsigned int ret;
+
+       status = sunzilog_read_channel_status(port);
+
+       ret = 0;
+       if (status & DCD)
+               ret |= TIOCM_CAR;
+       if (status & SYNC)
+               ret |= TIOCM_DSR;
+       if (status & CTS)
+               ret |= TIOCM_CTS;
+
+       return ret;
+}
+
+/* The port lock is held and interrupts are disabled.  */
+static void sunzilog_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
+       struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
+       unsigned char set_bits, clear_bits;
+
+       set_bits = clear_bits = 0;
+
+       if (mctrl & TIOCM_RTS)
+               set_bits |= RTS;
+       else
+               clear_bits |= RTS;
+       if (mctrl & TIOCM_DTR)
+               set_bits |= DTR;
+       else
+               clear_bits |= DTR;
+
+       /* NOTE: Not subject to 'transmitter active' rule.  */ 
+       up->curregs[R5] |= set_bits;
+       up->curregs[R5] &= ~clear_bits;
+       write_zsreg(channel, R5, up->curregs[R5]);
+}
+
+/* The port lock is held and interrupts are disabled.  */
+static void sunzilog_stop_tx(struct uart_port *port)
+{
+       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
+
+       up->flags |= SUNZILOG_FLAG_TX_STOPPED;
+}
+
+/* The port lock is held and interrupts are disabled.  */
+static void sunzilog_start_tx(struct uart_port *port)
+{
+       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
+       struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
+       unsigned char status;
+
+       up->flags |= SUNZILOG_FLAG_TX_ACTIVE;
+       up->flags &= ~SUNZILOG_FLAG_TX_STOPPED;
+
+       status = readb(&channel->control);
+       ZSDELAY();
+
+       /* TX busy?  Just wait for the TX done interrupt.  */
+       if (!(status & Tx_BUF_EMP))
+               return;
+
+       /* Send the first character to jump-start the TX done
+        * IRQ sending engine.
+        */
+       if (port->x_char) {
+               writeb(port->x_char, &channel->data);
+               ZSDELAY();
+               ZS_WSYNC(channel);
+
+               port->icount.tx++;
+               port->x_char = 0;
+       } else {
+               struct circ_buf *xmit = &port->state->xmit;
+
+               writeb(xmit->buf[xmit->tail], &channel->data);
+               ZSDELAY();
+               ZS_WSYNC(channel);
+
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+
+               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+                       uart_write_wakeup(&up->port);
+       }
+}
+
+/* The port lock is held.  */
+static void sunzilog_stop_rx(struct uart_port *port)
+{
+       struct uart_sunzilog_port *up = UART_ZILOG(port);
+       struct zilog_channel __iomem *channel;
+
+       if (ZS_IS_CONS(up))
+               return;
+
+       channel = ZILOG_CHANNEL_FROM_PORT(port);
+
+       /* Disable all RX interrupts.  */
+       up->curregs[R1] &= ~RxINT_MASK;
+       sunzilog_maybe_update_regs(up, channel);
+}
+
+/* The port lock is held.  */
+static void sunzilog_enable_ms(struct uart_port *port)
+{
+       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
+       struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
+       unsigned char new_reg;
+
+       new_reg = up->curregs[R15] | (DCDIE | SYNCIE | CTSIE);
+       if (new_reg != up->curregs[R15]) {
+               up->curregs[R15] = new_reg;
+
+               /* NOTE: Not subject to 'transmitter active' rule.  */ 
+               write_zsreg(channel, R15, up->curregs[R15] & ~WR7pEN);
+       }
+}
+
+/* The port lock is not held.  */
+static void sunzilog_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
+       struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
+       unsigned char set_bits, clear_bits, new_reg;
+       unsigned long flags;
+
+       set_bits = clear_bits = 0;
+
+       if (break_state)
+               set_bits |= SND_BRK;
+       else
+               clear_bits |= SND_BRK;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       new_reg = (up->curregs[R5] | set_bits) & ~clear_bits;
+       if (new_reg != up->curregs[R5]) {
+               up->curregs[R5] = new_reg;
+
+               /* NOTE: Not subject to 'transmitter active' rule.  */ 
+               write_zsreg(channel, R5, up->curregs[R5]);
+       }
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void __sunzilog_startup(struct uart_sunzilog_port *up)
+{
+       struct zilog_channel __iomem *channel;
+
+       channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+       up->prev_status = readb(&channel->control);
+
+       /* Enable receiver and transmitter.  */
+       up->curregs[R3] |= RxENAB;
+       up->curregs[R5] |= TxENAB;
+
+       up->curregs[R1] |= EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
+       sunzilog_maybe_update_regs(up, channel);
+}
+
+static int sunzilog_startup(struct uart_port *port)
+{
+       struct uart_sunzilog_port *up = UART_ZILOG(port);
+       unsigned long flags;
+
+       if (ZS_IS_CONS(up))
+               return 0;
+
+       spin_lock_irqsave(&port->lock, flags);
+       __sunzilog_startup(up);
+       spin_unlock_irqrestore(&port->lock, flags);
+       return 0;
+}
+
+/*
+ * The test for ZS_IS_CONS is explained by the following e-mail:
+ *****
+ * From: Russell King <rmk@arm.linux.org.uk>
+ * Date: Sun, 8 Dec 2002 10:18:38 +0000
+ *
+ * On Sun, Dec 08, 2002 at 02:43:36AM -0500, Pete Zaitcev wrote:
+ * > I boot my 2.5 boxes using "console=ttyS0,9600" argument,
+ * > and I noticed that something is not right with reference
+ * > counting in this case. It seems that when the console
+ * > is open by kernel initially, this is not accounted
+ * > as an open, and uart_startup is not called.
+ *
+ * That is correct.  We are unable to call uart_startup when the serial
+ * console is initialised because it may need to allocate memory (as
+ * request_irq does) and the memory allocators may not have been
+ * initialised.
+ *
+ * 1. initialise the port into a state where it can send characters in the
+ *    console write method.
+ *
+ * 2. don't do the actual hardware shutdown in your shutdown() method (but
+ *    do the normal software shutdown - ie, free irqs etc)
+ *****
+ */
+static void sunzilog_shutdown(struct uart_port *port)
+{
+       struct uart_sunzilog_port *up = UART_ZILOG(port);
+       struct zilog_channel __iomem *channel;
+       unsigned long flags;
+
+       if (ZS_IS_CONS(up))
+               return;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       channel = ZILOG_CHANNEL_FROM_PORT(port);
+
+       /* Disable receiver and transmitter.  */
+       up->curregs[R3] &= ~RxENAB;
+       up->curregs[R5] &= ~TxENAB;
+
+       /* Disable all interrupts and BRK assertion.  */
+       up->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
+       up->curregs[R5] &= ~SND_BRK;
+       sunzilog_maybe_update_regs(up, channel);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* Shared by TTY driver and serial console setup.  The port lock is held
+ * and local interrupts are disabled.
+ */
+static void
+sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag,
+                      unsigned int iflag, int brg)
+{
+
+       up->curregs[R10] = NRZ;
+       up->curregs[R11] = TCBR | RCBR;
+
+       /* Program BAUD and clock source. */
+       up->curregs[R4] &= ~XCLK_MASK;
+       up->curregs[R4] |= X16CLK;
+       up->curregs[R12] = brg & 0xff;
+       up->curregs[R13] = (brg >> 8) & 0xff;
+       up->curregs[R14] = BRSRC | BRENAB;
+
+       /* Character size, stop bits, and parity. */
+       up->curregs[R3] &= ~RxN_MASK;
+       up->curregs[R5] &= ~TxN_MASK;
+       switch (cflag & CSIZE) {
+       case CS5:
+               up->curregs[R3] |= Rx5;
+               up->curregs[R5] |= Tx5;
+               up->parity_mask = 0x1f;
+               break;
+       case CS6:
+               up->curregs[R3] |= Rx6;
+               up->curregs[R5] |= Tx6;
+               up->parity_mask = 0x3f;
+               break;
+       case CS7:
+               up->curregs[R3] |= Rx7;
+               up->curregs[R5] |= Tx7;
+               up->parity_mask = 0x7f;
+               break;
+       case CS8:
+       default:
+               up->curregs[R3] |= Rx8;
+               up->curregs[R5] |= Tx8;
+               up->parity_mask = 0xff;
+               break;
+       };
+       up->curregs[R4] &= ~0x0c;
+       if (cflag & CSTOPB)
+               up->curregs[R4] |= SB2;
+       else
+               up->curregs[R4] |= SB1;
+       if (cflag & PARENB)
+               up->curregs[R4] |= PAR_ENAB;
+       else
+               up->curregs[R4] &= ~PAR_ENAB;
+       if (!(cflag & PARODD))
+               up->curregs[R4] |= PAR_EVEN;
+       else
+               up->curregs[R4] &= ~PAR_EVEN;
+
+       up->port.read_status_mask = Rx_OVR;
+       if (iflag & INPCK)
+               up->port.read_status_mask |= CRC_ERR | PAR_ERR;
+       if (iflag & (BRKINT | PARMRK))
+               up->port.read_status_mask |= BRK_ABRT;
+
+       up->port.ignore_status_mask = 0;
+       if (iflag & IGNPAR)
+               up->port.ignore_status_mask |= CRC_ERR | PAR_ERR;
+       if (iflag & IGNBRK) {
+               up->port.ignore_status_mask |= BRK_ABRT;
+               if (iflag & IGNPAR)
+                       up->port.ignore_status_mask |= Rx_OVR;
+       }
+
+       if ((cflag & CREAD) == 0)
+               up->port.ignore_status_mask = 0xff;
+}
+
+/* The port lock is not held.  */
+static void
+sunzilog_set_termios(struct uart_port *port, struct ktermios *termios,
+                    struct ktermios *old)
+{
+       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
+       unsigned long flags;
+       int baud, brg;
+
+       baud = uart_get_baud_rate(port, termios, old, 1200, 76800);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
+
+       sunzilog_convert_to_zs(up, termios->c_cflag, termios->c_iflag, brg);
+
+       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
+               up->flags |= SUNZILOG_FLAG_MODEM_STATUS;
+       else
+               up->flags &= ~SUNZILOG_FLAG_MODEM_STATUS;
+
+       up->cflag = termios->c_cflag;
+
+       sunzilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port));
+
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static const char *sunzilog_type(struct uart_port *port)
+{
+       struct uart_sunzilog_port *up = UART_ZILOG(port);
+
+       return (up->flags & SUNZILOG_FLAG_ESCC) ? "zs (ESCC)" : "zs";
+}
+
+/* We do not request/release mappings of the registers here, this
+ * happens at early serial probe time.
+ */
+static void sunzilog_release_port(struct uart_port *port)
+{
+}
+
+static int sunzilog_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+/* These do not need to do anything interesting either.  */
+static void sunzilog_config_port(struct uart_port *port, int flags)
+{
+}
+
+/* We do not support letting the user mess with the divisor, IRQ, etc. */
+static int sunzilog_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       return -EINVAL;
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+static int sunzilog_get_poll_char(struct uart_port *port)
+{
+       unsigned char ch, r1;
+       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
+       struct zilog_channel __iomem *channel
+               = ZILOG_CHANNEL_FROM_PORT(&up->port);
+
+
+       r1 = read_zsreg(channel, R1);
+       if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
+               writeb(ERR_RES, &channel->control);
+               ZSDELAY();
+               ZS_WSYNC(channel);
+       }
+
+       ch = readb(&channel->control);
+       ZSDELAY();
+
+       /* This funny hack depends upon BRK_ABRT not interfering
+        * with the other bits we care about in R1.
+        */
+       if (ch & BRK_ABRT)
+               r1 |= BRK_ABRT;
+
+       if (!(ch & Rx_CH_AV))
+               return NO_POLL_CHAR;
+
+       ch = readb(&channel->data);
+       ZSDELAY();
+
+       ch &= up->parity_mask;
+       return ch;
+}
+
+static void sunzilog_put_poll_char(struct uart_port *port,
+                       unsigned char ch)
+{
+       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *)port;
+
+       sunzilog_putchar(&up->port, ch);
+}
+#endif /* CONFIG_CONSOLE_POLL */
+
+static struct uart_ops sunzilog_pops = {
+       .tx_empty       =       sunzilog_tx_empty,
+       .set_mctrl      =       sunzilog_set_mctrl,
+       .get_mctrl      =       sunzilog_get_mctrl,
+       .stop_tx        =       sunzilog_stop_tx,
+       .start_tx       =       sunzilog_start_tx,
+       .stop_rx        =       sunzilog_stop_rx,
+       .enable_ms      =       sunzilog_enable_ms,
+       .break_ctl      =       sunzilog_break_ctl,
+       .startup        =       sunzilog_startup,
+       .shutdown       =       sunzilog_shutdown,
+       .set_termios    =       sunzilog_set_termios,
+       .type           =       sunzilog_type,
+       .release_port   =       sunzilog_release_port,
+       .request_port   =       sunzilog_request_port,
+       .config_port    =       sunzilog_config_port,
+       .verify_port    =       sunzilog_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char  =       sunzilog_get_poll_char,
+       .poll_put_char  =       sunzilog_put_poll_char,
+#endif
+};
+
+static int uart_chip_count;
+static struct uart_sunzilog_port *sunzilog_port_table;
+static struct zilog_layout __iomem **sunzilog_chip_regs;
+
+static struct uart_sunzilog_port *sunzilog_irq_chain;
+
+static struct uart_driver sunzilog_reg = {
+       .owner          =       THIS_MODULE,
+       .driver_name    =       "sunzilog",
+       .dev_name       =       "ttyS",
+       .major          =       TTY_MAJOR,
+};
+
+static int __init sunzilog_alloc_tables(int num_sunzilog)
+{
+       struct uart_sunzilog_port *up;
+       unsigned long size;
+       int num_channels = num_sunzilog * 2;
+       int i;
+
+       size = num_channels * sizeof(struct uart_sunzilog_port);
+       sunzilog_port_table = kzalloc(size, GFP_KERNEL);
+       if (!sunzilog_port_table)
+               return -ENOMEM;
+
+       for (i = 0; i < num_channels; i++) {
+               up = &sunzilog_port_table[i];
+
+               spin_lock_init(&up->port.lock);
+
+               if (i == 0)
+                       sunzilog_irq_chain = up;
+
+               if (i < num_channels - 1)
+                       up->next = up + 1;
+               else
+                       up->next = NULL;
+       }
+
+       size = num_sunzilog * sizeof(struct zilog_layout __iomem *);
+       sunzilog_chip_regs = kzalloc(size, GFP_KERNEL);
+       if (!sunzilog_chip_regs) {
+               kfree(sunzilog_port_table);
+               sunzilog_irq_chain = NULL;
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void sunzilog_free_tables(void)
+{
+       kfree(sunzilog_port_table);
+       sunzilog_irq_chain = NULL;
+       kfree(sunzilog_chip_regs);
+}
+
+#define ZS_PUT_CHAR_MAX_DELAY  2000    /* 10 ms */
+
+static void sunzilog_putchar(struct uart_port *port, int ch)
+{
+       struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
+       int loops = ZS_PUT_CHAR_MAX_DELAY;
+
+       /* This is a timed polling loop so do not switch the explicit
+        * udelay with ZSDELAY as that is a NOP on some platforms.  -DaveM
+        */
+       do {
+               unsigned char val = readb(&channel->control);
+               if (val & Tx_BUF_EMP) {
+                       ZSDELAY();
+                       break;
+               }
+               udelay(5);
+       } while (--loops);
+
+       writeb(ch, &channel->data);
+       ZSDELAY();
+       ZS_WSYNC(channel);
+}
+
+#ifdef CONFIG_SERIO
+
+static DEFINE_SPINLOCK(sunzilog_serio_lock);
+
+static int sunzilog_serio_write(struct serio *serio, unsigned char ch)
+{
+       struct uart_sunzilog_port *up = serio->port_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sunzilog_serio_lock, flags);
+
+       sunzilog_putchar(&up->port, ch);
+
+       spin_unlock_irqrestore(&sunzilog_serio_lock, flags);
+
+       return 0;
+}
+
+static int sunzilog_serio_open(struct serio *serio)
+{
+       struct uart_sunzilog_port *up = serio->port_data;
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&sunzilog_serio_lock, flags);
+       if (!up->serio_open) {
+               up->serio_open = 1;
+               ret = 0;
+       } else
+               ret = -EBUSY;
+       spin_unlock_irqrestore(&sunzilog_serio_lock, flags);
+
+       return ret;
+}
+
+static void sunzilog_serio_close(struct serio *serio)
+{
+       struct uart_sunzilog_port *up = serio->port_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sunzilog_serio_lock, flags);
+       up->serio_open = 0;
+       spin_unlock_irqrestore(&sunzilog_serio_lock, flags);
+}
+
+#endif /* CONFIG_SERIO */
+
+#ifdef CONFIG_SERIAL_SUNZILOG_CONSOLE
+static void
+sunzilog_console_write(struct console *con, const char *s, unsigned int count)
+{
+       struct uart_sunzilog_port *up = &sunzilog_port_table[con->index];
+       unsigned long flags;
+       int locked = 1;
+
+       local_irq_save(flags);
+       if (up->port.sysrq) {
+               locked = 0;
+       } else if (oops_in_progress) {
+               locked = spin_trylock(&up->port.lock);
+       } else
+               spin_lock(&up->port.lock);
+
+       uart_console_write(&up->port, s, count, sunzilog_putchar);
+       udelay(2);
+
+       if (locked)
+               spin_unlock(&up->port.lock);
+       local_irq_restore(flags);
+}
+
+static int __init sunzilog_console_setup(struct console *con, char *options)
+{
+       struct uart_sunzilog_port *up = &sunzilog_port_table[con->index];
+       unsigned long flags;
+       int baud, brg;
+
+       if (up->port.type != PORT_SUNZILOG)
+               return -1;
+
+       printk(KERN_INFO "Console: ttyS%d (SunZilog zs%d)\n",
+              (sunzilog_reg.minor - 64) + con->index, con->index);
+
+       /* Get firmware console settings.  */
+       sunserial_console_termios(con, up->port.dev->of_node);
+
+       /* Firmware console speed is limited to 150-->38400 baud so
+        * this hackish cflag thing is OK.
+        */
+       switch (con->cflag & CBAUD) {
+       case B150: baud = 150; break;
+       case B300: baud = 300; break;
+       case B600: baud = 600; break;
+       case B1200: baud = 1200; break;
+       case B2400: baud = 2400; break;
+       case B4800: baud = 4800; break;
+       default: case B9600: baud = 9600; break;
+       case B19200: baud = 19200; break;
+       case B38400: baud = 38400; break;
+       };
+
+       brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       up->curregs[R15] |= BRKIE;
+       sunzilog_convert_to_zs(up, con->cflag, 0, brg);
+
+       sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
+       __sunzilog_startup(up);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       return 0;
+}
+
+static struct console sunzilog_console_ops = {
+       .name   =       "ttyS",
+       .write  =       sunzilog_console_write,
+       .device =       uart_console_device,
+       .setup  =       sunzilog_console_setup,
+       .flags  =       CON_PRINTBUFFER,
+       .index  =       -1,
+       .data   =       &sunzilog_reg,
+};
+
+static inline struct console *SUNZILOG_CONSOLE(void)
+{
+       return &sunzilog_console_ops;
+}
+
+#else
+#define SUNZILOG_CONSOLE()     (NULL)
+#endif
+
+static void __devinit sunzilog_init_kbdms(struct uart_sunzilog_port *up)
+{
+       int baud, brg;
+
+       if (up->flags & SUNZILOG_FLAG_CONS_KEYB) {
+               up->cflag = B1200 | CS8 | CLOCAL | CREAD;
+               baud = 1200;
+       } else {
+               up->cflag = B4800 | CS8 | CLOCAL | CREAD;
+               baud = 4800;
+       }
+
+       up->curregs[R15] |= BRKIE;
+       brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
+       sunzilog_convert_to_zs(up, up->cflag, 0, brg);
+       sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
+       __sunzilog_startup(up);
+}
+
+#ifdef CONFIG_SERIO
+static void __devinit sunzilog_register_serio(struct uart_sunzilog_port *up)
+{
+       struct serio *serio = &up->serio;
+
+       serio->port_data = up;
+
+       serio->id.type = SERIO_RS232;
+       if (up->flags & SUNZILOG_FLAG_CONS_KEYB) {
+               serio->id.proto = SERIO_SUNKBD;
+               strlcpy(serio->name, "zskbd", sizeof(serio->name));
+       } else {
+               serio->id.proto = SERIO_SUN;
+               serio->id.extra = 1;
+               strlcpy(serio->name, "zsms", sizeof(serio->name));
+       }
+       strlcpy(serio->phys,
+               ((up->flags & SUNZILOG_FLAG_CONS_KEYB) ?
+                "zs/serio0" : "zs/serio1"),
+               sizeof(serio->phys));
+
+       serio->write = sunzilog_serio_write;
+       serio->open = sunzilog_serio_open;
+       serio->close = sunzilog_serio_close;
+       serio->dev.parent = up->port.dev;
+
+       serio_register_port(serio);
+}
+#endif
+
+static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
+{
+       struct zilog_channel __iomem *channel;
+       unsigned long flags;
+       int baud, brg;
+
+       channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       if (ZS_IS_CHANNEL_A(up)) {
+               write_zsreg(channel, R9, FHWRES);
+               ZSDELAY_LONG();
+               (void) read_zsreg(channel, R0);
+       }
+
+       if (up->flags & (SUNZILOG_FLAG_CONS_KEYB |
+                        SUNZILOG_FLAG_CONS_MOUSE)) {
+               up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
+               up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
+               up->curregs[R3] = RxENAB | Rx8;
+               up->curregs[R5] = TxENAB | Tx8;
+               up->curregs[R6] = 0x00; /* SDLC Address */
+               up->curregs[R7] = 0x7E; /* SDLC Flag    */
+               up->curregs[R9] = NV;
+               up->curregs[R7p] = 0x00;
+               sunzilog_init_kbdms(up);
+               /* Only enable interrupts if an ISR handler available */
+               if (up->flags & SUNZILOG_FLAG_ISR_HANDLER)
+                       up->curregs[R9] |= MIE;
+               write_zsreg(channel, R9, up->curregs[R9]);
+       } else {
+               /* Normal serial TTY. */
+               up->parity_mask = 0xff;
+               up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
+               up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
+               up->curregs[R3] = RxENAB | Rx8;
+               up->curregs[R5] = TxENAB | Tx8;
+               up->curregs[R6] = 0x00; /* SDLC Address */
+               up->curregs[R7] = 0x7E; /* SDLC Flag    */
+               up->curregs[R9] = NV;
+               up->curregs[R10] = NRZ;
+               up->curregs[R11] = TCBR | RCBR;
+               baud = 9600;
+               brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
+               up->curregs[R12] = (brg & 0xff);
+               up->curregs[R13] = (brg >> 8) & 0xff;
+               up->curregs[R14] = BRSRC | BRENAB;
+               up->curregs[R15] = FIFOEN; /* Use FIFO if on ESCC */
+               up->curregs[R7p] = TxFIFO_LVL | RxFIFO_LVL;
+               if (__load_zsregs(channel, up->curregs)) {
+                       up->flags |= SUNZILOG_FLAG_ESCC;
+               }
+               /* Only enable interrupts if an ISR handler available */
+               if (up->flags & SUNZILOG_FLAG_ISR_HANDLER)
+                       up->curregs[R9] |= MIE;
+               write_zsreg(channel, R9, up->curregs[R9]);
+       }
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+#ifdef CONFIG_SERIO
+       if (up->flags & (SUNZILOG_FLAG_CONS_KEYB |
+                        SUNZILOG_FLAG_CONS_MOUSE))
+               sunzilog_register_serio(up);
+#endif
+}
+
+static int zilog_irq = -1;
+
+static int __devinit zs_probe(struct platform_device *op, const struct of_device_id *match)
+{
+       static int kbm_inst, uart_inst;
+       int inst;
+       struct uart_sunzilog_port *up;
+       struct zilog_layout __iomem *rp;
+       int keyboard_mouse = 0;
+       int err;
+
+       if (of_find_property(op->dev.of_node, "keyboard", NULL))
+               keyboard_mouse = 1;
+
+       /* uarts must come before keyboards/mice */
+       if (keyboard_mouse)
+               inst = uart_chip_count + kbm_inst;
+       else
+               inst = uart_inst;
+
+       sunzilog_chip_regs[inst] = of_ioremap(&op->resource[0], 0,
+                                             sizeof(struct zilog_layout),
+                                             "zs");
+       if (!sunzilog_chip_regs[inst])
+               return -ENOMEM;
+
+       rp = sunzilog_chip_regs[inst];
+
+       if (zilog_irq == -1)
+               zilog_irq = op->archdata.irqs[0];
+
+       up = &sunzilog_port_table[inst * 2];
+
+       /* Channel A */
+       up[0].port.mapbase = op->resource[0].start + 0x00;
+       up[0].port.membase = (void __iomem *) &rp->channelA;
+       up[0].port.iotype = UPIO_MEM;
+       up[0].port.irq = op->archdata.irqs[0];
+       up[0].port.uartclk = ZS_CLOCK;
+       up[0].port.fifosize = 1;
+       up[0].port.ops = &sunzilog_pops;
+       up[0].port.type = PORT_SUNZILOG;
+       up[0].port.flags = 0;
+       up[0].port.line = (inst * 2) + 0;
+       up[0].port.dev = &op->dev;
+       up[0].flags |= SUNZILOG_FLAG_IS_CHANNEL_A;
+       if (keyboard_mouse)
+               up[0].flags |= SUNZILOG_FLAG_CONS_KEYB;
+       sunzilog_init_hw(&up[0]);
+
+       /* Channel B */
+       up[1].port.mapbase = op->resource[0].start + 0x04;
+       up[1].port.membase = (void __iomem *) &rp->channelB;
+       up[1].port.iotype = UPIO_MEM;
+       up[1].port.irq = op->archdata.irqs[0];
+       up[1].port.uartclk = ZS_CLOCK;
+       up[1].port.fifosize = 1;
+       up[1].port.ops = &sunzilog_pops;
+       up[1].port.type = PORT_SUNZILOG;
+       up[1].port.flags = 0;
+       up[1].port.line = (inst * 2) + 1;
+       up[1].port.dev = &op->dev;
+       up[1].flags |= 0;
+       if (keyboard_mouse)
+               up[1].flags |= SUNZILOG_FLAG_CONS_MOUSE;
+       sunzilog_init_hw(&up[1]);
+
+       if (!keyboard_mouse) {
+               if (sunserial_console_match(SUNZILOG_CONSOLE(), op->dev.of_node,
+                                           &sunzilog_reg, up[0].port.line,
+                                           false))
+                       up->flags |= SUNZILOG_FLAG_IS_CONS;
+               err = uart_add_one_port(&sunzilog_reg, &up[0].port);
+               if (err) {
+                       of_iounmap(&op->resource[0],
+                                  rp, sizeof(struct zilog_layout));
+                       return err;
+               }
+               if (sunserial_console_match(SUNZILOG_CONSOLE(), op->dev.of_node,
+                                           &sunzilog_reg, up[1].port.line,
+                                           false))
+                       up->flags |= SUNZILOG_FLAG_IS_CONS;
+               err = uart_add_one_port(&sunzilog_reg, &up[1].port);
+               if (err) {
+                       uart_remove_one_port(&sunzilog_reg, &up[0].port);
+                       of_iounmap(&op->resource[0],
+                                  rp, sizeof(struct zilog_layout));
+                       return err;
+               }
+               uart_inst++;
+       } else {
+               printk(KERN_INFO "%s: Keyboard at MMIO 0x%llx (irq = %d) "
+                      "is a %s\n",
+                      dev_name(&op->dev),
+                      (unsigned long long) up[0].port.mapbase,
+                      op->archdata.irqs[0], sunzilog_type(&up[0].port));
+               printk(KERN_INFO "%s: Mouse at MMIO 0x%llx (irq = %d) "
+                      "is a %s\n",
+                      dev_name(&op->dev),
+                      (unsigned long long) up[1].port.mapbase,
+                      op->archdata.irqs[0], sunzilog_type(&up[1].port));
+               kbm_inst++;
+       }
+
+       dev_set_drvdata(&op->dev, &up[0]);
+
+       return 0;
+}
+
+static void __devexit zs_remove_one(struct uart_sunzilog_port *up)
+{
+       if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) {
+#ifdef CONFIG_SERIO
+               serio_unregister_port(&up->serio);
+#endif
+       } else
+               uart_remove_one_port(&sunzilog_reg, &up->port);
+}
+
+static int __devexit zs_remove(struct platform_device *op)
+{
+       struct uart_sunzilog_port *up = dev_get_drvdata(&op->dev);
+       struct zilog_layout __iomem *regs;
+
+       zs_remove_one(&up[0]);
+       zs_remove_one(&up[1]);
+
+       regs = sunzilog_chip_regs[up[0].port.line / 2];
+       of_iounmap(&op->resource[0], regs, sizeof(struct zilog_layout));
+
+       dev_set_drvdata(&op->dev, NULL);
+
+       return 0;
+}
+
+static const struct of_device_id zs_match[] = {
+       {
+               .name = "zs",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, zs_match);
+
+static struct of_platform_driver zs_driver = {
+       .driver = {
+               .name = "zs",
+               .owner = THIS_MODULE,
+               .of_match_table = zs_match,
+       },
+       .probe          = zs_probe,
+       .remove         = __devexit_p(zs_remove),
+};
+
+static int __init sunzilog_init(void)
+{
+       struct device_node *dp;
+       int err;
+       int num_keybms = 0;
+       int num_sunzilog = 0;
+
+       for_each_node_by_name(dp, "zs") {
+               num_sunzilog++;
+               if (of_find_property(dp, "keyboard", NULL))
+                       num_keybms++;
+       }
+
+       if (num_sunzilog) {
+               err = sunzilog_alloc_tables(num_sunzilog);
+               if (err)
+                       goto out;
+
+               uart_chip_count = num_sunzilog - num_keybms;
+
+               err = sunserial_register_minors(&sunzilog_reg,
+                                               uart_chip_count * 2);
+               if (err)
+                       goto out_free_tables;
+       }
+
+       err = of_register_platform_driver(&zs_driver);
+       if (err)
+               goto out_unregister_uart;
+
+       if (zilog_irq != -1) {
+               struct uart_sunzilog_port *up = sunzilog_irq_chain;
+               err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED,
+                                 "zs", sunzilog_irq_chain);
+               if (err)
+                       goto out_unregister_driver;
+
+               /* Enable Interrupts */
+               while (up) {
+                       struct zilog_channel __iomem *channel;
+
+                       /* printk (KERN_INFO "Enable IRQ for ZILOG Hardware %p\n", up); */
+                       channel          = ZILOG_CHANNEL_FROM_PORT(&up->port);
+                       up->flags       |= SUNZILOG_FLAG_ISR_HANDLER;
+                       up->curregs[R9] |= MIE;
+                       write_zsreg(channel, R9, up->curregs[R9]);
+                       up = up->next;
+               }
+       }
+
+out:
+       return err;
+
+out_unregister_driver:
+       of_unregister_platform_driver(&zs_driver);
+
+out_unregister_uart:
+       if (num_sunzilog) {
+               sunserial_unregister_minors(&sunzilog_reg, num_sunzilog);
+               sunzilog_reg.cons = NULL;
+       }
+
+out_free_tables:
+       sunzilog_free_tables();
+       goto out;
+}
+
+static void __exit sunzilog_exit(void)
+{
+       of_unregister_platform_driver(&zs_driver);
+
+       if (zilog_irq != -1) {
+               struct uart_sunzilog_port *up = sunzilog_irq_chain;
+
+               /* Disable Interrupts */
+               while (up) {
+                       struct zilog_channel __iomem *channel;
+
+                       /* printk (KERN_INFO "Disable IRQ for ZILOG Hardware %p\n", up); */
+                       channel          = ZILOG_CHANNEL_FROM_PORT(&up->port);
+                       up->flags       &= ~SUNZILOG_FLAG_ISR_HANDLER;
+                       up->curregs[R9] &= ~MIE;
+                       write_zsreg(channel, R9, up->curregs[R9]);
+                       up = up->next;
+               }
+
+               free_irq(zilog_irq, sunzilog_irq_chain);
+               zilog_irq = -1;
+       }
+
+       if (sunzilog_reg.nr) {
+               sunserial_unregister_minors(&sunzilog_reg, sunzilog_reg.nr);
+               sunzilog_free_tables();
+       }
+}
+
+module_init(sunzilog_init);
+module_exit(sunzilog_exit);
+
+MODULE_AUTHOR("David S. Miller");
+MODULE_DESCRIPTION("Sun Zilog serial port driver");
+MODULE_VERSION("2.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/sunzilog.h b/drivers/tty/serial/sunzilog.h
new file mode 100644 (file)
index 0000000..5dec7b4
--- /dev/null
@@ -0,0 +1,289 @@
+#ifndef _SUNZILOG_H
+#define _SUNZILOG_H
+
+struct zilog_channel {
+       volatile unsigned char control;
+       volatile unsigned char __pad1;
+       volatile unsigned char data;
+       volatile unsigned char __pad2;
+};
+
+struct zilog_layout {
+       struct zilog_channel channelB;
+       struct zilog_channel channelA;
+};
+
+#define        NUM_ZSREGS      17
+#define        R7p             16 /* Written as R7 with P15 bit 0 set */
+
+/* Conversion routines to/from brg time constants from/to bits
+ * per second.
+ */
+#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+/* The Zilog register set */
+
+#define        FLAG    0x7e
+
+/* Write Register 0 */
+#define        R0      0               /* Register selects */
+#define        R1      1
+#define        R2      2
+#define        R3      3
+#define        R4      4
+#define        R5      5
+#define        R6      6
+#define        R7      7
+#define        R8      8
+#define        R9      9
+#define        R10     10
+#define        R11     11
+#define        R12     12
+#define        R13     13
+#define        R14     14
+#define        R15     15
+
+#define        NULLCODE        0       /* Null Code */
+#define        POINT_HIGH      0x8     /* Select upper half of registers */
+#define        RES_EXT_INT     0x10    /* Reset Ext. Status Interrupts */
+#define        SEND_ABORT      0x18    /* HDLC Abort */
+#define        RES_RxINT_FC    0x20    /* Reset RxINT on First Character */
+#define        RES_Tx_P        0x28    /* Reset TxINT Pending */
+#define        ERR_RES         0x30    /* Error Reset */
+#define        RES_H_IUS       0x38    /* Reset highest IUS */
+
+#define        RES_Rx_CRC      0x40    /* Reset Rx CRC Checker */
+#define        RES_Tx_CRC      0x80    /* Reset Tx CRC Checker */
+#define        RES_EOM_L       0xC0    /* Reset EOM latch */
+
+/* Write Register 1 */
+
+#define        EXT_INT_ENAB    0x1     /* Ext Int Enable */
+#define        TxINT_ENAB      0x2     /* Tx Int Enable */
+#define        PAR_SPEC        0x4     /* Parity is special condition */
+
+#define        RxINT_DISAB     0       /* Rx Int Disable */
+#define        RxINT_FCERR     0x8     /* Rx Int on First Character Only or Error */
+#define        INT_ALL_Rx      0x10    /* Int on all Rx Characters or error */
+#define        INT_ERR_Rx      0x18    /* Int on error only */
+#define RxINT_MASK     0x18
+
+#define        WT_RDY_RT       0x20    /* Wait/Ready on R/T */
+#define        WT_FN_RDYFN     0x40    /* Wait/FN/Ready FN */
+#define        WT_RDY_ENAB     0x80    /* Wait/Ready Enable */
+
+/* Write Register #2 (Interrupt Vector) */
+
+/* Write Register 3 */
+
+#define        RxENAB          0x1     /* Rx Enable */
+#define        SYNC_L_INH      0x2     /* Sync Character Load Inhibit */
+#define        ADD_SM          0x4     /* Address Search Mode (SDLC) */
+#define        RxCRC_ENAB      0x8     /* Rx CRC Enable */
+#define        ENT_HM          0x10    /* Enter Hunt Mode */
+#define        AUTO_ENAB       0x20    /* Auto Enables */
+#define        Rx5             0x0     /* Rx 5 Bits/Character */
+#define        Rx7             0x40    /* Rx 7 Bits/Character */
+#define        Rx6             0x80    /* Rx 6 Bits/Character */
+#define        Rx8             0xc0    /* Rx 8 Bits/Character */
+#define RxN_MASK       0xc0
+
+/* Write Register 4 */
+
+#define        PAR_ENAB        0x1     /* Parity Enable */
+#define        PAR_EVEN        0x2     /* Parity Even/Odd* */
+
+#define        SYNC_ENAB       0       /* Sync Modes Enable */
+#define        SB1             0x4     /* 1 stop bit/char */
+#define        SB15            0x8     /* 1.5 stop bits/char */
+#define        SB2             0xc     /* 2 stop bits/char */
+
+#define        MONSYNC         0       /* 8 Bit Sync character */
+#define        BISYNC          0x10    /* 16 bit sync character */
+#define        SDLC            0x20    /* SDLC Mode (01111110 Sync Flag) */
+#define        EXTSYNC         0x30    /* External Sync Mode */
+
+#define        X1CLK           0x0     /* x1 clock mode */
+#define        X16CLK          0x40    /* x16 clock mode */
+#define        X32CLK          0x80    /* x32 clock mode */
+#define        X64CLK          0xC0    /* x64 clock mode */
+#define XCLK_MASK      0xC0
+
+/* Write Register 5 */
+
+#define        TxCRC_ENAB      0x1     /* Tx CRC Enable */
+#define        RTS             0x2     /* RTS */
+#define        SDLC_CRC        0x4     /* SDLC/CRC-16 */
+#define        TxENAB          0x8     /* Tx Enable */
+#define        SND_BRK         0x10    /* Send Break */
+#define        Tx5             0x0     /* Tx 5 bits (or less)/character */
+#define        Tx7             0x20    /* Tx 7 bits/character */
+#define        Tx6             0x40    /* Tx 6 bits/character */
+#define        Tx8             0x60    /* Tx 8 bits/character */
+#define TxN_MASK       0x60
+#define        DTR             0x80    /* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 7' (ESCC Only) */
+#define        AUTO_TxFLAG     1       /* Automatic Tx SDLC Flag */
+#define        AUTO_EOM_RST    2       /* Automatic EOM Reset */
+#define        AUTOnRTS        4       /* Automatic /RTS pin deactivation */
+#define        RxFIFO_LVL      8       /* Receive FIFO interrupt level */
+#define        nDTRnREQ        0x10    /* /DTR/REQ timing */
+#define        TxFIFO_LVL      0x20    /* Transmit FIFO interrupt level */
+#define        EXT_RD_EN       0x40    /* Extended read register enable */
+
+/* Write Register 8 (transmit buffer) */
+
+/* Write Register 9 (Master interrupt control) */
+#define        VIS     1       /* Vector Includes Status */
+#define        NV      2       /* No Vector */
+#define        DLC     4       /* Disable Lower Chain */
+#define        MIE     8       /* Master Interrupt Enable */
+#define        STATHI  0x10    /* Status high */
+#define        SWIACK  0x20    /* Software Interrupt Ack (not on NMOS) */
+#define        NORESET 0       /* No reset on write to R9 */
+#define        CHRB    0x40    /* Reset channel B */
+#define        CHRA    0x80    /* Reset channel A */
+#define        FHWRES  0xc0    /* Force hardware reset */
+
+/* Write Register 10 (misc control bits) */
+#define        BIT6    1       /* 6 bit/8bit sync */
+#define        LOOPMODE 2      /* SDLC Loop mode */
+#define        ABUNDER 4       /* Abort/flag on SDLC xmit underrun */
+#define        MARKIDLE 8      /* Mark/flag on idle */
+#define        GAOP    0x10    /* Go active on poll */
+#define        NRZ     0       /* NRZ mode */
+#define        NRZI    0x20    /* NRZI mode */
+#define        FM1     0x40    /* FM1 (transition = 1) */
+#define        FM0     0x60    /* FM0 (transition = 0) */
+#define        CRCPS   0x80    /* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode control) */
+#define        TRxCXT  0       /* TRxC = Xtal output */
+#define        TRxCTC  1       /* TRxC = Transmit clock */
+#define        TRxCBR  2       /* TRxC = BR Generator Output */
+#define        TRxCDP  3       /* TRxC = DPLL output */
+#define        TRxCOI  4       /* TRxC O/I */
+#define        TCRTxCP 0       /* Transmit clock = RTxC pin */
+#define        TCTRxCP 8       /* Transmit clock = TRxC pin */
+#define        TCBR    0x10    /* Transmit clock = BR Generator output */
+#define        TCDPLL  0x18    /* Transmit clock = DPLL output */
+#define        RCRTxCP 0       /* Receive clock = RTxC pin */
+#define        RCTRxCP 0x20    /* Receive clock = TRxC pin */
+#define        RCBR    0x40    /* Receive clock = BR Generator output */
+#define        RCDPLL  0x60    /* Receive clock = DPLL output */
+#define        RTxCX   0x80    /* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (lower byte of baud rate generator time constant) */
+
+/* Write Register 13 (upper byte of baud rate generator time constant) */
+
+/* Write Register 14 (Misc control bits) */
+#define        BRENAB  1       /* Baud rate generator enable */
+#define        BRSRC   2       /* Baud rate generator source */
+#define        DTRREQ  4       /* DTR/Request function */
+#define        AUTOECHO 8      /* Auto Echo */
+#define        LOOPBAK 0x10    /* Local loopback */
+#define        SEARCH  0x20    /* Enter search mode */
+#define        RMC     0x40    /* Reset missing clock */
+#define        DISDPLL 0x60    /* Disable DPLL */
+#define        SSBR    0x80    /* Set DPLL source = BR generator */
+#define        SSRTxC  0xa0    /* Set DPLL source = RTxC */
+#define        SFMM    0xc0    /* Set FM mode */
+#define        SNRZI   0xe0    /* Set NRZI mode */
+
+/* Write Register 15 (external/status interrupt control) */
+#define        WR7pEN  1       /* WR7' Enable (ESCC only) */
+#define        ZCIE    2       /* Zero count IE */
+#define        FIFOEN  4       /* FIFO Enable (ESCC only) */
+#define        DCDIE   8       /* DCD IE */
+#define        SYNCIE  0x10    /* Sync/hunt IE */
+#define        CTSIE   0x20    /* CTS IE */
+#define        TxUIE   0x40    /* Tx Underrun/EOM IE */
+#define        BRKIE   0x80    /* Break/Abort IE */
+
+
+/* Read Register 0 */
+#define        Rx_CH_AV        0x1     /* Rx Character Available */
+#define        ZCOUNT          0x2     /* Zero count */
+#define        Tx_BUF_EMP      0x4     /* Tx Buffer empty */
+#define        DCD             0x8     /* DCD */
+#define        SYNC            0x10    /* Sync/hunt */
+#define        CTS             0x20    /* CTS */
+#define        TxEOM           0x40    /* Tx underrun */
+#define        BRK_ABRT        0x80    /* Break/Abort */
+
+/* Read Register 1 */
+#define        ALL_SNT         0x1     /* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define        RES3            0x8     /* 0/3 */
+#define        RES4            0x4     /* 0/4 */
+#define        RES5            0xc     /* 0/5 */
+#define        RES6            0x2     /* 0/6 */
+#define        RES7            0xa     /* 0/7 */
+#define        RES8            0x6     /* 0/8 */
+#define        RES18           0xe     /* 1/8 */
+#define        RES28           0x0     /* 2/8 */
+/* Special Rx Condition Interrupts */
+#define        PAR_ERR         0x10    /* Parity error */
+#define        Rx_OVR          0x20    /* Rx Overrun Error */
+#define        CRC_ERR         0x40    /* CRC/Framing Error */
+#define        END_FR          0x80    /* End of Frame (SDLC) */
+
+/* Read Register 2 (channel b only) - Interrupt vector */
+#define CHB_Tx_EMPTY   0x00
+#define CHB_EXT_STAT   0x02
+#define CHB_Rx_AVAIL   0x04
+#define CHB_SPECIAL    0x06
+#define CHA_Tx_EMPTY   0x08
+#define CHA_EXT_STAT   0x0a
+#define CHA_Rx_AVAIL   0x0c
+#define CHA_SPECIAL    0x0e
+#define STATUS_MASK    0x0e
+
+/* Read Register 3 (interrupt pending register) ch a only */
+#define        CHBEXT  0x1             /* Channel B Ext/Stat IP */
+#define        CHBTxIP 0x2             /* Channel B Tx IP */
+#define        CHBRxIP 0x4             /* Channel B Rx IP */
+#define        CHAEXT  0x8             /* Channel A Ext/Stat IP */
+#define        CHATxIP 0x10            /* Channel A Tx IP */
+#define        CHARxIP 0x20            /* Channel A Rx IP */
+
+/* Read Register 6 (LSB frame byte count [Not on NMOS]) */
+
+/* Read Register 7 (MSB frame byte count and FIFO status [Not on NMOS]) */
+
+/* Read Register 8 (receive data register) */
+
+/* Read Register 10  (misc status bits) */
+#define        ONLOOP  2               /* On loop */
+#define        LOOPSEND 0x10           /* Loop sending */
+#define        CLK2MIS 0x40            /* Two clocks missing */
+#define        CLK1MIS 0x80            /* One clock missing */
+
+/* Read Register 12 (lower byte of baud rate generator constant) */
+
+/* Read Register 13 (upper byte of baud rate generator constant) */
+
+/* Read Register 15 (value of WR 15) */
+
+/* Misc macros */
+#define ZS_CLEARERR(channel)    do { sbus_writeb(ERR_RES, &channel->control); \
+                                    udelay(5); } while(0)
+
+#define ZS_CLEARSTAT(channel)   do { sbus_writeb(RES_EXT_INT, &channel->control); \
+                                    udelay(5); } while(0)
+
+#define ZS_CLEARFIFO(channel)   do { sbus_readb(&channel->data); \
+                                    udelay(2); \
+                                    sbus_readb(&channel->data); \
+                                    udelay(2); \
+                                    sbus_readb(&channel->data); \
+                                    udelay(2); } while(0)
+
+#endif /* _SUNZILOG_H */
diff --git a/drivers/tty/serial/timbuart.c b/drivers/tty/serial/timbuart.c
new file mode 100644 (file)
index 0000000..1f36b7e
--- /dev/null
@@ -0,0 +1,531 @@
+/*
+ * timbuart.c timberdale FPGA UART driver
+ * Copyright (c) 2009 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/* Supports:
+ * Timberdale FPGA UART
+ */
+
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/serial_core.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+
+#include "timbuart.h"
+
+struct timbuart_port {
+       struct uart_port        port;
+       struct tasklet_struct   tasklet;
+       int                     usedma;
+       u32                     last_ier;
+       struct platform_device  *dev;
+};
+
+static int baudrates[] = {9600, 19200, 38400, 57600, 115200, 230400, 460800,
+       921600, 1843200, 3250000};
+
+static void timbuart_mctrl_check(struct uart_port *port, u32 isr, u32 *ier);
+
+static irqreturn_t timbuart_handleinterrupt(int irq, void *devid);
+
+static void timbuart_stop_rx(struct uart_port *port)
+{
+       /* spin lock held by upper layer, disable all RX interrupts */
+       u32 ier = ioread32(port->membase + TIMBUART_IER) & ~RXFLAGS;
+       iowrite32(ier, port->membase + TIMBUART_IER);
+}
+
+static void timbuart_stop_tx(struct uart_port *port)
+{
+       /* spinlock held by upper layer, disable TX interrupt */
+       u32 ier = ioread32(port->membase + TIMBUART_IER) & ~TXBAE;
+       iowrite32(ier, port->membase + TIMBUART_IER);
+}
+
+static void timbuart_start_tx(struct uart_port *port)
+{
+       struct timbuart_port *uart =
+               container_of(port, struct timbuart_port, port);
+
+       /* do not transfer anything here -> fire off the tasklet */
+       tasklet_schedule(&uart->tasklet);
+}
+
+static unsigned int timbuart_tx_empty(struct uart_port *port)
+{
+       u32 isr = ioread32(port->membase + TIMBUART_ISR);
+
+       return (isr & TXBE) ? TIOCSER_TEMT : 0;
+}
+
+static void timbuart_flush_buffer(struct uart_port *port)
+{
+       if (!timbuart_tx_empty(port)) {
+               u8 ctl = ioread8(port->membase + TIMBUART_CTRL) |
+                       TIMBUART_CTRL_FLSHTX;
+
+               iowrite8(ctl, port->membase + TIMBUART_CTRL);
+               iowrite32(TXBF, port->membase + TIMBUART_ISR);
+       }
+}
+
+static void timbuart_rx_chars(struct uart_port *port)
+{
+       struct tty_struct *tty = port->state->port.tty;
+
+       while (ioread32(port->membase + TIMBUART_ISR) & RXDP) {
+               u8 ch = ioread8(port->membase + TIMBUART_RXFIFO);
+               port->icount.rx++;
+               tty_insert_flip_char(tty, ch, TTY_NORMAL);
+       }
+
+       spin_unlock(&port->lock);
+       tty_flip_buffer_push(port->state->port.tty);
+       spin_lock(&port->lock);
+
+       dev_dbg(port->dev, "%s - total read %d bytes\n",
+               __func__, port->icount.rx);
+}
+
+static void timbuart_tx_chars(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->state->xmit;
+
+       while (!(ioread32(port->membase + TIMBUART_ISR) & TXBF) &&
+               !uart_circ_empty(xmit)) {
+               iowrite8(xmit->buf[xmit->tail],
+                       port->membase + TIMBUART_TXFIFO);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+       }
+
+       dev_dbg(port->dev,
+               "%s - total written %d bytes, CTL: %x, RTS: %x, baud: %x\n",
+                __func__,
+               port->icount.tx,
+               ioread8(port->membase + TIMBUART_CTRL),
+               port->mctrl & TIOCM_RTS,
+               ioread8(port->membase + TIMBUART_BAUDRATE));
+}
+
+static void timbuart_handle_tx_port(struct uart_port *port, u32 isr, u32 *ier)
+{
+       struct timbuart_port *uart =
+               container_of(port, struct timbuart_port, port);
+       struct circ_buf *xmit = &port->state->xmit;
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+               return;
+
+       if (port->x_char)
+               return;
+
+       if (isr & TXFLAGS) {
+               timbuart_tx_chars(port);
+               /* clear all TX interrupts */
+               iowrite32(TXFLAGS, port->membase + TIMBUART_ISR);
+
+               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+                       uart_write_wakeup(port);
+       } else
+               /* Re-enable any tx interrupt */
+               *ier |= uart->last_ier & TXFLAGS;
+
+       /* enable interrupts if there are chars in the transmit buffer,
+        * Or if we delivered some bytes and want the almost empty interrupt
+        * we wake up the upper layer later when we got the interrupt
+        * to give it some time to go out...
+        */
+       if (!uart_circ_empty(xmit))
+               *ier |= TXBAE;
+
+       dev_dbg(port->dev, "%s - leaving\n", __func__);
+}
+
+void timbuart_handle_rx_port(struct uart_port *port, u32 isr, u32 *ier)
+{
+       if (isr & RXFLAGS) {
+               /* Some RX status is set */
+               if (isr & RXBF) {
+                       u8 ctl = ioread8(port->membase + TIMBUART_CTRL) |
+                               TIMBUART_CTRL_FLSHRX;
+                       iowrite8(ctl, port->membase + TIMBUART_CTRL);
+                       port->icount.overrun++;
+               } else if (isr & (RXDP))
+                       timbuart_rx_chars(port);
+
+               /* ack all RX interrupts */
+               iowrite32(RXFLAGS, port->membase + TIMBUART_ISR);
+       }
+
+       /* always have the RX interrupts enabled */
+       *ier |= RXBAF | RXBF | RXTT;
+
+       dev_dbg(port->dev, "%s - leaving\n", __func__);
+}
+
+void timbuart_tasklet(unsigned long arg)
+{
+       struct timbuart_port *uart = (struct timbuart_port *)arg;
+       u32 isr, ier = 0;
+
+       spin_lock(&uart->port.lock);
+
+       isr = ioread32(uart->port.membase + TIMBUART_ISR);
+       dev_dbg(uart->port.dev, "%s ISR: %x\n", __func__, isr);
+
+       if (!uart->usedma)
+               timbuart_handle_tx_port(&uart->port, isr, &ier);
+
+       timbuart_mctrl_check(&uart->port, isr, &ier);
+
+       if (!uart->usedma)
+               timbuart_handle_rx_port(&uart->port, isr, &ier);
+
+       iowrite32(ier, uart->port.membase + TIMBUART_IER);
+
+       spin_unlock(&uart->port.lock);
+       dev_dbg(uart->port.dev, "%s leaving\n", __func__);
+}
+
+static unsigned int timbuart_get_mctrl(struct uart_port *port)
+{
+       u8 cts = ioread8(port->membase + TIMBUART_CTRL);
+       dev_dbg(port->dev, "%s - cts %x\n", __func__, cts);
+
+       if (cts & TIMBUART_CTRL_CTS)
+               return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+       else
+               return TIOCM_DSR | TIOCM_CAR;
+}
+
+static void timbuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       dev_dbg(port->dev, "%s - %x\n", __func__, mctrl);
+
+       if (mctrl & TIOCM_RTS)
+               iowrite8(TIMBUART_CTRL_RTS, port->membase + TIMBUART_CTRL);
+       else
+               iowrite8(0, port->membase + TIMBUART_CTRL);
+}
+
+static void timbuart_mctrl_check(struct uart_port *port, u32 isr, u32 *ier)
+{
+       unsigned int cts;
+
+       if (isr & CTS_DELTA) {
+               /* ack */
+               iowrite32(CTS_DELTA, port->membase + TIMBUART_ISR);
+               cts = timbuart_get_mctrl(port);
+               uart_handle_cts_change(port, cts & TIOCM_CTS);
+               wake_up_interruptible(&port->state->port.delta_msr_wait);
+       }
+
+       *ier |= CTS_DELTA;
+}
+
+static void timbuart_enable_ms(struct uart_port *port)
+{
+       /* N/A */
+}
+
+static void timbuart_break_ctl(struct uart_port *port, int ctl)
+{
+       /* N/A */
+}
+
+static int timbuart_startup(struct uart_port *port)
+{
+       struct timbuart_port *uart =
+               container_of(port, struct timbuart_port, port);
+
+       dev_dbg(port->dev, "%s\n", __func__);
+
+       iowrite8(TIMBUART_CTRL_FLSHRX, port->membase + TIMBUART_CTRL);
+       iowrite32(0x1ff, port->membase + TIMBUART_ISR);
+       /* Enable all but TX interrupts */
+       iowrite32(RXBAF | RXBF | RXTT | CTS_DELTA,
+               port->membase + TIMBUART_IER);
+
+       return request_irq(port->irq, timbuart_handleinterrupt, IRQF_SHARED,
+               "timb-uart", uart);
+}
+
+static void timbuart_shutdown(struct uart_port *port)
+{
+       struct timbuart_port *uart =
+               container_of(port, struct timbuart_port, port);
+       dev_dbg(port->dev, "%s\n", __func__);
+       free_irq(port->irq, uart);
+       iowrite32(0, port->membase + TIMBUART_IER);
+}
+
+static int get_bindex(int baud)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(baudrates); i++)
+               if (baud <= baudrates[i])
+                       return i;
+
+       return -1;
+}
+
+static void timbuart_set_termios(struct uart_port *port,
+       struct ktermios *termios,
+       struct ktermios *old)
+{
+       unsigned int baud;
+       short bindex;
+       unsigned long flags;
+
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
+       bindex = get_bindex(baud);
+       dev_dbg(port->dev, "%s - bindex %d\n", __func__, bindex);
+
+       if (bindex < 0)
+               bindex = 0;
+       baud = baudrates[bindex];
+
+       /* The serial layer calls into this once with old = NULL when setting
+          up initially */
+       if (old)
+               tty_termios_copy_hw(termios, old);
+       tty_termios_encode_baud_rate(termios, baud, baud);
+
+       spin_lock_irqsave(&port->lock, flags);
+       iowrite8((u8)bindex, port->membase + TIMBUART_BAUDRATE);
+       uart_update_timeout(port, termios->c_cflag, baud);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *timbuart_type(struct uart_port *port)
+{
+       return port->type == PORT_UNKNOWN ? "timbuart" : NULL;
+}
+
+/* We do not request/release mappings of the registers here,
+ * currently it's done in the proble function.
+ */
+static void timbuart_release_port(struct uart_port *port)
+{
+       struct platform_device *pdev = to_platform_device(port->dev);
+       int size =
+               resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0));
+
+       if (port->flags & UPF_IOREMAP) {
+               iounmap(port->membase);
+               port->membase = NULL;
+       }
+
+       release_mem_region(port->mapbase, size);
+}
+
+static int timbuart_request_port(struct uart_port *port)
+{
+       struct platform_device *pdev = to_platform_device(port->dev);
+       int size =
+               resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0));
+
+       if (!request_mem_region(port->mapbase, size, "timb-uart"))
+               return -EBUSY;
+
+       if (port->flags & UPF_IOREMAP) {
+               port->membase = ioremap(port->mapbase, size);
+               if (port->membase == NULL) {
+                       release_mem_region(port->mapbase, size);
+                       return -ENOMEM;
+               }
+       }
+
+       return 0;
+}
+
+static irqreturn_t timbuart_handleinterrupt(int irq, void *devid)
+{
+       struct timbuart_port *uart = (struct timbuart_port *)devid;
+
+       if (ioread8(uart->port.membase + TIMBUART_IPR)) {
+               uart->last_ier = ioread32(uart->port.membase + TIMBUART_IER);
+
+               /* disable interrupts, the tasklet enables them again */
+               iowrite32(0, uart->port.membase + TIMBUART_IER);
+
+               /* fire off bottom half */
+               tasklet_schedule(&uart->tasklet);
+
+               return IRQ_HANDLED;
+       } else
+               return IRQ_NONE;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void timbuart_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = PORT_TIMBUART;
+               timbuart_request_port(port);
+       }
+}
+
+static int timbuart_verify_port(struct uart_port *port,
+       struct serial_struct *ser)
+{
+       /* we don't want the core code to modify any port params */
+       return -EINVAL;
+}
+
+static struct uart_ops timbuart_ops = {
+       .tx_empty = timbuart_tx_empty,
+       .set_mctrl = timbuart_set_mctrl,
+       .get_mctrl = timbuart_get_mctrl,
+       .stop_tx = timbuart_stop_tx,
+       .start_tx = timbuart_start_tx,
+       .flush_buffer = timbuart_flush_buffer,
+       .stop_rx = timbuart_stop_rx,
+       .enable_ms = timbuart_enable_ms,
+       .break_ctl = timbuart_break_ctl,
+       .startup = timbuart_startup,
+       .shutdown = timbuart_shutdown,
+       .set_termios = timbuart_set_termios,
+       .type = timbuart_type,
+       .release_port = timbuart_release_port,
+       .request_port = timbuart_request_port,
+       .config_port = timbuart_config_port,
+       .verify_port = timbuart_verify_port
+};
+
+static struct uart_driver timbuart_driver = {
+       .owner = THIS_MODULE,
+       .driver_name = "timberdale_uart",
+       .dev_name = "ttyTU",
+       .major = TIMBUART_MAJOR,
+       .minor = TIMBUART_MINOR,
+       .nr = 1
+};
+
+static int __devinit timbuart_probe(struct platform_device *dev)
+{
+       int err, irq;
+       struct timbuart_port *uart;
+       struct resource *iomem;
+
+       dev_dbg(&dev->dev, "%s\n", __func__);
+
+       uart = kzalloc(sizeof(*uart), GFP_KERNEL);
+       if (!uart) {
+               err = -EINVAL;
+               goto err_mem;
+       }
+
+       uart->usedma = 0;
+
+       uart->port.uartclk = 3250000 * 16;
+       uart->port.fifosize  = TIMBUART_FIFO_SIZE;
+       uart->port.regshift  = 2;
+       uart->port.iotype  = UPIO_MEM;
+       uart->port.ops = &timbuart_ops;
+       uart->port.irq = 0;
+       uart->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
+       uart->port.line  = 0;
+       uart->port.dev  = &dev->dev;
+
+       iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (!iomem) {
+               err = -ENOMEM;
+               goto err_register;
+       }
+       uart->port.mapbase = iomem->start;
+       uart->port.membase = NULL;
+
+       irq = platform_get_irq(dev, 0);
+       if (irq < 0) {
+               err = -EINVAL;
+               goto err_register;
+       }
+       uart->port.irq = irq;
+
+       tasklet_init(&uart->tasklet, timbuart_tasklet, (unsigned long)uart);
+
+       err = uart_register_driver(&timbuart_driver);
+       if (err)
+               goto err_register;
+
+       err = uart_add_one_port(&timbuart_driver, &uart->port);
+       if (err)
+               goto err_add_port;
+
+       platform_set_drvdata(dev, uart);
+
+       return 0;
+
+err_add_port:
+       uart_unregister_driver(&timbuart_driver);
+err_register:
+       kfree(uart);
+err_mem:
+       printk(KERN_ERR "timberdale: Failed to register Timberdale UART: %d\n",
+               err);
+
+       return err;
+}
+
+static int __devexit timbuart_remove(struct platform_device *dev)
+{
+       struct timbuart_port *uart = platform_get_drvdata(dev);
+
+       tasklet_kill(&uart->tasklet);
+       uart_remove_one_port(&timbuart_driver, &uart->port);
+       uart_unregister_driver(&timbuart_driver);
+       kfree(uart);
+
+       return 0;
+}
+
+static struct platform_driver timbuart_platform_driver = {
+       .driver = {
+               .name   = "timb-uart",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = timbuart_probe,
+       .remove         = __devexit_p(timbuart_remove),
+};
+
+/*--------------------------------------------------------------------------*/
+
+static int __init timbuart_init(void)
+{
+       return platform_driver_register(&timbuart_platform_driver);
+}
+
+static void __exit timbuart_exit(void)
+{
+       platform_driver_unregister(&timbuart_platform_driver);
+}
+
+module_init(timbuart_init);
+module_exit(timbuart_exit);
+
+MODULE_DESCRIPTION("Timberdale UART driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:timb-uart");
+
diff --git a/drivers/tty/serial/timbuart.h b/drivers/tty/serial/timbuart.h
new file mode 100644 (file)
index 0000000..7e56676
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * timbuart.c timberdale FPGA GPIO driver
+ * Copyright (c) 2009 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/* Supports:
+ * Timberdale FPGA UART
+ */
+
+#ifndef _TIMBUART_H
+#define _TIMBUART_H
+
+#define TIMBUART_FIFO_SIZE     2048
+
+#define TIMBUART_RXFIFO                0x08
+#define TIMBUART_TXFIFO                0x0c
+#define TIMBUART_IER           0x10
+#define TIMBUART_IPR           0x14
+#define TIMBUART_ISR           0x18
+#define TIMBUART_CTRL          0x1c
+#define TIMBUART_BAUDRATE      0x20
+
+#define TIMBUART_CTRL_RTS      0x01
+#define TIMBUART_CTRL_CTS      0x02
+#define TIMBUART_CTRL_FLSHTX   0x40
+#define TIMBUART_CTRL_FLSHRX   0x80
+
+#define TXBF           0x01
+#define TXBAE          0x02
+#define CTS_DELTA      0x04
+#define RXDP           0x08
+#define RXBAF          0x10
+#define RXBF           0x20
+#define RXTT           0x40
+#define RXBNAE         0x80
+#define TXBE           0x100
+
+#define RXFLAGS (RXDP | RXBAF | RXBF | RXTT | RXBNAE)
+#define TXFLAGS (TXBF | TXBAE)
+
+#define TIMBUART_MAJOR 204
+#define TIMBUART_MINOR 192
+
+#endif /* _TIMBUART_H */
+
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
new file mode 100644 (file)
index 0000000..d2fce86
--- /dev/null
@@ -0,0 +1,709 @@
+/*
+ * uartlite.c: Serial driver for Xilinx uartlite serial controller
+ *
+ * Copyright (C) 2006 Peter Korsgaard <jacmet@sunsite.dk>
+ * Copyright (C) 2007 Secret Lab Technologies Ltd.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/tty.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#if defined(CONFIG_OF) && (defined(CONFIG_PPC32) || defined(CONFIG_MICROBLAZE))
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+
+/* Match table for of_platform binding */
+static struct of_device_id ulite_of_match[] __devinitdata = {
+       { .compatible = "xlnx,opb-uartlite-1.00.b", },
+       { .compatible = "xlnx,xps-uartlite-1.00.a", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, ulite_of_match);
+
+#endif
+
+#define ULITE_NAME             "ttyUL"
+#define ULITE_MAJOR            204
+#define ULITE_MINOR            187
+#define ULITE_NR_UARTS         4
+
+/* ---------------------------------------------------------------------
+ * Register definitions
+ *
+ * For register details see datasheet:
+ * http://www.xilinx.com/support/documentation/ip_documentation/opb_uartlite.pdf 
+ */
+
+#define ULITE_RX               0x00
+#define ULITE_TX               0x04
+#define ULITE_STATUS           0x08
+#define ULITE_CONTROL          0x0c
+
+#define ULITE_REGION           16
+
+#define ULITE_STATUS_RXVALID   0x01
+#define ULITE_STATUS_RXFULL    0x02
+#define ULITE_STATUS_TXEMPTY   0x04
+#define ULITE_STATUS_TXFULL    0x08
+#define ULITE_STATUS_IE                0x10
+#define ULITE_STATUS_OVERRUN   0x20
+#define ULITE_STATUS_FRAME     0x40
+#define ULITE_STATUS_PARITY    0x80
+
+#define ULITE_CONTROL_RST_TX   0x01
+#define ULITE_CONTROL_RST_RX   0x02
+#define ULITE_CONTROL_IE       0x10
+
+
+static struct uart_port ulite_ports[ULITE_NR_UARTS];
+
+/* ---------------------------------------------------------------------
+ * Core UART driver operations
+ */
+
+static int ulite_receive(struct uart_port *port, int stat)
+{
+       struct tty_struct *tty = port->state->port.tty;
+       unsigned char ch = 0;
+       char flag = TTY_NORMAL;
+
+       if ((stat & (ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN
+                    | ULITE_STATUS_FRAME)) == 0)
+               return 0;
+
+       /* stats */
+       if (stat & ULITE_STATUS_RXVALID) {
+               port->icount.rx++;
+               ch = ioread32be(port->membase + ULITE_RX);
+
+               if (stat & ULITE_STATUS_PARITY)
+                       port->icount.parity++;
+       }
+
+       if (stat & ULITE_STATUS_OVERRUN)
+               port->icount.overrun++;
+
+       if (stat & ULITE_STATUS_FRAME)
+               port->icount.frame++;
+
+
+       /* drop byte with parity error if IGNPAR specificed */
+       if (stat & port->ignore_status_mask & ULITE_STATUS_PARITY)
+               stat &= ~ULITE_STATUS_RXVALID;
+
+       stat &= port->read_status_mask;
+
+       if (stat & ULITE_STATUS_PARITY)
+               flag = TTY_PARITY;
+
+
+       stat &= ~port->ignore_status_mask;
+
+       if (stat & ULITE_STATUS_RXVALID)
+               tty_insert_flip_char(tty, ch, flag);
+
+       if (stat & ULITE_STATUS_FRAME)
+               tty_insert_flip_char(tty, 0, TTY_FRAME);
+
+       if (stat & ULITE_STATUS_OVERRUN)
+               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+
+       return 1;
+}
+
+static int ulite_transmit(struct uart_port *port, int stat)
+{
+       struct circ_buf *xmit  = &port->state->xmit;
+
+       if (stat & ULITE_STATUS_TXFULL)
+               return 0;
+
+       if (port->x_char) {
+               iowrite32be(port->x_char, port->membase + ULITE_TX);
+               port->x_char = 0;
+               port->icount.tx++;
+               return 1;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+               return 0;
+
+       iowrite32be(xmit->buf[xmit->tail], port->membase + ULITE_TX);
+       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
+       port->icount.tx++;
+
+       /* wake up */
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       return 1;
+}
+
+static irqreturn_t ulite_isr(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       int busy, n = 0;
+
+       do {
+               int stat = ioread32be(port->membase + ULITE_STATUS);
+               busy  = ulite_receive(port, stat);
+               busy |= ulite_transmit(port, stat);
+               n++;
+       } while (busy);
+
+       /* work done? */
+       if (n > 1) {
+               tty_flip_buffer_push(port->state->port.tty);
+               return IRQ_HANDLED;
+       } else {
+               return IRQ_NONE;
+       }
+}
+
+static unsigned int ulite_tx_empty(struct uart_port *port)
+{
+       unsigned long flags;
+       unsigned int ret;
+
+       spin_lock_irqsave(&port->lock, flags);
+       ret = ioread32be(port->membase + ULITE_STATUS);
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int ulite_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void ulite_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       /* N/A */
+}
+
+static void ulite_stop_tx(struct uart_port *port)
+{
+       /* N/A */
+}
+
+static void ulite_start_tx(struct uart_port *port)
+{
+       ulite_transmit(port, ioread32be(port->membase + ULITE_STATUS));
+}
+
+static void ulite_stop_rx(struct uart_port *port)
+{
+       /* don't forward any more data (like !CREAD) */
+       port->ignore_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY
+               | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
+}
+
+static void ulite_enable_ms(struct uart_port *port)
+{
+       /* N/A */
+}
+
+static void ulite_break_ctl(struct uart_port *port, int ctl)
+{
+       /* N/A */
+}
+
+static int ulite_startup(struct uart_port *port)
+{
+       int ret;
+
+       ret = request_irq(port->irq, ulite_isr,
+                         IRQF_SHARED | IRQF_SAMPLE_RANDOM, "uartlite", port);
+       if (ret)
+               return ret;
+
+       iowrite32be(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX,
+              port->membase + ULITE_CONTROL);
+       iowrite32be(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
+
+       return 0;
+}
+
+static void ulite_shutdown(struct uart_port *port)
+{
+       iowrite32be(0, port->membase + ULITE_CONTROL);
+       ioread32be(port->membase + ULITE_CONTROL); /* dummy */
+       free_irq(port->irq, port);
+}
+
+static void ulite_set_termios(struct uart_port *port, struct ktermios *termios,
+                             struct ktermios *old)
+{
+       unsigned long flags;
+       unsigned int baud;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       port->read_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN
+               | ULITE_STATUS_TXFULL;
+
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |=
+                       ULITE_STATUS_PARITY | ULITE_STATUS_FRAME;
+
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= ULITE_STATUS_PARITY
+                       | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
+
+       /* ignore all characters if CREAD is not set */
+       if ((termios->c_cflag & CREAD) == 0)
+               port->ignore_status_mask |=
+                       ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY
+                       | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
+
+       /* update timeout */
+       baud = uart_get_baud_rate(port, termios, old, 0, 460800);
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *ulite_type(struct uart_port *port)
+{
+       return port->type == PORT_UARTLITE ? "uartlite" : NULL;
+}
+
+static void ulite_release_port(struct uart_port *port)
+{
+       release_mem_region(port->mapbase, ULITE_REGION);
+       iounmap(port->membase);
+       port->membase = NULL;
+}
+
+static int ulite_request_port(struct uart_port *port)
+{
+       pr_debug("ulite console: port=%p; port->mapbase=%llx\n",
+                port, (unsigned long long) port->mapbase);
+
+       if (!request_mem_region(port->mapbase, ULITE_REGION, "uartlite")) {
+               dev_err(port->dev, "Memory region busy\n");
+               return -EBUSY;
+       }
+
+       port->membase = ioremap(port->mapbase, ULITE_REGION);
+       if (!port->membase) {
+               dev_err(port->dev, "Unable to map registers\n");
+               release_mem_region(port->mapbase, ULITE_REGION);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static void ulite_config_port(struct uart_port *port, int flags)
+{
+       if (!ulite_request_port(port))
+               port->type = PORT_UARTLITE;
+}
+
+static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       /* we don't want the core code to modify any port params */
+       return -EINVAL;
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+static int ulite_get_poll_char(struct uart_port *port)
+{
+       if (!(ioread32be(port->membase + ULITE_STATUS)
+                                               & ULITE_STATUS_RXVALID))
+               return NO_POLL_CHAR;
+
+       return ioread32be(port->membase + ULITE_RX);
+}
+
+static void ulite_put_poll_char(struct uart_port *port, unsigned char ch)
+{
+       while (ioread32be(port->membase + ULITE_STATUS) & ULITE_STATUS_TXFULL)
+               cpu_relax();
+
+       /* write char to device */
+       iowrite32be(ch, port->membase + ULITE_TX);
+}
+#endif
+
+static struct uart_ops ulite_ops = {
+       .tx_empty       = ulite_tx_empty,
+       .set_mctrl      = ulite_set_mctrl,
+       .get_mctrl      = ulite_get_mctrl,
+       .stop_tx        = ulite_stop_tx,
+       .start_tx       = ulite_start_tx,
+       .stop_rx        = ulite_stop_rx,
+       .enable_ms      = ulite_enable_ms,
+       .break_ctl      = ulite_break_ctl,
+       .startup        = ulite_startup,
+       .shutdown       = ulite_shutdown,
+       .set_termios    = ulite_set_termios,
+       .type           = ulite_type,
+       .release_port   = ulite_release_port,
+       .request_port   = ulite_request_port,
+       .config_port    = ulite_config_port,
+       .verify_port    = ulite_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char  = ulite_get_poll_char,
+       .poll_put_char  = ulite_put_poll_char,
+#endif
+};
+
+/* ---------------------------------------------------------------------
+ * Console driver operations
+ */
+
+#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
+static void ulite_console_wait_tx(struct uart_port *port)
+{
+       int i;
+       u8 val;
+
+       /* Spin waiting for TX fifo to have space available */
+       for (i = 0; i < 100000; i++) {
+               val = ioread32be(port->membase + ULITE_STATUS);
+               if ((val & ULITE_STATUS_TXFULL) == 0)
+                       break;
+               cpu_relax();
+       }
+}
+
+static void ulite_console_putchar(struct uart_port *port, int ch)
+{
+       ulite_console_wait_tx(port);
+       iowrite32be(ch, port->membase + ULITE_TX);
+}
+
+static void ulite_console_write(struct console *co, const char *s,
+                               unsigned int count)
+{
+       struct uart_port *port = &ulite_ports[co->index];
+       unsigned long flags;
+       unsigned int ier;
+       int locked = 1;
+
+       if (oops_in_progress) {
+               locked = spin_trylock_irqsave(&port->lock, flags);
+       } else
+               spin_lock_irqsave(&port->lock, flags);
+
+       /* save and disable interrupt */
+       ier = ioread32be(port->membase + ULITE_STATUS) & ULITE_STATUS_IE;
+       iowrite32be(0, port->membase + ULITE_CONTROL);
+
+       uart_console_write(port, s, count, ulite_console_putchar);
+
+       ulite_console_wait_tx(port);
+
+       /* restore interrupt state */
+       if (ier)
+               iowrite32be(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
+
+       if (locked)
+               spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int __devinit ulite_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (co->index < 0 || co->index >= ULITE_NR_UARTS)
+               return -EINVAL;
+
+       port = &ulite_ports[co->index];
+
+       /* Has the device been initialized yet? */
+       if (!port->mapbase) {
+               pr_debug("console on ttyUL%i not present\n", co->index);
+               return -ENODEV;
+       }
+
+       /* not initialized yet? */
+       if (!port->membase) {
+               if (ulite_request_port(port))
+                       return -ENODEV;
+       }
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver ulite_uart_driver;
+
+static struct console ulite_console = {
+       .name   = ULITE_NAME,
+       .write  = ulite_console_write,
+       .device = uart_console_device,
+       .setup  = ulite_console_setup,
+       .flags  = CON_PRINTBUFFER,
+       .index  = -1, /* Specified on the cmdline (e.g. console=ttyUL0 ) */
+       .data   = &ulite_uart_driver,
+};
+
+static int __init ulite_console_init(void)
+{
+       register_console(&ulite_console);
+       return 0;
+}
+
+console_initcall(ulite_console_init);
+
+#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */
+
+static struct uart_driver ulite_uart_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "uartlite",
+       .dev_name       = ULITE_NAME,
+       .major          = ULITE_MAJOR,
+       .minor          = ULITE_MINOR,
+       .nr             = ULITE_NR_UARTS,
+#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
+       .cons           = &ulite_console,
+#endif
+};
+
+/* ---------------------------------------------------------------------
+ * Port assignment functions (mapping devices to uart_port structures)
+ */
+
+/** ulite_assign: register a uartlite device with the driver
+ *
+ * @dev: pointer to device structure
+ * @id: requested id number.  Pass -1 for automatic port assignment
+ * @base: base address of uartlite registers
+ * @irq: irq number for uartlite
+ *
+ * Returns: 0 on success, <0 otherwise
+ */
+static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq)
+{
+       struct uart_port *port;
+       int rc;
+
+       /* if id = -1; then scan for a free id and use that */
+       if (id < 0) {
+               for (id = 0; id < ULITE_NR_UARTS; id++)
+                       if (ulite_ports[id].mapbase == 0)
+                               break;
+       }
+       if (id < 0 || id >= ULITE_NR_UARTS) {
+               dev_err(dev, "%s%i too large\n", ULITE_NAME, id);
+               return -EINVAL;
+       }
+
+       if ((ulite_ports[id].mapbase) && (ulite_ports[id].mapbase != base)) {
+               dev_err(dev, "cannot assign to %s%i; it is already in use\n",
+                       ULITE_NAME, id);
+               return -EBUSY;
+       }
+
+       port = &ulite_ports[id];
+
+       spin_lock_init(&port->lock);
+       port->fifosize = 16;
+       port->regshift = 2;
+       port->iotype = UPIO_MEM;
+       port->iobase = 1; /* mark port in use */
+       port->mapbase = base;
+       port->membase = NULL;
+       port->ops = &ulite_ops;
+       port->irq = irq;
+       port->flags = UPF_BOOT_AUTOCONF;
+       port->dev = dev;
+       port->type = PORT_UNKNOWN;
+       port->line = id;
+
+       dev_set_drvdata(dev, port);
+
+       /* Register the port */
+       rc = uart_add_one_port(&ulite_uart_driver, port);
+       if (rc) {
+               dev_err(dev, "uart_add_one_port() failed; err=%i\n", rc);
+               port->mapbase = 0;
+               dev_set_drvdata(dev, NULL);
+               return rc;
+       }
+
+       return 0;
+}
+
+/** ulite_release: register a uartlite device with the driver
+ *
+ * @dev: pointer to device structure
+ */
+static int __devexit ulite_release(struct device *dev)
+{
+       struct uart_port *port = dev_get_drvdata(dev);
+       int rc = 0;
+
+       if (port) {
+               rc = uart_remove_one_port(&ulite_uart_driver, port);
+               dev_set_drvdata(dev, NULL);
+               port->mapbase = 0;
+       }
+
+       return rc;
+}
+
+/* ---------------------------------------------------------------------
+ * Platform bus binding
+ */
+
+static int __devinit ulite_probe(struct platform_device *pdev)
+{
+       struct resource *res, *res2;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+
+       res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res2)
+               return -ENODEV;
+
+       return ulite_assign(&pdev->dev, pdev->id, res->start, res2->start);
+}
+
+static int __devexit ulite_remove(struct platform_device *pdev)
+{
+       return ulite_release(&pdev->dev);
+}
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:uartlite");
+
+static struct platform_driver ulite_platform_driver = {
+       .probe  = ulite_probe,
+       .remove = __devexit_p(ulite_remove),
+       .driver = {
+                  .owner = THIS_MODULE,
+                  .name  = "uartlite",
+                  },
+};
+
+/* ---------------------------------------------------------------------
+ * OF bus bindings
+ */
+#if defined(CONFIG_OF) && (defined(CONFIG_PPC32) || defined(CONFIG_MICROBLAZE))
+static int __devinit
+ulite_of_probe(struct platform_device *op, const struct of_device_id *match)
+{
+       struct resource res;
+       const unsigned int *id;
+       int irq, rc;
+
+       dev_dbg(&op->dev, "%s(%p, %p)\n", __func__, op, match);
+
+       rc = of_address_to_resource(op->dev.of_node, 0, &res);
+       if (rc) {
+               dev_err(&op->dev, "invalid address\n");
+               return rc;
+       }
+
+       irq = irq_of_parse_and_map(op->dev.of_node, 0);
+
+       id = of_get_property(op->dev.of_node, "port-number", NULL);
+
+       return ulite_assign(&op->dev, id ? *id : -1, res.start, irq);
+}
+
+static int __devexit ulite_of_remove(struct platform_device *op)
+{
+       return ulite_release(&op->dev);
+}
+
+static struct of_platform_driver ulite_of_driver = {
+       .probe = ulite_of_probe,
+       .remove = __devexit_p(ulite_of_remove),
+       .driver = {
+               .name = "uartlite",
+               .owner = THIS_MODULE,
+               .of_match_table = ulite_of_match,
+       },
+};
+
+/* Registration helpers to keep the number of #ifdefs to a minimum */
+static inline int __init ulite_of_register(void)
+{
+       pr_debug("uartlite: calling of_register_platform_driver()\n");
+       return of_register_platform_driver(&ulite_of_driver);
+}
+
+static inline void __exit ulite_of_unregister(void)
+{
+       of_unregister_platform_driver(&ulite_of_driver);
+}
+#else /* CONFIG_OF && (CONFIG_PPC32 || CONFIG_MICROBLAZE) */
+/* Appropriate config not enabled; do nothing helpers */
+static inline int __init ulite_of_register(void) { return 0; }
+static inline void __exit ulite_of_unregister(void) { }
+#endif /* CONFIG_OF && (CONFIG_PPC32 || CONFIG_MICROBLAZE) */
+
+/* ---------------------------------------------------------------------
+ * Module setup/teardown
+ */
+
+int __init ulite_init(void)
+{
+       int ret;
+
+       pr_debug("uartlite: calling uart_register_driver()\n");
+       ret = uart_register_driver(&ulite_uart_driver);
+       if (ret)
+               goto err_uart;
+
+       ret = ulite_of_register();
+       if (ret)
+               goto err_of;
+
+       pr_debug("uartlite: calling platform_driver_register()\n");
+       ret = platform_driver_register(&ulite_platform_driver);
+       if (ret)
+               goto err_plat;
+
+       return 0;
+
+err_plat:
+       ulite_of_unregister();
+err_of:
+       uart_unregister_driver(&ulite_uart_driver);
+err_uart:
+       printk(KERN_ERR "registering uartlite driver failed: err=%i", ret);
+       return ret;
+}
+
+void __exit ulite_exit(void)
+{
+       platform_driver_unregister(&ulite_platform_driver);
+       ulite_of_unregister();
+       uart_unregister_driver(&ulite_uart_driver);
+}
+
+module_init(ulite_init);
+module_exit(ulite_exit);
+
+MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
+MODULE_DESCRIPTION("Xilinx uartlite serial driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c
new file mode 100644 (file)
index 0000000..3f4848e
--- /dev/null
@@ -0,0 +1,1537 @@
+/*
+ * Freescale QUICC Engine UART device driver
+ *
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * Copyright 2007 Freescale Semiconductor, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ * This driver adds support for UART devices via Freescale's QUICC Engine
+ * found on some Freescale SOCs.
+ *
+ * If Soft-UART support is needed but not already present, then this driver
+ * will request and upload the "Soft-UART" microcode upon probe.  The
+ * filename of the microcode should be fsl_qe_ucode_uart_X_YZ.bin, where "X"
+ * is the name of the SOC (e.g. 8323), and YZ is the revision of the SOC,
+ * (e.g. "11" for 1.1).
+ */
+
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/slab.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/fs_uart_pd.h>
+#include <asm/ucc_slow.h>
+
+#include <linux/firmware.h>
+#include <asm/reg.h>
+
+/*
+ * The GUMR flag for Soft UART.  This would normally be defined in qe.h,
+ * but Soft-UART is a hack and we want to keep everything related to it in
+ * this file.
+ */
+#define UCC_SLOW_GUMR_H_SUART          0x00004000      /* Soft-UART */
+
+/*
+ * soft_uart is 1 if we need to use Soft-UART mode
+ */
+static int soft_uart;
+/*
+ * firmware_loaded is 1 if the firmware has been loaded, 0 otherwise.
+ */
+static int firmware_loaded;
+
+/* Enable this macro to configure all serial ports in internal loopback
+   mode */
+/* #define LOOPBACK */
+
+/* The major and minor device numbers are defined in
+ * http://www.lanana.org/docs/device-list/devices-2.6+.txt.  For the QE
+ * UART, we have major number 204 and minor numbers 46 - 49, which are the
+ * same as for the CPM2.  This decision was made because no Freescale part
+ * has both a CPM and a QE.
+ */
+#define SERIAL_QE_MAJOR 204
+#define SERIAL_QE_MINOR 46
+
+/* Since we only have minor numbers 46 - 49, there is a hard limit of 4 ports */
+#define UCC_MAX_UART    4
+
+/* The number of buffer descriptors for receiving characters. */
+#define RX_NUM_FIFO     4
+
+/* The number of buffer descriptors for transmitting characters. */
+#define TX_NUM_FIFO     4
+
+/* The maximum size of the character buffer for a single RX BD. */
+#define RX_BUF_SIZE     32
+
+/* The maximum size of the character buffer for a single TX BD. */
+#define TX_BUF_SIZE     32
+
+/*
+ * The number of jiffies to wait after receiving a close command before the
+ * device is actually closed.  This allows the last few characters to be
+ * sent over the wire.
+ */
+#define UCC_WAIT_CLOSING 100
+
+struct ucc_uart_pram {
+       struct ucc_slow_pram common;
+       u8 res1[8];             /* reserved */
+       __be16 maxidl;          /* Maximum idle chars */
+       __be16 idlc;            /* temp idle counter */
+       __be16 brkcr;           /* Break count register */
+       __be16 parec;           /* receive parity error counter */
+       __be16 frmec;           /* receive framing error counter */
+       __be16 nosec;           /* receive noise counter */
+       __be16 brkec;           /* receive break condition counter */
+       __be16 brkln;           /* last received break length */
+       __be16 uaddr[2];        /* UART address character 1 & 2 */
+       __be16 rtemp;           /* Temp storage */
+       __be16 toseq;           /* Transmit out of sequence char */
+       __be16 cchars[8];       /* control characters 1-8 */
+       __be16 rccm;            /* receive control character mask */
+       __be16 rccr;            /* receive control character register */
+       __be16 rlbc;            /* receive last break character */
+       __be16 res2;            /* reserved */
+       __be32 res3;            /* reserved, should be cleared */
+       u8 res4;                /* reserved, should be cleared */
+       u8 res5[3];             /* reserved, should be cleared */
+       __be32 res6;            /* reserved, should be cleared */
+       __be32 res7;            /* reserved, should be cleared */
+       __be32 res8;            /* reserved, should be cleared */
+       __be32 res9;            /* reserved, should be cleared */
+       __be32 res10;           /* reserved, should be cleared */
+       __be32 res11;           /* reserved, should be cleared */
+       __be32 res12;           /* reserved, should be cleared */
+       __be32 res13;           /* reserved, should be cleared */
+/* The rest is for Soft-UART only */
+       __be16 supsmr;          /* 0x90, Shadow UPSMR */
+       __be16 res92;           /* 0x92, reserved, initialize to 0 */
+       __be32 rx_state;        /* 0x94, RX state, initialize to 0 */
+       __be32 rx_cnt;          /* 0x98, RX count, initialize to 0 */
+       u8 rx_length;           /* 0x9C, Char length, set to 1+CL+PEN+1+SL */
+       u8 rx_bitmark;          /* 0x9D, reserved, initialize to 0 */
+       u8 rx_temp_dlst_qe;     /* 0x9E, reserved, initialize to 0 */
+       u8 res14[0xBC - 0x9F];  /* reserved */
+       __be32 dump_ptr;        /* 0xBC, Dump pointer */
+       __be32 rx_frame_rem;    /* 0xC0, reserved, initialize to 0 */
+       u8 rx_frame_rem_size;   /* 0xC4, reserved, initialize to 0 */
+       u8 tx_mode;             /* 0xC5, mode, 0=AHDLC, 1=UART */
+       __be16 tx_state;        /* 0xC6, TX state */
+       u8 res15[0xD0 - 0xC8];  /* reserved */
+       __be32 resD0;           /* 0xD0, reserved, initialize to 0 */
+       u8 resD4;               /* 0xD4, reserved, initialize to 0 */
+       __be16 resD5;           /* 0xD5, reserved, initialize to 0 */
+} __attribute__ ((packed));
+
+/* SUPSMR definitions, for Soft-UART only */
+#define UCC_UART_SUPSMR_SL             0x8000
+#define UCC_UART_SUPSMR_RPM_MASK       0x6000
+#define UCC_UART_SUPSMR_RPM_ODD        0x0000
+#define UCC_UART_SUPSMR_RPM_LOW        0x2000
+#define UCC_UART_SUPSMR_RPM_EVEN       0x4000
+#define UCC_UART_SUPSMR_RPM_HIGH       0x6000
+#define UCC_UART_SUPSMR_PEN            0x1000
+#define UCC_UART_SUPSMR_TPM_MASK       0x0C00
+#define UCC_UART_SUPSMR_TPM_ODD        0x0000
+#define UCC_UART_SUPSMR_TPM_LOW        0x0400
+#define UCC_UART_SUPSMR_TPM_EVEN       0x0800
+#define UCC_UART_SUPSMR_TPM_HIGH       0x0C00
+#define UCC_UART_SUPSMR_FRZ            0x0100
+#define UCC_UART_SUPSMR_UM_MASK        0x00c0
+#define UCC_UART_SUPSMR_UM_NORMAL       0x0000
+#define UCC_UART_SUPSMR_UM_MAN_MULTI    0x0040
+#define UCC_UART_SUPSMR_UM_AUTO_MULTI   0x00c0
+#define UCC_UART_SUPSMR_CL_MASK        0x0030
+#define UCC_UART_SUPSMR_CL_8           0x0030
+#define UCC_UART_SUPSMR_CL_7           0x0020
+#define UCC_UART_SUPSMR_CL_6           0x0010
+#define UCC_UART_SUPSMR_CL_5           0x0000
+
+#define UCC_UART_TX_STATE_AHDLC        0x00
+#define UCC_UART_TX_STATE_UART         0x01
+#define UCC_UART_TX_STATE_X1           0x00
+#define UCC_UART_TX_STATE_X16          0x80
+
+#define UCC_UART_PRAM_ALIGNMENT 0x100
+
+#define UCC_UART_SIZE_OF_BD     UCC_SLOW_SIZE_OF_BD
+#define NUM_CONTROL_CHARS       8
+
+/* Private per-port data structure */
+struct uart_qe_port {
+       struct uart_port port;
+       struct ucc_slow __iomem *uccp;
+       struct ucc_uart_pram __iomem *uccup;
+       struct ucc_slow_info us_info;
+       struct ucc_slow_private *us_private;
+       struct device_node *np;
+       unsigned int ucc_num;   /* First ucc is 0, not 1 */
+
+       u16 rx_nrfifos;
+       u16 rx_fifosize;
+       u16 tx_nrfifos;
+       u16 tx_fifosize;
+       int wait_closing;
+       u32 flags;
+       struct qe_bd *rx_bd_base;
+       struct qe_bd *rx_cur;
+       struct qe_bd *tx_bd_base;
+       struct qe_bd *tx_cur;
+       unsigned char *tx_buf;
+       unsigned char *rx_buf;
+       void *bd_virt;          /* virtual address of the BD buffers */
+       dma_addr_t bd_dma_addr; /* bus address of the BD buffers */
+       unsigned int bd_size;   /* size of BD buffer space */
+};
+
+static struct uart_driver ucc_uart_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "ucc_uart",
+       .dev_name       = "ttyQE",
+       .major          = SERIAL_QE_MAJOR,
+       .minor          = SERIAL_QE_MINOR,
+       .nr             = UCC_MAX_UART,
+};
+
+/*
+ * Virtual to physical address translation.
+ *
+ * Given the virtual address for a character buffer, this function returns
+ * the physical (DMA) equivalent.
+ */
+static inline dma_addr_t cpu2qe_addr(void *addr, struct uart_qe_port *qe_port)
+{
+       if (likely((addr >= qe_port->bd_virt)) &&
+           (addr < (qe_port->bd_virt + qe_port->bd_size)))
+               return qe_port->bd_dma_addr + (addr - qe_port->bd_virt);
+
+       /* something nasty happened */
+       printk(KERN_ERR "%s: addr=%p\n", __func__, addr);
+       BUG();
+       return 0;
+}
+
+/*
+ * Physical to virtual address translation.
+ *
+ * Given the physical (DMA) address for a character buffer, this function
+ * returns the virtual equivalent.
+ */
+static inline void *qe2cpu_addr(dma_addr_t addr, struct uart_qe_port *qe_port)
+{
+       /* sanity check */
+       if (likely((addr >= qe_port->bd_dma_addr) &&
+                  (addr < (qe_port->bd_dma_addr + qe_port->bd_size))))
+               return qe_port->bd_virt + (addr - qe_port->bd_dma_addr);
+
+       /* something nasty happened */
+       printk(KERN_ERR "%s: addr=%x\n", __func__, addr);
+       BUG();
+       return NULL;
+}
+
+/*
+ * Return 1 if the QE is done transmitting all buffers for this port
+ *
+ * This function scans each BD in sequence.  If we find a BD that is not
+ * ready (READY=1), then we return 0 indicating that the QE is still sending
+ * data.  If we reach the last BD (WRAP=1), then we know we've scanned
+ * the entire list, and all BDs are done.
+ */
+static unsigned int qe_uart_tx_empty(struct uart_port *port)
+{
+       struct uart_qe_port *qe_port =
+               container_of(port, struct uart_qe_port, port);
+       struct qe_bd *bdp = qe_port->tx_bd_base;
+
+       while (1) {
+               if (in_be16(&bdp->status) & BD_SC_READY)
+                       /* This BD is not done, so return "not done" */
+                       return 0;
+
+               if (in_be16(&bdp->status) & BD_SC_WRAP)
+                       /*
+                        * This BD is done and it's the last one, so return
+                        * "done"
+                        */
+                       return 1;
+
+               bdp++;
+       };
+}
+
+/*
+ * Set the modem control lines
+ *
+ * Although the QE can control the modem control lines (e.g. CTS), we
+ * don't need that support. This function must exist, however, otherwise
+ * the kernel will panic.
+ */
+void qe_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+/*
+ * Get the current modem control line status
+ *
+ * Although the QE can control the modem control lines (e.g. CTS), this
+ * driver currently doesn't support that, so we always return Carrier
+ * Detect, Data Set Ready, and Clear To Send.
+ */
+static unsigned int qe_uart_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+/*
+ * Disable the transmit interrupt.
+ *
+ * Although this function is called "stop_tx", it does not actually stop
+ * transmission of data.  Instead, it tells the QE to not generate an
+ * interrupt when the UCC is finished sending characters.
+ */
+static void qe_uart_stop_tx(struct uart_port *port)
+{
+       struct uart_qe_port *qe_port =
+               container_of(port, struct uart_qe_port, port);
+
+       clrbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_TX);
+}
+
+/*
+ * Transmit as many characters to the HW as possible.
+ *
+ * This function will attempt to stuff of all the characters from the
+ * kernel's transmit buffer into TX BDs.
+ *
+ * A return value of non-zero indicates that it successfully stuffed all
+ * characters from the kernel buffer.
+ *
+ * A return value of zero indicates that there are still characters in the
+ * kernel's buffer that have not been transmitted, but there are no more BDs
+ * available.  This function should be called again after a BD has been made
+ * available.
+ */
+static int qe_uart_tx_pump(struct uart_qe_port *qe_port)
+{
+       struct qe_bd *bdp;
+       unsigned char *p;
+       unsigned int count;
+       struct uart_port *port = &qe_port->port;
+       struct circ_buf *xmit = &port->state->xmit;
+
+       bdp = qe_port->rx_cur;
+
+       /* Handle xon/xoff */
+       if (port->x_char) {
+               /* Pick next descriptor and fill from buffer */
+               bdp = qe_port->tx_cur;
+
+               p = qe2cpu_addr(bdp->buf, qe_port);
+
+               *p++ = port->x_char;
+               out_be16(&bdp->length, 1);
+               setbits16(&bdp->status, BD_SC_READY);
+               /* Get next BD. */
+               if (in_be16(&bdp->status) & BD_SC_WRAP)
+                       bdp = qe_port->tx_bd_base;
+               else
+                       bdp++;
+               qe_port->tx_cur = bdp;
+
+               port->icount.tx++;
+               port->x_char = 0;
+               return 1;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               qe_uart_stop_tx(port);
+               return 0;
+       }
+
+       /* Pick next descriptor and fill from buffer */
+       bdp = qe_port->tx_cur;
+
+       while (!(in_be16(&bdp->status) & BD_SC_READY) &&
+              (xmit->tail != xmit->head)) {
+               count = 0;
+               p = qe2cpu_addr(bdp->buf, qe_port);
+               while (count < qe_port->tx_fifosize) {
+                       *p++ = xmit->buf[xmit->tail];
+                       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+                       port->icount.tx++;
+                       count++;
+                       if (xmit->head == xmit->tail)
+                               break;
+               }
+
+               out_be16(&bdp->length, count);
+               setbits16(&bdp->status, BD_SC_READY);
+
+               /* Get next BD. */
+               if (in_be16(&bdp->status) & BD_SC_WRAP)
+                       bdp = qe_port->tx_bd_base;
+               else
+                       bdp++;
+       }
+       qe_port->tx_cur = bdp;
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit)) {
+               /* The kernel buffer is empty, so turn off TX interrupts.  We
+                  don't need to be told when the QE is finished transmitting
+                  the data. */
+               qe_uart_stop_tx(port);
+               return 0;
+       }
+
+       return 1;
+}
+
+/*
+ * Start transmitting data
+ *
+ * This function will start transmitting any available data, if the port
+ * isn't already transmitting data.
+ */
+static void qe_uart_start_tx(struct uart_port *port)
+{
+       struct uart_qe_port *qe_port =
+               container_of(port, struct uart_qe_port, port);
+
+       /* If we currently are transmitting, then just return */
+       if (in_be16(&qe_port->uccp->uccm) & UCC_UART_UCCE_TX)
+               return;
+
+       /* Otherwise, pump the port and start transmission */
+       if (qe_uart_tx_pump(qe_port))
+               setbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_TX);
+}
+
+/*
+ * Stop transmitting data
+ */
+static void qe_uart_stop_rx(struct uart_port *port)
+{
+       struct uart_qe_port *qe_port =
+               container_of(port, struct uart_qe_port, port);
+
+       clrbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_RX);
+}
+
+/*
+ * Enable status change interrupts
+ *
+ * We don't support status change interrupts, but we need to define this
+ * function otherwise the kernel will panic.
+ */
+static void qe_uart_enable_ms(struct uart_port *port)
+{
+}
+
+/* Start or stop sending  break signal
+ *
+ * This function controls the sending of a break signal.  If break_state=1,
+ * then we start sending a break signal.  If break_state=0, then we stop
+ * sending the break signal.
+ */
+static void qe_uart_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_qe_port *qe_port =
+               container_of(port, struct uart_qe_port, port);
+
+       if (break_state)
+               ucc_slow_stop_tx(qe_port->us_private);
+       else
+               ucc_slow_restart_tx(qe_port->us_private);
+}
+
+/* ISR helper function for receiving character.
+ *
+ * This function is called by the ISR to handling receiving characters
+ */
+static void qe_uart_int_rx(struct uart_qe_port *qe_port)
+{
+       int i;
+       unsigned char ch, *cp;
+       struct uart_port *port = &qe_port->port;
+       struct tty_struct *tty = port->state->port.tty;
+       struct qe_bd *bdp;
+       u16 status;
+       unsigned int flg;
+
+       /* Just loop through the closed BDs and copy the characters into
+        * the buffer.
+        */
+       bdp = qe_port->rx_cur;
+       while (1) {
+               status = in_be16(&bdp->status);
+
+               /* If this one is empty, then we assume we've read them all */
+               if (status & BD_SC_EMPTY)
+                       break;
+
+               /* get number of characters, and check space in RX buffer */
+               i = in_be16(&bdp->length);
+
+               /* If we don't have enough room in RX buffer for the entire BD,
+                * then we try later, which will be the next RX interrupt.
+                */
+               if (tty_buffer_request_room(tty, i) < i) {
+                       dev_dbg(port->dev, "ucc-uart: no room in RX buffer\n");
+                       return;
+               }
+
+               /* get pointer */
+               cp = qe2cpu_addr(bdp->buf, qe_port);
+
+               /* loop through the buffer */
+               while (i-- > 0) {
+                       ch = *cp++;
+                       port->icount.rx++;
+                       flg = TTY_NORMAL;
+
+                       if (!i && status &
+                           (BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV))
+                               goto handle_error;
+                       if (uart_handle_sysrq_char(port, ch))
+                               continue;
+
+error_return:
+                       tty_insert_flip_char(tty, ch, flg);
+
+               }
+
+               /* This BD is ready to be used again. Clear status. get next */
+               clrsetbits_be16(&bdp->status, BD_SC_BR | BD_SC_FR | BD_SC_PR |
+                       BD_SC_OV | BD_SC_ID, BD_SC_EMPTY);
+               if (in_be16(&bdp->status) & BD_SC_WRAP)
+                       bdp = qe_port->rx_bd_base;
+               else
+                       bdp++;
+
+       }
+
+       /* Write back buffer pointer */
+       qe_port->rx_cur = bdp;
+
+       /* Activate BH processing */
+       tty_flip_buffer_push(tty);
+
+       return;
+
+       /* Error processing */
+
+handle_error:
+       /* Statistics */
+       if (status & BD_SC_BR)
+               port->icount.brk++;
+       if (status & BD_SC_PR)
+               port->icount.parity++;
+       if (status & BD_SC_FR)
+               port->icount.frame++;
+       if (status & BD_SC_OV)
+               port->icount.overrun++;
+
+       /* Mask out ignored conditions */
+       status &= port->read_status_mask;
+
+       /* Handle the remaining ones */
+       if (status & BD_SC_BR)
+               flg = TTY_BREAK;
+       else if (status & BD_SC_PR)
+               flg = TTY_PARITY;
+       else if (status & BD_SC_FR)
+               flg = TTY_FRAME;
+
+       /* Overrun does not affect the current character ! */
+       if (status & BD_SC_OV)
+               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+#ifdef SUPPORT_SYSRQ
+       port->sysrq = 0;
+#endif
+       goto error_return;
+}
+
+/* Interrupt handler
+ *
+ * This interrupt handler is called after a BD is processed.
+ */
+static irqreturn_t qe_uart_int(int irq, void *data)
+{
+       struct uart_qe_port *qe_port = (struct uart_qe_port *) data;
+       struct ucc_slow __iomem *uccp = qe_port->uccp;
+       u16 events;
+
+       /* Clear the interrupts */
+       events = in_be16(&uccp->ucce);
+       out_be16(&uccp->ucce, events);
+
+       if (events & UCC_UART_UCCE_BRKE)
+               uart_handle_break(&qe_port->port);
+
+       if (events & UCC_UART_UCCE_RX)
+               qe_uart_int_rx(qe_port);
+
+       if (events & UCC_UART_UCCE_TX)
+               qe_uart_tx_pump(qe_port);
+
+       return events ? IRQ_HANDLED : IRQ_NONE;
+}
+
+/* Initialize buffer descriptors
+ *
+ * This function initializes all of the RX and TX buffer descriptors.
+ */
+static void qe_uart_initbd(struct uart_qe_port *qe_port)
+{
+       int i;
+       void *bd_virt;
+       struct qe_bd *bdp;
+
+       /* Set the physical address of the host memory buffers in the buffer
+        * descriptors, and the virtual address for us to work with.
+        */
+       bd_virt = qe_port->bd_virt;
+       bdp = qe_port->rx_bd_base;
+       qe_port->rx_cur = qe_port->rx_bd_base;
+       for (i = 0; i < (qe_port->rx_nrfifos - 1); i++) {
+               out_be16(&bdp->status, BD_SC_EMPTY | BD_SC_INTRPT);
+               out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port));
+               out_be16(&bdp->length, 0);
+               bd_virt += qe_port->rx_fifosize;
+               bdp++;
+       }
+
+       /* */
+       out_be16(&bdp->status, BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT);
+       out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port));
+       out_be16(&bdp->length, 0);
+
+       /* Set the physical address of the host memory
+        * buffers in the buffer descriptors, and the
+        * virtual address for us to work with.
+        */
+       bd_virt = qe_port->bd_virt +
+               L1_CACHE_ALIGN(qe_port->rx_nrfifos * qe_port->rx_fifosize);
+       qe_port->tx_cur = qe_port->tx_bd_base;
+       bdp = qe_port->tx_bd_base;
+       for (i = 0; i < (qe_port->tx_nrfifos - 1); i++) {
+               out_be16(&bdp->status, BD_SC_INTRPT);
+               out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port));
+               out_be16(&bdp->length, 0);
+               bd_virt += qe_port->tx_fifosize;
+               bdp++;
+       }
+
+       /* Loopback requires the preamble bit to be set on the first TX BD */
+#ifdef LOOPBACK
+       setbits16(&qe_port->tx_cur->status, BD_SC_P);
+#endif
+
+       out_be16(&bdp->status, BD_SC_WRAP | BD_SC_INTRPT);
+       out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port));
+       out_be16(&bdp->length, 0);
+}
+
+/*
+ * Initialize a UCC for UART.
+ *
+ * This function configures a given UCC to be used as a UART device. Basic
+ * UCC initialization is handled in qe_uart_request_port().  This function
+ * does all the UART-specific stuff.
+ */
+static void qe_uart_init_ucc(struct uart_qe_port *qe_port)
+{
+       u32 cecr_subblock;
+       struct ucc_slow __iomem *uccp = qe_port->uccp;
+       struct ucc_uart_pram *uccup = qe_port->uccup;
+
+       unsigned int i;
+
+       /* First, disable TX and RX in the UCC */
+       ucc_slow_disable(qe_port->us_private, COMM_DIR_RX_AND_TX);
+
+       /* Program the UCC UART parameter RAM */
+       out_8(&uccup->common.rbmr, UCC_BMR_GBL | UCC_BMR_BO_BE);
+       out_8(&uccup->common.tbmr, UCC_BMR_GBL | UCC_BMR_BO_BE);
+       out_be16(&uccup->common.mrblr, qe_port->rx_fifosize);
+       out_be16(&uccup->maxidl, 0x10);
+       out_be16(&uccup->brkcr, 1);
+       out_be16(&uccup->parec, 0);
+       out_be16(&uccup->frmec, 0);
+       out_be16(&uccup->nosec, 0);
+       out_be16(&uccup->brkec, 0);
+       out_be16(&uccup->uaddr[0], 0);
+       out_be16(&uccup->uaddr[1], 0);
+       out_be16(&uccup->toseq, 0);
+       for (i = 0; i < 8; i++)
+               out_be16(&uccup->cchars[i], 0xC000);
+       out_be16(&uccup->rccm, 0xc0ff);
+
+       /* Configure the GUMR registers for UART */
+       if (soft_uart) {
+               /* Soft-UART requires a 1X multiplier for TX */
+               clrsetbits_be32(&uccp->gumr_l,
+                       UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK |
+                       UCC_SLOW_GUMR_L_RDCR_MASK,
+                       UCC_SLOW_GUMR_L_MODE_UART | UCC_SLOW_GUMR_L_TDCR_1 |
+                       UCC_SLOW_GUMR_L_RDCR_16);
+
+               clrsetbits_be32(&uccp->gumr_h, UCC_SLOW_GUMR_H_RFW,
+                       UCC_SLOW_GUMR_H_TRX | UCC_SLOW_GUMR_H_TTX);
+       } else {
+               clrsetbits_be32(&uccp->gumr_l,
+                       UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK |
+                       UCC_SLOW_GUMR_L_RDCR_MASK,
+                       UCC_SLOW_GUMR_L_MODE_UART | UCC_SLOW_GUMR_L_TDCR_16 |
+                       UCC_SLOW_GUMR_L_RDCR_16);
+
+               clrsetbits_be32(&uccp->gumr_h,
+                       UCC_SLOW_GUMR_H_TRX | UCC_SLOW_GUMR_H_TTX,
+                       UCC_SLOW_GUMR_H_RFW);
+       }
+
+#ifdef LOOPBACK
+       clrsetbits_be32(&uccp->gumr_l, UCC_SLOW_GUMR_L_DIAG_MASK,
+               UCC_SLOW_GUMR_L_DIAG_LOOP);
+       clrsetbits_be32(&uccp->gumr_h,
+               UCC_SLOW_GUMR_H_CTSP | UCC_SLOW_GUMR_H_RSYN,
+               UCC_SLOW_GUMR_H_CDS);
+#endif
+
+       /* Disable rx interrupts  and clear all pending events.  */
+       out_be16(&uccp->uccm, 0);
+       out_be16(&uccp->ucce, 0xffff);
+       out_be16(&uccp->udsr, 0x7e7e);
+
+       /* Initialize UPSMR */
+       out_be16(&uccp->upsmr, 0);
+
+       if (soft_uart) {
+               out_be16(&uccup->supsmr, 0x30);
+               out_be16(&uccup->res92, 0);
+               out_be32(&uccup->rx_state, 0);
+               out_be32(&uccup->rx_cnt, 0);
+               out_8(&uccup->rx_bitmark, 0);
+               out_8(&uccup->rx_length, 10);
+               out_be32(&uccup->dump_ptr, 0x4000);
+               out_8(&uccup->rx_temp_dlst_qe, 0);
+               out_be32(&uccup->rx_frame_rem, 0);
+               out_8(&uccup->rx_frame_rem_size, 0);
+               /* Soft-UART requires TX to be 1X */
+               out_8(&uccup->tx_mode,
+                       UCC_UART_TX_STATE_UART | UCC_UART_TX_STATE_X1);
+               out_be16(&uccup->tx_state, 0);
+               out_8(&uccup->resD4, 0);
+               out_be16(&uccup->resD5, 0);
+
+               /* Set UART mode.
+                * Enable receive and transmit.
+                */
+
+               /* From the microcode errata:
+                * 1.GUMR_L register, set mode=0010 (QMC).
+                * 2.Set GUMR_H[17] bit. (UART/AHDLC mode).
+                * 3.Set GUMR_H[19:20] (Transparent mode)
+                * 4.Clear GUMR_H[26] (RFW)
+                * ...
+                * 6.Receiver must use 16x over sampling
+                */
+               clrsetbits_be32(&uccp->gumr_l,
+                       UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK |
+                       UCC_SLOW_GUMR_L_RDCR_MASK,
+                       UCC_SLOW_GUMR_L_MODE_QMC | UCC_SLOW_GUMR_L_TDCR_16 |
+                       UCC_SLOW_GUMR_L_RDCR_16);
+
+               clrsetbits_be32(&uccp->gumr_h,
+                       UCC_SLOW_GUMR_H_RFW | UCC_SLOW_GUMR_H_RSYN,
+                       UCC_SLOW_GUMR_H_SUART | UCC_SLOW_GUMR_H_TRX |
+                       UCC_SLOW_GUMR_H_TTX | UCC_SLOW_GUMR_H_TFL);
+
+#ifdef LOOPBACK
+               clrsetbits_be32(&uccp->gumr_l, UCC_SLOW_GUMR_L_DIAG_MASK,
+                               UCC_SLOW_GUMR_L_DIAG_LOOP);
+               clrbits32(&uccp->gumr_h, UCC_SLOW_GUMR_H_CTSP |
+                         UCC_SLOW_GUMR_H_CDS);
+#endif
+
+               cecr_subblock = ucc_slow_get_qe_cr_subblock(qe_port->ucc_num);
+               qe_issue_cmd(QE_INIT_TX_RX, cecr_subblock,
+                       QE_CR_PROTOCOL_UNSPECIFIED, 0);
+       } else {
+               cecr_subblock = ucc_slow_get_qe_cr_subblock(qe_port->ucc_num);
+               qe_issue_cmd(QE_INIT_TX_RX, cecr_subblock,
+                       QE_CR_PROTOCOL_UART, 0);
+       }
+}
+
+/*
+ * Initialize the port.
+ */
+static int qe_uart_startup(struct uart_port *port)
+{
+       struct uart_qe_port *qe_port =
+               container_of(port, struct uart_qe_port, port);
+       int ret;
+
+       /*
+        * If we're using Soft-UART mode, then we need to make sure the
+        * firmware has been uploaded first.
+        */
+       if (soft_uart && !firmware_loaded) {
+               dev_err(port->dev, "Soft-UART firmware not uploaded\n");
+               return -ENODEV;
+       }
+
+       qe_uart_initbd(qe_port);
+       qe_uart_init_ucc(qe_port);
+
+       /* Install interrupt handler. */
+       ret = request_irq(port->irq, qe_uart_int, IRQF_SHARED, "ucc-uart",
+               qe_port);
+       if (ret) {
+               dev_err(port->dev, "could not claim IRQ %u\n", port->irq);
+               return ret;
+       }
+
+       /* Startup rx-int */
+       setbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_RX);
+       ucc_slow_enable(qe_port->us_private, COMM_DIR_RX_AND_TX);
+
+       return 0;
+}
+
+/*
+ * Shutdown the port.
+ */
+static void qe_uart_shutdown(struct uart_port *port)
+{
+       struct uart_qe_port *qe_port =
+               container_of(port, struct uart_qe_port, port);
+       struct ucc_slow __iomem *uccp = qe_port->uccp;
+       unsigned int timeout = 20;
+
+       /* Disable RX and TX */
+
+       /* Wait for all the BDs marked sent */
+       while (!qe_uart_tx_empty(port)) {
+               if (!--timeout) {
+                       dev_warn(port->dev, "shutdown timeout\n");
+                       break;
+               }
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(2);
+       }
+
+       if (qe_port->wait_closing) {
+               /* Wait a bit longer */
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(qe_port->wait_closing);
+       }
+
+       /* Stop uarts */
+       ucc_slow_disable(qe_port->us_private, COMM_DIR_RX_AND_TX);
+       clrbits16(&uccp->uccm, UCC_UART_UCCE_TX | UCC_UART_UCCE_RX);
+
+       /* Shut them really down and reinit buffer descriptors */
+       ucc_slow_graceful_stop_tx(qe_port->us_private);
+       qe_uart_initbd(qe_port);
+
+       free_irq(port->irq, qe_port);
+}
+
+/*
+ * Set the serial port parameters.
+ */
+static void qe_uart_set_termios(struct uart_port *port,
+                               struct ktermios *termios, struct ktermios *old)
+{
+       struct uart_qe_port *qe_port =
+               container_of(port, struct uart_qe_port, port);
+       struct ucc_slow __iomem *uccp = qe_port->uccp;
+       unsigned int baud;
+       unsigned long flags;
+       u16 upsmr = in_be16(&uccp->upsmr);
+       struct ucc_uart_pram __iomem *uccup = qe_port->uccup;
+       u16 supsmr = in_be16(&uccup->supsmr);
+       u8 char_length = 2; /* 1 + CL + PEN + 1 + SL */
+
+       /* Character length programmed into the mode register is the
+        * sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
+        * 1 or 2 stop bits, minus 1.
+        * The value 'bits' counts this for us.
+        */
+
+       /* byte size */
+       upsmr &= UCC_UART_UPSMR_CL_MASK;
+       supsmr &= UCC_UART_SUPSMR_CL_MASK;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               upsmr |= UCC_UART_UPSMR_CL_5;
+               supsmr |= UCC_UART_SUPSMR_CL_5;
+               char_length += 5;
+               break;
+       case CS6:
+               upsmr |= UCC_UART_UPSMR_CL_6;
+               supsmr |= UCC_UART_SUPSMR_CL_6;
+               char_length += 6;
+               break;
+       case CS7:
+               upsmr |= UCC_UART_UPSMR_CL_7;
+               supsmr |= UCC_UART_SUPSMR_CL_7;
+               char_length += 7;
+               break;
+       default:        /* case CS8 */
+               upsmr |= UCC_UART_UPSMR_CL_8;
+               supsmr |= UCC_UART_SUPSMR_CL_8;
+               char_length += 8;
+               break;
+       }
+
+       /* If CSTOPB is set, we want two stop bits */
+       if (termios->c_cflag & CSTOPB) {
+               upsmr |= UCC_UART_UPSMR_SL;
+               supsmr |= UCC_UART_SUPSMR_SL;
+               char_length++;  /* + SL */
+       }
+
+       if (termios->c_cflag & PARENB) {
+               upsmr |= UCC_UART_UPSMR_PEN;
+               supsmr |= UCC_UART_SUPSMR_PEN;
+               char_length++;  /* + PEN */
+
+               if (!(termios->c_cflag & PARODD)) {
+                       upsmr &= ~(UCC_UART_UPSMR_RPM_MASK |
+                                  UCC_UART_UPSMR_TPM_MASK);
+                       upsmr |= UCC_UART_UPSMR_RPM_EVEN |
+                               UCC_UART_UPSMR_TPM_EVEN;
+                       supsmr &= ~(UCC_UART_SUPSMR_RPM_MASK |
+                                   UCC_UART_SUPSMR_TPM_MASK);
+                       supsmr |= UCC_UART_SUPSMR_RPM_EVEN |
+                               UCC_UART_SUPSMR_TPM_EVEN;
+               }
+       }
+
+       /*
+        * Set up parity check flag
+        */
+       port->read_status_mask = BD_SC_EMPTY | BD_SC_OV;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= BD_SC_FR | BD_SC_PR;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               port->read_status_mask |= BD_SC_BR;
+
+       /*
+        * Characters to ignore
+        */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= BD_SC_PR | BD_SC_FR;
+       if (termios->c_iflag & IGNBRK) {
+               port->ignore_status_mask |= BD_SC_BR;
+               /*
+                * If we're ignore parity and break indicators, ignore
+                * overruns too.  (For real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       port->ignore_status_mask |= BD_SC_OV;
+       }
+       /*
+        * !!! ignore all characters if CREAD is not set
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               port->read_status_mask &= ~BD_SC_EMPTY;
+
+       baud = uart_get_baud_rate(port, termios, old, 0, 115200);
+
+       /* Do we really need a spinlock here? */
+       spin_lock_irqsave(&port->lock, flags);
+
+       out_be16(&uccp->upsmr, upsmr);
+       if (soft_uart) {
+               out_be16(&uccup->supsmr, supsmr);
+               out_8(&uccup->rx_length, char_length);
+
+               /* Soft-UART requires a 1X multiplier for TX */
+               qe_setbrg(qe_port->us_info.rx_clock, baud, 16);
+               qe_setbrg(qe_port->us_info.tx_clock, baud, 1);
+       } else {
+               qe_setbrg(qe_port->us_info.rx_clock, baud, 16);
+               qe_setbrg(qe_port->us_info.tx_clock, baud, 16);
+       }
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/*
+ * Return a pointer to a string that describes what kind of port this is.
+ */
+static const char *qe_uart_type(struct uart_port *port)
+{
+       return "QE";
+}
+
+/*
+ * Allocate any memory and I/O resources required by the port.
+ */
+static int qe_uart_request_port(struct uart_port *port)
+{
+       int ret;
+       struct uart_qe_port *qe_port =
+               container_of(port, struct uart_qe_port, port);
+       struct ucc_slow_info *us_info = &qe_port->us_info;
+       struct ucc_slow_private *uccs;
+       unsigned int rx_size, tx_size;
+       void *bd_virt;
+       dma_addr_t bd_dma_addr = 0;
+
+       ret = ucc_slow_init(us_info, &uccs);
+       if (ret) {
+               dev_err(port->dev, "could not initialize UCC%u\n",
+                      qe_port->ucc_num);
+               return ret;
+       }
+
+       qe_port->us_private = uccs;
+       qe_port->uccp = uccs->us_regs;
+       qe_port->uccup = (struct ucc_uart_pram *) uccs->us_pram;
+       qe_port->rx_bd_base = uccs->rx_bd;
+       qe_port->tx_bd_base = uccs->tx_bd;
+
+       /*
+        * Allocate the transmit and receive data buffers.
+        */
+
+       rx_size = L1_CACHE_ALIGN(qe_port->rx_nrfifos * qe_port->rx_fifosize);
+       tx_size = L1_CACHE_ALIGN(qe_port->tx_nrfifos * qe_port->tx_fifosize);
+
+       bd_virt = dma_alloc_coherent(port->dev, rx_size + tx_size, &bd_dma_addr,
+               GFP_KERNEL);
+       if (!bd_virt) {
+               dev_err(port->dev, "could not allocate buffer descriptors\n");
+               return -ENOMEM;
+       }
+
+       qe_port->bd_virt = bd_virt;
+       qe_port->bd_dma_addr = bd_dma_addr;
+       qe_port->bd_size = rx_size + tx_size;
+
+       qe_port->rx_buf = bd_virt;
+       qe_port->tx_buf = qe_port->rx_buf + rx_size;
+
+       return 0;
+}
+
+/*
+ * Configure the port.
+ *
+ * We say we're a CPM-type port because that's mostly true.  Once the device
+ * is configured, this driver operates almost identically to the CPM serial
+ * driver.
+ */
+static void qe_uart_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = PORT_CPM;
+               qe_uart_request_port(port);
+       }
+}
+
+/*
+ * Release any memory and I/O resources that were allocated in
+ * qe_uart_request_port().
+ */
+static void qe_uart_release_port(struct uart_port *port)
+{
+       struct uart_qe_port *qe_port =
+               container_of(port, struct uart_qe_port, port);
+       struct ucc_slow_private *uccs = qe_port->us_private;
+
+       dma_free_coherent(port->dev, qe_port->bd_size, qe_port->bd_virt,
+                         qe_port->bd_dma_addr);
+
+       ucc_slow_free(uccs);
+}
+
+/*
+ * Verify that the data in serial_struct is suitable for this device.
+ */
+static int qe_uart_verify_port(struct uart_port *port,
+                              struct serial_struct *ser)
+{
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_CPM)
+               return -EINVAL;
+
+       if (ser->irq < 0 || ser->irq >= nr_irqs)
+               return -EINVAL;
+
+       if (ser->baud_base < 9600)
+               return -EINVAL;
+
+       return 0;
+}
+/* UART operations
+ *
+ * Details on these functions can be found in Documentation/serial/driver
+ */
+static struct uart_ops qe_uart_pops = {
+       .tx_empty       = qe_uart_tx_empty,
+       .set_mctrl      = qe_uart_set_mctrl,
+       .get_mctrl      = qe_uart_get_mctrl,
+       .stop_tx        = qe_uart_stop_tx,
+       .start_tx       = qe_uart_start_tx,
+       .stop_rx        = qe_uart_stop_rx,
+       .enable_ms      = qe_uart_enable_ms,
+       .break_ctl      = qe_uart_break_ctl,
+       .startup        = qe_uart_startup,
+       .shutdown       = qe_uart_shutdown,
+       .set_termios    = qe_uart_set_termios,
+       .type           = qe_uart_type,
+       .release_port   = qe_uart_release_port,
+       .request_port   = qe_uart_request_port,
+       .config_port    = qe_uart_config_port,
+       .verify_port    = qe_uart_verify_port,
+};
+
+/*
+ * Obtain the SOC model number and revision level
+ *
+ * This function parses the device tree to obtain the SOC model.  It then
+ * reads the SVR register to the revision.
+ *
+ * The device tree stores the SOC model two different ways.
+ *
+ * The new way is:
+ *
+ *             cpu@0 {
+ *                     compatible = "PowerPC,8323";
+ *                     device_type = "cpu";
+ *                     ...
+ *
+ *
+ * The old way is:
+ *              PowerPC,8323@0 {
+ *                     device_type = "cpu";
+ *                     ...
+ *
+ * This code first checks the new way, and then the old way.
+ */
+static unsigned int soc_info(unsigned int *rev_h, unsigned int *rev_l)
+{
+       struct device_node *np;
+       const char *soc_string;
+       unsigned int svr;
+       unsigned int soc;
+
+       /* Find the CPU node */
+       np = of_find_node_by_type(NULL, "cpu");
+       if (!np)
+               return 0;
+       /* Find the compatible property */
+       soc_string = of_get_property(np, "compatible", NULL);
+       if (!soc_string)
+               /* No compatible property, so try the name. */
+               soc_string = np->name;
+
+       /* Extract the SOC number from the "PowerPC," string */
+       if ((sscanf(soc_string, "PowerPC,%u", &soc) != 1) || !soc)
+               return 0;
+
+       /* Get the revision from the SVR */
+       svr = mfspr(SPRN_SVR);
+       *rev_h = (svr >> 4) & 0xf;
+       *rev_l = svr & 0xf;
+
+       return soc;
+}
+
+/*
+ * requst_firmware_nowait() callback function
+ *
+ * This function is called by the kernel when a firmware is made available,
+ * or if it times out waiting for the firmware.
+ */
+static void uart_firmware_cont(const struct firmware *fw, void *context)
+{
+       struct qe_firmware *firmware;
+       struct device *dev = context;
+       int ret;
+
+       if (!fw) {
+               dev_err(dev, "firmware not found\n");
+               return;
+       }
+
+       firmware = (struct qe_firmware *) fw->data;
+
+       if (firmware->header.length != fw->size) {
+               dev_err(dev, "invalid firmware\n");
+               goto out;
+       }
+
+       ret = qe_upload_firmware(firmware);
+       if (ret) {
+               dev_err(dev, "could not load firmware\n");
+               goto out;
+       }
+
+       firmware_loaded = 1;
+ out:
+       release_firmware(fw);
+}
+
+static int ucc_uart_probe(struct platform_device *ofdev,
+       const struct of_device_id *match)
+{
+       struct device_node *np = ofdev->dev.of_node;
+       const unsigned int *iprop;      /* Integer OF properties */
+       const char *sprop;      /* String OF properties */
+       struct uart_qe_port *qe_port = NULL;
+       struct resource res;
+       int ret;
+
+       /*
+        * Determine if we need Soft-UART mode
+        */
+       if (of_find_property(np, "soft-uart", NULL)) {
+               dev_dbg(&ofdev->dev, "using Soft-UART mode\n");
+               soft_uart = 1;
+       }
+
+       /*
+        * If we are using Soft-UART, determine if we need to upload the
+        * firmware, too.
+        */
+       if (soft_uart) {
+               struct qe_firmware_info *qe_fw_info;
+
+               qe_fw_info = qe_get_firmware_info();
+
+               /* Check if the firmware has been uploaded. */
+               if (qe_fw_info && strstr(qe_fw_info->id, "Soft-UART")) {
+                       firmware_loaded = 1;
+               } else {
+                       char filename[32];
+                       unsigned int soc;
+                       unsigned int rev_h;
+                       unsigned int rev_l;
+
+                       soc = soc_info(&rev_h, &rev_l);
+                       if (!soc) {
+                               dev_err(&ofdev->dev, "unknown CPU model\n");
+                               return -ENXIO;
+                       }
+                       sprintf(filename, "fsl_qe_ucode_uart_%u_%u%u.bin",
+                               soc, rev_h, rev_l);
+
+                       dev_info(&ofdev->dev, "waiting for firmware %s\n",
+                               filename);
+
+                       /*
+                        * We call request_firmware_nowait instead of
+                        * request_firmware so that the driver can load and
+                        * initialize the ports without holding up the rest of
+                        * the kernel.  If hotplug support is enabled in the
+                        * kernel, then we use it.
+                        */
+                       ret = request_firmware_nowait(THIS_MODULE,
+                               FW_ACTION_HOTPLUG, filename, &ofdev->dev,
+                               GFP_KERNEL, &ofdev->dev, uart_firmware_cont);
+                       if (ret) {
+                               dev_err(&ofdev->dev,
+                                       "could not load firmware %s\n",
+                                       filename);
+                               return ret;
+                       }
+               }
+       }
+
+       qe_port = kzalloc(sizeof(struct uart_qe_port), GFP_KERNEL);
+       if (!qe_port) {
+               dev_err(&ofdev->dev, "can't allocate QE port structure\n");
+               return -ENOMEM;
+       }
+
+       /* Search for IRQ and mapbase */
+       ret = of_address_to_resource(np, 0, &res);
+       if (ret) {
+               dev_err(&ofdev->dev, "missing 'reg' property in device tree\n");
+               kfree(qe_port);
+               return ret;
+       }
+       if (!res.start) {
+               dev_err(&ofdev->dev, "invalid 'reg' property in device tree\n");
+               kfree(qe_port);
+               return -EINVAL;
+       }
+       qe_port->port.mapbase = res.start;
+
+       /* Get the UCC number (device ID) */
+       /* UCCs are numbered 1-7 */
+       iprop = of_get_property(np, "cell-index", NULL);
+       if (!iprop) {
+               iprop = of_get_property(np, "device-id", NULL);
+               if (!iprop) {
+                       kfree(qe_port);
+                       dev_err(&ofdev->dev, "UCC is unspecified in "
+                               "device tree\n");
+                       return -EINVAL;
+               }
+       }
+
+       if ((*iprop < 1) || (*iprop > UCC_MAX_NUM)) {
+               dev_err(&ofdev->dev, "no support for UCC%u\n", *iprop);
+               kfree(qe_port);
+               return -ENODEV;
+       }
+       qe_port->ucc_num = *iprop - 1;
+
+       /*
+        * In the future, we should not require the BRG to be specified in the
+        * device tree.  If no clock-source is specified, then just pick a BRG
+        * to use.  This requires a new QE library function that manages BRG
+        * assignments.
+        */
+
+       sprop = of_get_property(np, "rx-clock-name", NULL);
+       if (!sprop) {
+               dev_err(&ofdev->dev, "missing rx-clock-name in device tree\n");
+               kfree(qe_port);
+               return -ENODEV;
+       }
+
+       qe_port->us_info.rx_clock = qe_clock_source(sprop);
+       if ((qe_port->us_info.rx_clock < QE_BRG1) ||
+           (qe_port->us_info.rx_clock > QE_BRG16)) {
+               dev_err(&ofdev->dev, "rx-clock-name must be a BRG for UART\n");
+               kfree(qe_port);
+               return -ENODEV;
+       }
+
+#ifdef LOOPBACK
+       /* In internal loopback mode, TX and RX must use the same clock */
+       qe_port->us_info.tx_clock = qe_port->us_info.rx_clock;
+#else
+       sprop = of_get_property(np, "tx-clock-name", NULL);
+       if (!sprop) {
+               dev_err(&ofdev->dev, "missing tx-clock-name in device tree\n");
+               kfree(qe_port);
+               return -ENODEV;
+       }
+       qe_port->us_info.tx_clock = qe_clock_source(sprop);
+#endif
+       if ((qe_port->us_info.tx_clock < QE_BRG1) ||
+           (qe_port->us_info.tx_clock > QE_BRG16)) {
+               dev_err(&ofdev->dev, "tx-clock-name must be a BRG for UART\n");
+               kfree(qe_port);
+               return -ENODEV;
+       }
+
+       /* Get the port number, numbered 0-3 */
+       iprop = of_get_property(np, "port-number", NULL);
+       if (!iprop) {
+               dev_err(&ofdev->dev, "missing port-number in device tree\n");
+               kfree(qe_port);
+               return -EINVAL;
+       }
+       qe_port->port.line = *iprop;
+       if (qe_port->port.line >= UCC_MAX_UART) {
+               dev_err(&ofdev->dev, "port-number must be 0-%u\n",
+                       UCC_MAX_UART - 1);
+               kfree(qe_port);
+               return -EINVAL;
+       }
+
+       qe_port->port.irq = irq_of_parse_and_map(np, 0);
+       if (qe_port->port.irq == NO_IRQ) {
+               dev_err(&ofdev->dev, "could not map IRQ for UCC%u\n",
+                      qe_port->ucc_num + 1);
+               kfree(qe_port);
+               return -EINVAL;
+       }
+
+       /*
+        * Newer device trees have an "fsl,qe" compatible property for the QE
+        * node, but we still need to support older device trees.
+        */
+       np = of_find_compatible_node(NULL, NULL, "fsl,qe");
+       if (!np) {
+               np = of_find_node_by_type(NULL, "qe");
+               if (!np) {
+                       dev_err(&ofdev->dev, "could not find 'qe' node\n");
+                       kfree(qe_port);
+                       return -EINVAL;
+               }
+       }
+
+       iprop = of_get_property(np, "brg-frequency", NULL);
+       if (!iprop) {
+               dev_err(&ofdev->dev,
+                      "missing brg-frequency in device tree\n");
+               kfree(qe_port);
+               return -EINVAL;
+       }
+
+       if (*iprop)
+               qe_port->port.uartclk = *iprop;
+       else {
+               /*
+                * Older versions of U-Boot do not initialize the brg-frequency
+                * property, so in this case we assume the BRG frequency is
+                * half the QE bus frequency.
+                */
+               iprop = of_get_property(np, "bus-frequency", NULL);
+               if (!iprop) {
+                       dev_err(&ofdev->dev,
+                               "missing QE bus-frequency in device tree\n");
+                       kfree(qe_port);
+                       return -EINVAL;
+               }
+               if (*iprop)
+                       qe_port->port.uartclk = *iprop / 2;
+               else {
+                       dev_err(&ofdev->dev,
+                               "invalid QE bus-frequency in device tree\n");
+                       kfree(qe_port);
+                       return -EINVAL;
+               }
+       }
+
+       spin_lock_init(&qe_port->port.lock);
+       qe_port->np = np;
+       qe_port->port.dev = &ofdev->dev;
+       qe_port->port.ops = &qe_uart_pops;
+       qe_port->port.iotype = UPIO_MEM;
+
+       qe_port->tx_nrfifos = TX_NUM_FIFO;
+       qe_port->tx_fifosize = TX_BUF_SIZE;
+       qe_port->rx_nrfifos = RX_NUM_FIFO;
+       qe_port->rx_fifosize = RX_BUF_SIZE;
+
+       qe_port->wait_closing = UCC_WAIT_CLOSING;
+       qe_port->port.fifosize = 512;
+       qe_port->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
+
+       qe_port->us_info.ucc_num = qe_port->ucc_num;
+       qe_port->us_info.regs = (phys_addr_t) res.start;
+       qe_port->us_info.irq = qe_port->port.irq;
+
+       qe_port->us_info.rx_bd_ring_len = qe_port->rx_nrfifos;
+       qe_port->us_info.tx_bd_ring_len = qe_port->tx_nrfifos;
+
+       /* Make sure ucc_slow_init() initializes both TX and RX */
+       qe_port->us_info.init_tx = 1;
+       qe_port->us_info.init_rx = 1;
+
+       /* Add the port to the uart sub-system.  This will cause
+        * qe_uart_config_port() to be called, so the us_info structure must
+        * be initialized.
+        */
+       ret = uart_add_one_port(&ucc_uart_driver, &qe_port->port);
+       if (ret) {
+               dev_err(&ofdev->dev, "could not add /dev/ttyQE%u\n",
+                      qe_port->port.line);
+               kfree(qe_port);
+               return ret;
+       }
+
+       dev_set_drvdata(&ofdev->dev, qe_port);
+
+       dev_info(&ofdev->dev, "UCC%u assigned to /dev/ttyQE%u\n",
+               qe_port->ucc_num + 1, qe_port->port.line);
+
+       /* Display the mknod command for this device */
+       dev_dbg(&ofdev->dev, "mknod command is 'mknod /dev/ttyQE%u c %u %u'\n",
+              qe_port->port.line, SERIAL_QE_MAJOR,
+              SERIAL_QE_MINOR + qe_port->port.line);
+
+       return 0;
+}
+
+static int ucc_uart_remove(struct platform_device *ofdev)
+{
+       struct uart_qe_port *qe_port = dev_get_drvdata(&ofdev->dev);
+
+       dev_info(&ofdev->dev, "removing /dev/ttyQE%u\n", qe_port->port.line);
+
+       uart_remove_one_port(&ucc_uart_driver, &qe_port->port);
+
+       dev_set_drvdata(&ofdev->dev, NULL);
+       kfree(qe_port);
+
+       return 0;
+}
+
+static struct of_device_id ucc_uart_match[] = {
+       {
+               .type = "serial",
+               .compatible = "ucc_uart",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, ucc_uart_match);
+
+static struct of_platform_driver ucc_uart_of_driver = {
+       .driver = {
+               .name = "ucc_uart",
+               .owner = THIS_MODULE,
+               .of_match_table    = ucc_uart_match,
+       },
+       .probe          = ucc_uart_probe,
+       .remove         = ucc_uart_remove,
+};
+
+static int __init ucc_uart_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "Freescale QUICC Engine UART device driver\n");
+#ifdef LOOPBACK
+       printk(KERN_INFO "ucc-uart: Using loopback mode\n");
+#endif
+
+       ret = uart_register_driver(&ucc_uart_driver);
+       if (ret) {
+               printk(KERN_ERR "ucc-uart: could not register UART driver\n");
+               return ret;
+       }
+
+       ret = of_register_platform_driver(&ucc_uart_of_driver);
+       if (ret)
+               printk(KERN_ERR
+                      "ucc-uart: could not register platform driver\n");
+
+       return ret;
+}
+
+static void __exit ucc_uart_exit(void)
+{
+       printk(KERN_INFO
+              "Freescale QUICC Engine UART device driver unloading\n");
+
+       of_unregister_platform_driver(&ucc_uart_of_driver);
+       uart_unregister_driver(&ucc_uart_driver);
+}
+
+module_init(ucc_uart_init);
+module_exit(ucc_uart_exit);
+
+MODULE_DESCRIPTION("Freescale QUICC Engine (QE) UART");
+MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_QE_MAJOR);
+
diff --git a/drivers/tty/serial/vr41xx_siu.c b/drivers/tty/serial/vr41xx_siu.c
new file mode 100644 (file)
index 0000000..3beb6ab
--- /dev/null
@@ -0,0 +1,978 @@
+/*
+ *  Driver for NEC VR4100 series Serial Interface Unit.
+ *
+ *  Copyright (C) 2004-2008  Yoichi Yuasa <yuasa@linux-mips.org>
+ *
+ *  Based on drivers/serial/8250.c, by Russell King.
+ *
+ *  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
+ */
+
+#if defined(CONFIG_SERIAL_VR41XX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/console.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+#include <asm/io.h>
+#include <asm/vr41xx/siu.h>
+#include <asm/vr41xx/vr41xx.h>
+
+#define SIU_BAUD_BASE  1152000
+#define SIU_MAJOR      204
+#define SIU_MINOR_BASE 82
+
+#define RX_MAX_COUNT   256
+#define TX_MAX_COUNT   15
+
+#define SIUIRSEL       0x08
+ #define TMICMODE      0x20
+ #define TMICTX                0x10
+ #define IRMSEL                0x0c
+ #define IRMSEL_HP     0x08
+ #define IRMSEL_TEMIC  0x04
+ #define IRMSEL_SHARP  0x00
+ #define IRUSESEL      0x02
+ #define SIRSEL                0x01
+
+static struct uart_port siu_uart_ports[SIU_PORTS_MAX] = {
+       [0 ... SIU_PORTS_MAX-1] = {
+               .lock   = __SPIN_LOCK_UNLOCKED(siu_uart_ports->lock),
+               .irq    = -1,
+       },
+};
+
+#ifdef CONFIG_SERIAL_VR41XX_CONSOLE
+static uint8_t lsr_break_flag[SIU_PORTS_MAX];
+#endif
+
+#define siu_read(port, offset)         readb((port)->membase + (offset))
+#define siu_write(port, offset, value) writeb((value), (port)->membase + (offset))
+
+void vr41xx_select_siu_interface(siu_interface_t interface)
+{
+       struct uart_port *port;
+       unsigned long flags;
+       uint8_t irsel;
+
+       port = &siu_uart_ports[0];
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       irsel = siu_read(port, SIUIRSEL);
+       if (interface == SIU_INTERFACE_IRDA)
+               irsel |= SIRSEL;
+       else
+               irsel &= ~SIRSEL;
+       siu_write(port, SIUIRSEL, irsel);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+EXPORT_SYMBOL_GPL(vr41xx_select_siu_interface);
+
+void vr41xx_use_irda(irda_use_t use)
+{
+       struct uart_port *port;
+       unsigned long flags;
+       uint8_t irsel;
+
+       port = &siu_uart_ports[0];
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       irsel = siu_read(port, SIUIRSEL);
+       if (use == FIR_USE_IRDA)
+               irsel |= IRUSESEL;
+       else
+               irsel &= ~IRUSESEL;
+       siu_write(port, SIUIRSEL, irsel);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+EXPORT_SYMBOL_GPL(vr41xx_use_irda);
+
+void vr41xx_select_irda_module(irda_module_t module, irda_speed_t speed)
+{
+       struct uart_port *port;
+       unsigned long flags;
+       uint8_t irsel;
+
+       port = &siu_uart_ports[0];
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       irsel = siu_read(port, SIUIRSEL);
+       irsel &= ~(IRMSEL | TMICTX | TMICMODE);
+       switch (module) {
+       case SHARP_IRDA:
+               irsel |= IRMSEL_SHARP;
+               break;
+       case TEMIC_IRDA:
+               irsel |= IRMSEL_TEMIC | TMICMODE;
+               if (speed == IRDA_TX_4MBPS)
+                       irsel |= TMICTX;
+               break;
+       case HP_IRDA:
+               irsel |= IRMSEL_HP;
+               break;
+       default:
+               break;
+       }
+       siu_write(port, SIUIRSEL, irsel);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+EXPORT_SYMBOL_GPL(vr41xx_select_irda_module);
+
+static inline void siu_clear_fifo(struct uart_port *port)
+{
+       siu_write(port, UART_FCR, UART_FCR_ENABLE_FIFO);
+       siu_write(port, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
+                                 UART_FCR_CLEAR_XMIT);
+       siu_write(port, UART_FCR, 0);
+}
+
+static inline unsigned long siu_port_size(struct uart_port *port)
+{
+       switch (port->type) {
+       case PORT_VR41XX_SIU:
+               return 11UL;
+       case PORT_VR41XX_DSIU:
+               return 8UL;
+       }
+
+       return 0;
+}
+
+static inline unsigned int siu_check_type(struct uart_port *port)
+{
+       if (port->line == 0)
+               return PORT_VR41XX_SIU;
+       if (port->line == 1 && port->irq != -1)
+               return PORT_VR41XX_DSIU;
+
+       return PORT_UNKNOWN;
+}
+
+static inline const char *siu_type_name(struct uart_port *port)
+{
+       switch (port->type) {
+       case PORT_VR41XX_SIU:
+               return "SIU";
+       case PORT_VR41XX_DSIU:
+               return "DSIU";
+       }
+
+       return NULL;
+}
+
+static unsigned int siu_tx_empty(struct uart_port *port)
+{
+       uint8_t lsr;
+
+       lsr = siu_read(port, UART_LSR);
+       if (lsr & UART_LSR_TEMT)
+               return TIOCSER_TEMT;
+
+       return 0;
+}
+
+static void siu_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       uint8_t mcr = 0;
+
+       if (mctrl & TIOCM_DTR)
+               mcr |= UART_MCR_DTR;
+       if (mctrl & TIOCM_RTS)
+               mcr |= UART_MCR_RTS;
+       if (mctrl & TIOCM_OUT1)
+               mcr |= UART_MCR_OUT1;
+       if (mctrl & TIOCM_OUT2)
+               mcr |= UART_MCR_OUT2;
+       if (mctrl & TIOCM_LOOP)
+               mcr |= UART_MCR_LOOP;
+
+       siu_write(port, UART_MCR, mcr);
+}
+
+static unsigned int siu_get_mctrl(struct uart_port *port)
+{
+       uint8_t msr;
+       unsigned int mctrl = 0;
+
+       msr = siu_read(port, UART_MSR);
+       if (msr & UART_MSR_DCD)
+               mctrl |= TIOCM_CAR;
+       if (msr & UART_MSR_RI)
+               mctrl |= TIOCM_RNG;
+       if (msr & UART_MSR_DSR)
+               mctrl |= TIOCM_DSR;
+       if (msr & UART_MSR_CTS)
+               mctrl |= TIOCM_CTS;
+
+       return mctrl;
+}
+
+static void siu_stop_tx(struct uart_port *port)
+{
+       unsigned long flags;
+       uint8_t ier;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       ier = siu_read(port, UART_IER);
+       ier &= ~UART_IER_THRI;
+       siu_write(port, UART_IER, ier);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void siu_start_tx(struct uart_port *port)
+{
+       unsigned long flags;
+       uint8_t ier;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       ier = siu_read(port, UART_IER);
+       ier |= UART_IER_THRI;
+       siu_write(port, UART_IER, ier);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void siu_stop_rx(struct uart_port *port)
+{
+       unsigned long flags;
+       uint8_t ier;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       ier = siu_read(port, UART_IER);
+       ier &= ~UART_IER_RLSI;
+       siu_write(port, UART_IER, ier);
+
+       port->read_status_mask &= ~UART_LSR_DR;
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void siu_enable_ms(struct uart_port *port)
+{
+       unsigned long flags;
+       uint8_t ier;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       ier = siu_read(port, UART_IER);
+       ier |= UART_IER_MSI;
+       siu_write(port, UART_IER, ier);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void siu_break_ctl(struct uart_port *port, int ctl)
+{
+       unsigned long flags;
+       uint8_t lcr;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       lcr = siu_read(port, UART_LCR);
+       if (ctl == -1)
+               lcr |= UART_LCR_SBC;
+       else
+               lcr &= ~UART_LCR_SBC;
+       siu_write(port, UART_LCR, lcr);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static inline void receive_chars(struct uart_port *port, uint8_t *status)
+{
+       struct tty_struct *tty;
+       uint8_t lsr, ch;
+       char flag;
+       int max_count = RX_MAX_COUNT;
+
+       tty = port->state->port.tty;
+       lsr = *status;
+
+       do {
+               ch = siu_read(port, UART_RX);
+               port->icount.rx++;
+               flag = TTY_NORMAL;
+
+#ifdef CONFIG_SERIAL_VR41XX_CONSOLE
+               lsr |= lsr_break_flag[port->line];
+               lsr_break_flag[port->line] = 0;
+#endif
+               if (unlikely(lsr & (UART_LSR_BI | UART_LSR_FE |
+                                   UART_LSR_PE | UART_LSR_OE))) {
+                       if (lsr & UART_LSR_BI) {
+                               lsr &= ~(UART_LSR_FE | UART_LSR_PE);
+                               port->icount.brk++;
+
+                               if (uart_handle_break(port))
+                                       goto ignore_char;
+                       }
+
+                       if (lsr & UART_LSR_FE)
+                               port->icount.frame++;
+                       if (lsr & UART_LSR_PE)
+                               port->icount.parity++;
+                       if (lsr & UART_LSR_OE)
+                               port->icount.overrun++;
+
+                       lsr &= port->read_status_mask;
+                       if (lsr & UART_LSR_BI)
+                               flag = TTY_BREAK;
+                       if (lsr & UART_LSR_FE)
+                               flag = TTY_FRAME;
+                       if (lsr & UART_LSR_PE)
+                               flag = TTY_PARITY;
+               }
+
+               if (uart_handle_sysrq_char(port, ch))
+                       goto ignore_char;
+
+               uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
+
+       ignore_char:
+               lsr = siu_read(port, UART_LSR);
+       } while ((lsr & UART_LSR_DR) && (max_count-- > 0));
+
+       tty_flip_buffer_push(tty);
+
+       *status = lsr;
+}
+
+static inline void check_modem_status(struct uart_port *port)
+{
+       uint8_t msr;
+
+       msr = siu_read(port, UART_MSR);
+       if ((msr & UART_MSR_ANY_DELTA) == 0)
+               return;
+       if (msr & UART_MSR_DDCD)
+               uart_handle_dcd_change(port, msr & UART_MSR_DCD);
+       if (msr & UART_MSR_TERI)
+               port->icount.rng++;
+       if (msr & UART_MSR_DDSR)
+               port->icount.dsr++;
+       if (msr & UART_MSR_DCTS)
+               uart_handle_cts_change(port, msr & UART_MSR_CTS);
+
+       wake_up_interruptible(&port->state->port.delta_msr_wait);
+}
+
+static inline void transmit_chars(struct uart_port *port)
+{
+       struct circ_buf *xmit;
+       int max_count = TX_MAX_COUNT;
+
+       xmit = &port->state->xmit;
+
+       if (port->x_char) {
+               siu_write(port, UART_TX, port->x_char);
+               port->icount.tx++;
+               port->x_char = 0;
+               return;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               siu_stop_tx(port);
+               return;
+       }
+
+       do {
+               siu_write(port, UART_TX, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (max_count-- > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit))
+               siu_stop_tx(port);
+}
+
+static irqreturn_t siu_interrupt(int irq, void *dev_id)
+{
+       struct uart_port *port;
+       uint8_t iir, lsr;
+
+       port = (struct uart_port *)dev_id;
+
+       iir = siu_read(port, UART_IIR);
+       if (iir & UART_IIR_NO_INT)
+               return IRQ_NONE;
+
+       lsr = siu_read(port, UART_LSR);
+       if (lsr & UART_LSR_DR)
+               receive_chars(port, &lsr);
+
+       check_modem_status(port);
+
+       if (lsr & UART_LSR_THRE)
+               transmit_chars(port);
+
+       return IRQ_HANDLED;
+}
+
+static int siu_startup(struct uart_port *port)
+{
+       int retval;
+
+       if (port->membase == NULL)
+               return -ENODEV;
+
+       siu_clear_fifo(port);
+
+       (void)siu_read(port, UART_LSR);
+       (void)siu_read(port, UART_RX);
+       (void)siu_read(port, UART_IIR);
+       (void)siu_read(port, UART_MSR);
+
+       if (siu_read(port, UART_LSR) == 0xff)
+               return -ENODEV;
+
+       retval = request_irq(port->irq, siu_interrupt, 0, siu_type_name(port), port);
+       if (retval)
+               return retval;
+
+       if (port->type == PORT_VR41XX_DSIU)
+               vr41xx_enable_dsiuint(DSIUINT_ALL);
+
+       siu_write(port, UART_LCR, UART_LCR_WLEN8);
+
+       spin_lock_irq(&port->lock);
+       siu_set_mctrl(port, port->mctrl);
+       spin_unlock_irq(&port->lock);
+
+       siu_write(port, UART_IER, UART_IER_RLSI | UART_IER_RDI);
+
+       (void)siu_read(port, UART_LSR);
+       (void)siu_read(port, UART_RX);
+       (void)siu_read(port, UART_IIR);
+       (void)siu_read(port, UART_MSR);
+
+       return 0;
+}
+
+static void siu_shutdown(struct uart_port *port)
+{
+       unsigned long flags;
+       uint8_t lcr;
+
+       siu_write(port, UART_IER, 0);
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       port->mctrl &= ~TIOCM_OUT2;
+       siu_set_mctrl(port, port->mctrl);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       lcr = siu_read(port, UART_LCR);
+       lcr &= ~UART_LCR_SBC;
+       siu_write(port, UART_LCR, lcr);
+
+       siu_clear_fifo(port);
+
+       (void)siu_read(port, UART_RX);
+
+       if (port->type == PORT_VR41XX_DSIU)
+               vr41xx_disable_dsiuint(DSIUINT_ALL);
+
+       free_irq(port->irq, port);
+}
+
+static void siu_set_termios(struct uart_port *port, struct ktermios *new,
+                            struct ktermios *old)
+{
+       tcflag_t c_cflag, c_iflag;
+       uint8_t lcr, fcr, ier;
+       unsigned int baud, quot;
+       unsigned long flags;
+
+       c_cflag = new->c_cflag;
+       switch (c_cflag & CSIZE) {
+       case CS5:
+               lcr = UART_LCR_WLEN5;
+               break;
+       case CS6:
+               lcr = UART_LCR_WLEN6;
+               break;
+       case CS7:
+               lcr = UART_LCR_WLEN7;
+               break;
+       default:
+               lcr = UART_LCR_WLEN8;
+               break;
+       }
+
+       if (c_cflag & CSTOPB)
+               lcr |= UART_LCR_STOP;
+       if (c_cflag & PARENB)
+               lcr |= UART_LCR_PARITY;
+       if ((c_cflag & PARODD) != PARODD)
+               lcr |= UART_LCR_EPAR;
+       if (c_cflag & CMSPAR)
+               lcr |= UART_LCR_SPAR;
+
+       baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
+       quot = uart_get_divisor(port, baud);
+
+       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       uart_update_timeout(port, c_cflag, baud);
+
+       c_iflag = new->c_iflag;
+
+       port->read_status_mask = UART_LSR_THRE | UART_LSR_OE | UART_LSR_DR;
+       if (c_iflag & INPCK)
+               port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+       if (c_iflag & (BRKINT | PARMRK))
+               port->read_status_mask |= UART_LSR_BI;
+
+       port->ignore_status_mask = 0;
+       if (c_iflag & IGNPAR)
+               port->ignore_status_mask |= UART_LSR_FE | UART_LSR_PE;
+       if (c_iflag & IGNBRK) {
+               port->ignore_status_mask |= UART_LSR_BI;
+               if (c_iflag & IGNPAR)
+                       port->ignore_status_mask |= UART_LSR_OE;
+       }
+
+       if ((c_cflag & CREAD) == 0)
+               port->ignore_status_mask |= UART_LSR_DR;
+
+       ier = siu_read(port, UART_IER);
+       ier &= ~UART_IER_MSI;
+       if (UART_ENABLE_MS(port, c_cflag))
+               ier |= UART_IER_MSI;
+       siu_write(port, UART_IER, ier);
+
+       siu_write(port, UART_LCR, lcr | UART_LCR_DLAB);
+
+       siu_write(port, UART_DLL, (uint8_t)quot);
+       siu_write(port, UART_DLM, (uint8_t)(quot >> 8));
+
+       siu_write(port, UART_LCR, lcr);
+
+       siu_write(port, UART_FCR, fcr);
+
+       siu_set_mctrl(port, port->mctrl);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void siu_pm(struct uart_port *port, unsigned int state, unsigned int oldstate)
+{
+       switch (state) {
+       case 0:
+               switch (port->type) {
+               case PORT_VR41XX_SIU:
+                       vr41xx_supply_clock(SIU_CLOCK);
+                       break;
+               case PORT_VR41XX_DSIU:
+                       vr41xx_supply_clock(DSIU_CLOCK);
+                       break;
+               }
+               break;
+       case 3:
+               switch (port->type) {
+               case PORT_VR41XX_SIU:
+                       vr41xx_mask_clock(SIU_CLOCK);
+                       break;
+               case PORT_VR41XX_DSIU:
+                       vr41xx_mask_clock(DSIU_CLOCK);
+                       break;
+               }
+               break;
+       }
+}
+
+static const char *siu_type(struct uart_port *port)
+{
+       return siu_type_name(port);
+}
+
+static void siu_release_port(struct uart_port *port)
+{
+       unsigned long size;
+
+       if (port->flags & UPF_IOREMAP) {
+               iounmap(port->membase);
+               port->membase = NULL;
+       }
+
+       size = siu_port_size(port);
+       release_mem_region(port->mapbase, size);
+}
+
+static int siu_request_port(struct uart_port *port)
+{
+       unsigned long size;
+       struct resource *res;
+
+       size = siu_port_size(port);
+       res = request_mem_region(port->mapbase, size, siu_type_name(port));
+       if (res == NULL)
+               return -EBUSY;
+
+       if (port->flags & UPF_IOREMAP) {
+               port->membase = ioremap(port->mapbase, size);
+               if (port->membase == NULL) {
+                       release_resource(res);
+                       return -ENOMEM;
+               }
+       }
+
+       return 0;
+}
+
+static void siu_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = siu_check_type(port);
+               (void)siu_request_port(port);
+       }
+}
+
+static int siu_verify_port(struct uart_port *port, struct serial_struct *serial)
+{
+       if (port->type != PORT_VR41XX_SIU && port->type != PORT_VR41XX_DSIU)
+               return -EINVAL;
+       if (port->irq != serial->irq)
+               return -EINVAL;
+       if (port->iotype != serial->io_type)
+               return -EINVAL;
+       if (port->mapbase != (unsigned long)serial->iomem_base)
+               return -EINVAL;
+
+       return 0;
+}
+
+static struct uart_ops siu_uart_ops = {
+       .tx_empty       = siu_tx_empty,
+       .set_mctrl      = siu_set_mctrl,
+       .get_mctrl      = siu_get_mctrl,
+       .stop_tx        = siu_stop_tx,
+       .start_tx       = siu_start_tx,
+       .stop_rx        = siu_stop_rx,
+       .enable_ms      = siu_enable_ms,
+       .break_ctl      = siu_break_ctl,
+       .startup        = siu_startup,
+       .shutdown       = siu_shutdown,
+       .set_termios    = siu_set_termios,
+       .pm             = siu_pm,
+       .type           = siu_type,
+       .release_port   = siu_release_port,
+       .request_port   = siu_request_port,
+       .config_port    = siu_config_port,
+       .verify_port    = siu_verify_port,
+};
+
+static int siu_init_ports(struct platform_device *pdev)
+{
+       struct uart_port *port;
+       struct resource *res;
+       int *type = pdev->dev.platform_data;
+       int i;
+
+       if (!type)
+               return 0;
+
+       port = siu_uart_ports;
+       for (i = 0; i < SIU_PORTS_MAX; i++) {
+               port->type = type[i];
+               if (port->type == PORT_UNKNOWN)
+                       continue;
+               port->irq = platform_get_irq(pdev, i);
+               port->uartclk = SIU_BAUD_BASE * 16;
+               port->fifosize = 16;
+               port->regshift = 0;
+               port->iotype = UPIO_MEM;
+               port->flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
+               port->line = i;
+               res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+               port->mapbase = res->start;
+               port++;
+       }
+
+       return i;
+}
+
+#ifdef CONFIG_SERIAL_VR41XX_CONSOLE
+
+#define BOTH_EMPTY     (UART_LSR_TEMT | UART_LSR_THRE)
+
+static void wait_for_xmitr(struct uart_port *port)
+{
+       int timeout = 10000;
+       uint8_t lsr, msr;
+
+       do {
+               lsr = siu_read(port, UART_LSR);
+               if (lsr & UART_LSR_BI)
+                       lsr_break_flag[port->line] = UART_LSR_BI;
+
+               if ((lsr & BOTH_EMPTY) == BOTH_EMPTY)
+                       break;
+       } while (timeout-- > 0);
+
+       if (port->flags & UPF_CONS_FLOW) {
+               timeout = 1000000;
+
+               do {
+                       msr = siu_read(port, UART_MSR);
+                       if ((msr & UART_MSR_CTS) != 0)
+                               break;
+               } while (timeout-- > 0);
+       }
+}
+
+static void siu_console_putchar(struct uart_port *port, int ch)
+{
+       wait_for_xmitr(port);
+       siu_write(port, UART_TX, ch);
+}
+
+static void siu_console_write(struct console *con, const char *s, unsigned count)
+{
+       struct uart_port *port;
+       uint8_t ier;
+
+       port = &siu_uart_ports[con->index];
+
+       ier = siu_read(port, UART_IER);
+       siu_write(port, UART_IER, 0);
+
+       uart_console_write(port, s, count, siu_console_putchar);
+
+       wait_for_xmitr(port);
+       siu_write(port, UART_IER, ier);
+}
+
+static int __init siu_console_setup(struct console *con, char *options)
+{
+       struct uart_port *port;
+       int baud = 9600;
+       int parity = 'n';
+       int bits = 8;
+       int flow = 'n';
+
+       if (con->index >= SIU_PORTS_MAX)
+               con->index = 0;
+
+       port = &siu_uart_ports[con->index];
+       if (port->membase == NULL) {
+               if (port->mapbase == 0)
+                       return -ENODEV;
+               port->membase = ioremap(port->mapbase, siu_port_size(port));
+       }
+
+       if (port->type == PORT_VR41XX_SIU)
+               vr41xx_select_siu_interface(SIU_INTERFACE_RS232C);
+
+       if (options != NULL)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, con, baud, parity, bits, flow);
+}
+
+static struct uart_driver siu_uart_driver;
+
+static struct console siu_console = {
+       .name   = "ttyVR",
+       .write  = siu_console_write,
+       .device = uart_console_device,
+       .setup  = siu_console_setup,
+       .flags  = CON_PRINTBUFFER,
+       .index  = -1,
+       .data   = &siu_uart_driver,
+};
+
+static int __devinit siu_console_init(void)
+{
+       struct uart_port *port;
+       int i;
+
+       for (i = 0; i < SIU_PORTS_MAX; i++) {
+               port = &siu_uart_ports[i];
+               port->ops = &siu_uart_ops;
+       }
+
+       register_console(&siu_console);
+
+       return 0;
+}
+
+console_initcall(siu_console_init);
+
+void __init vr41xx_siu_early_setup(struct uart_port *port)
+{
+       if (port->type == PORT_UNKNOWN)
+               return;
+
+       siu_uart_ports[port->line].line = port->line;
+       siu_uart_ports[port->line].type = port->type;
+       siu_uart_ports[port->line].uartclk = SIU_BAUD_BASE * 16;
+       siu_uart_ports[port->line].mapbase = port->mapbase;
+       siu_uart_ports[port->line].mapbase = port->mapbase;
+       siu_uart_ports[port->line].ops = &siu_uart_ops;
+}
+
+#define SERIAL_VR41XX_CONSOLE  &siu_console
+#else
+#define SERIAL_VR41XX_CONSOLE  NULL
+#endif
+
+static struct uart_driver siu_uart_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "SIU",
+       .dev_name       = "ttyVR",
+       .major          = SIU_MAJOR,
+       .minor          = SIU_MINOR_BASE,
+       .cons           = SERIAL_VR41XX_CONSOLE,
+};
+
+static int __devinit siu_probe(struct platform_device *dev)
+{
+       struct uart_port *port;
+       int num, i, retval;
+
+       num = siu_init_ports(dev);
+       if (num <= 0)
+               return -ENODEV;
+
+       siu_uart_driver.nr = num;
+       retval = uart_register_driver(&siu_uart_driver);
+       if (retval)
+               return retval;
+
+       for (i = 0; i < num; i++) {
+               port = &siu_uart_ports[i];
+               port->ops = &siu_uart_ops;
+               port->dev = &dev->dev;
+
+               retval = uart_add_one_port(&siu_uart_driver, port);
+               if (retval < 0) {
+                       port->dev = NULL;
+                       break;
+               }
+       }
+
+       if (i == 0 && retval < 0) {
+               uart_unregister_driver(&siu_uart_driver);
+               return retval;
+       }
+
+       return 0;
+}
+
+static int __devexit siu_remove(struct platform_device *dev)
+{
+       struct uart_port *port;
+       int i;
+
+       for (i = 0; i < siu_uart_driver.nr; i++) {
+               port = &siu_uart_ports[i];
+               if (port->dev == &dev->dev) {
+                       uart_remove_one_port(&siu_uart_driver, port);
+                       port->dev = NULL;
+               }
+       }
+
+       uart_unregister_driver(&siu_uart_driver);
+
+       return 0;
+}
+
+static int siu_suspend(struct platform_device *dev, pm_message_t state)
+{
+       struct uart_port *port;
+       int i;
+
+       for (i = 0; i < siu_uart_driver.nr; i++) {
+               port = &siu_uart_ports[i];
+               if ((port->type == PORT_VR41XX_SIU ||
+                    port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev)
+                       uart_suspend_port(&siu_uart_driver, port);
+
+       }
+
+       return 0;
+}
+
+static int siu_resume(struct platform_device *dev)
+{
+       struct uart_port *port;
+       int i;
+
+       for (i = 0; i < siu_uart_driver.nr; i++) {
+               port = &siu_uart_ports[i];
+               if ((port->type == PORT_VR41XX_SIU ||
+                    port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev)
+                       uart_resume_port(&siu_uart_driver, port);
+       }
+
+       return 0;
+}
+
+static struct platform_driver siu_device_driver = {
+       .probe          = siu_probe,
+       .remove         = __devexit_p(siu_remove),
+       .suspend        = siu_suspend,
+       .resume         = siu_resume,
+       .driver         = {
+               .name   = "SIU",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init vr41xx_siu_init(void)
+{
+       return platform_driver_register(&siu_device_driver);
+}
+
+static void __exit vr41xx_siu_exit(void)
+{
+       platform_driver_unregister(&siu_device_driver);
+}
+
+module_init(vr41xx_siu_init);
+module_exit(vr41xx_siu_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:SIU");
diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c
new file mode 100644 (file)
index 0000000..322bf56
--- /dev/null
@@ -0,0 +1,648 @@
+/*
+ * drivers/serial/vt8500_serial.c
+ *
+ * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * Based on msm_serial.c, which is:
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Robert Love <rlove@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#if defined(CONFIG_SERIAL_VT8500_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+# define SUPPORT_SYSRQ
+#endif
+
+#include <linux/hrtimer.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+/*
+ * UART Register offsets
+ */
+
+#define VT8500_URTDR           0x0000  /* Transmit data */
+#define VT8500_URRDR           0x0004  /* Receive data */
+#define VT8500_URDIV           0x0008  /* Clock/Baud rate divisor */
+#define VT8500_URLCR           0x000C  /* Line control */
+#define VT8500_URICR           0x0010  /* IrDA control */
+#define VT8500_URIER           0x0014  /* Interrupt enable */
+#define VT8500_URISR           0x0018  /* Interrupt status */
+#define VT8500_URUSR           0x001c  /* UART status */
+#define VT8500_URFCR           0x0020  /* FIFO control */
+#define VT8500_URFIDX          0x0024  /* FIFO index */
+#define VT8500_URBKR           0x0028  /* Break signal count */
+#define VT8500_URTOD           0x002c  /* Time out divisor */
+#define VT8500_TXFIFO          0x1000  /* Transmit FIFO (16x8) */
+#define VT8500_RXFIFO          0x1020  /* Receive FIFO (16x10) */
+
+/*
+ * Interrupt enable and status bits
+ */
+
+#define TXDE   (1 << 0)        /* Tx Data empty */
+#define RXDF   (1 << 1)        /* Rx Data full */
+#define TXFAE  (1 << 2)        /* Tx FIFO almost empty */
+#define TXFE   (1 << 3)        /* Tx FIFO empty */
+#define RXFAF  (1 << 4)        /* Rx FIFO almost full */
+#define RXFF   (1 << 5)        /* Rx FIFO full */
+#define TXUDR  (1 << 6)        /* Tx underrun */
+#define RXOVER (1 << 7)        /* Rx overrun */
+#define PER    (1 << 8)        /* Parity error */
+#define FER    (1 << 9)        /* Frame error */
+#define TCTS   (1 << 10)       /* Toggle of CTS */
+#define RXTOUT (1 << 11)       /* Rx timeout */
+#define BKDONE (1 << 12)       /* Break signal done */
+#define ERR    (1 << 13)       /* AHB error response */
+
+#define RX_FIFO_INTS   (RXFAF | RXFF | RXOVER | PER | FER | RXTOUT)
+#define TX_FIFO_INTS   (TXFAE | TXFE | TXUDR)
+
+struct vt8500_port {
+       struct uart_port        uart;
+       char                    name[16];
+       struct clk              *clk;
+       unsigned int            ier;
+};
+
+static inline void vt8500_write(struct uart_port *port, unsigned int val,
+                            unsigned int off)
+{
+       writel(val, port->membase + off);
+}
+
+static inline unsigned int vt8500_read(struct uart_port *port, unsigned int off)
+{
+       return readl(port->membase + off);
+}
+
+static void vt8500_stop_tx(struct uart_port *port)
+{
+       struct vt8500_port *vt8500_port = container_of(port,
+                                                      struct vt8500_port,
+                                                      uart);
+
+       vt8500_port->ier &= ~TX_FIFO_INTS;
+       vt8500_write(port, vt8500_port->ier, VT8500_URIER);
+}
+
+static void vt8500_stop_rx(struct uart_port *port)
+{
+       struct vt8500_port *vt8500_port = container_of(port,
+                                                      struct vt8500_port,
+                                                      uart);
+
+       vt8500_port->ier &= ~RX_FIFO_INTS;
+       vt8500_write(port, vt8500_port->ier, VT8500_URIER);
+}
+
+static void vt8500_enable_ms(struct uart_port *port)
+{
+       struct vt8500_port *vt8500_port = container_of(port,
+                                                      struct vt8500_port,
+                                                      uart);
+
+       vt8500_port->ier |= TCTS;
+       vt8500_write(port, vt8500_port->ier, VT8500_URIER);
+}
+
+static void handle_rx(struct uart_port *port)
+{
+       struct tty_struct *tty = tty_port_tty_get(&port->state->port);
+       if (!tty) {
+               /* Discard data: no tty available */
+               int count = (vt8500_read(port, VT8500_URFIDX) & 0x1f00) >> 8;
+               u16 ch;
+               while (count--)
+                       ch = readw(port->membase + VT8500_RXFIFO);
+               return;
+       }
+
+       /*
+        * Handle overrun
+        */
+       if ((vt8500_read(port, VT8500_URISR) & RXOVER)) {
+               port->icount.overrun++;
+               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+       }
+
+       /* and now the main RX loop */
+       while (vt8500_read(port, VT8500_URFIDX) & 0x1f00) {
+               unsigned int c;
+               char flag = TTY_NORMAL;
+
+               c = readw(port->membase + VT8500_RXFIFO) & 0x3ff;
+
+               /* Mask conditions we're ignorning. */
+               c &= ~port->read_status_mask;
+
+               if (c & FER) {
+                       port->icount.frame++;
+                       flag = TTY_FRAME;
+               } else if (c & PER) {
+                       port->icount.parity++;
+                       flag = TTY_PARITY;
+               }
+               port->icount.rx++;
+
+               if (!uart_handle_sysrq_char(port, c))
+                       tty_insert_flip_char(tty, c, flag);
+       }
+
+       tty_flip_buffer_push(tty);
+       tty_kref_put(tty);
+}
+
+static void handle_tx(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->state->xmit;
+
+       if (port->x_char) {
+               writeb(port->x_char, port->membase + VT8500_TXFIFO);
+               port->icount.tx++;
+               port->x_char = 0;
+       }
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               vt8500_stop_tx(port);
+               return;
+       }
+
+       while ((vt8500_read(port, VT8500_URFIDX) & 0x1f) < 16) {
+               if (uart_circ_empty(xmit))
+                       break;
+
+               writeb(xmit->buf[xmit->tail], port->membase + VT8500_TXFIFO);
+
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit))
+               vt8500_stop_tx(port);
+}
+
+static void vt8500_start_tx(struct uart_port *port)
+{
+       struct vt8500_port *vt8500_port = container_of(port,
+                                                      struct vt8500_port,
+                                                      uart);
+
+       vt8500_port->ier &= ~TX_FIFO_INTS;
+       vt8500_write(port, vt8500_port->ier, VT8500_URIER);
+       handle_tx(port);
+       vt8500_port->ier |= TX_FIFO_INTS;
+       vt8500_write(port, vt8500_port->ier, VT8500_URIER);
+}
+
+static void handle_delta_cts(struct uart_port *port)
+{
+       port->icount.cts++;
+       wake_up_interruptible(&port->state->port.delta_msr_wait);
+}
+
+static irqreturn_t vt8500_irq(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       unsigned long isr;
+
+       spin_lock(&port->lock);
+       isr = vt8500_read(port, VT8500_URISR);
+
+       /* Acknowledge active status bits */
+       vt8500_write(port, isr, VT8500_URISR);
+
+       if (isr & RX_FIFO_INTS)
+               handle_rx(port);
+       if (isr & TX_FIFO_INTS)
+               handle_tx(port);
+       if (isr & TCTS)
+               handle_delta_cts(port);
+
+       spin_unlock(&port->lock);
+
+       return IRQ_HANDLED;
+}
+
+static unsigned int vt8500_tx_empty(struct uart_port *port)
+{
+       return (vt8500_read(port, VT8500_URFIDX) & 0x1f) < 16 ?
+                                               TIOCSER_TEMT : 0;
+}
+
+static unsigned int vt8500_get_mctrl(struct uart_port *port)
+{
+       unsigned int usr;
+
+       usr = vt8500_read(port, VT8500_URUSR);
+       if (usr & (1 << 4))
+               return TIOCM_CTS;
+       else
+               return 0;
+}
+
+static void vt8500_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static void vt8500_break_ctl(struct uart_port *port, int break_ctl)
+{
+       if (break_ctl)
+               vt8500_write(port, vt8500_read(port, VT8500_URLCR) | (1 << 9),
+                            VT8500_URLCR);
+}
+
+static int vt8500_set_baud_rate(struct uart_port *port, unsigned int baud)
+{
+       unsigned long div;
+       unsigned int loops = 1000;
+
+       div = vt8500_read(port, VT8500_URDIV) & ~(0x3ff);
+
+       if (unlikely((baud < 900) || (baud > 921600)))
+               div |= 7;
+       else
+               div |= (921600 / baud) - 1;
+
+       while ((vt8500_read(port, VT8500_URUSR) & (1 << 5)) && --loops)
+               cpu_relax();
+       vt8500_write(port, div, VT8500_URDIV);
+
+       return baud;
+}
+
+static int vt8500_startup(struct uart_port *port)
+{
+       struct vt8500_port *vt8500_port =
+                       container_of(port, struct vt8500_port, uart);
+       int ret;
+
+       snprintf(vt8500_port->name, sizeof(vt8500_port->name),
+                "vt8500_serial%d", port->line);
+
+       ret = request_irq(port->irq, vt8500_irq, IRQF_TRIGGER_HIGH,
+                         vt8500_port->name, port);
+       if (unlikely(ret))
+               return ret;
+
+       vt8500_write(port, 0x03, VT8500_URLCR); /* enable TX & RX */
+
+       return 0;
+}
+
+static void vt8500_shutdown(struct uart_port *port)
+{
+       struct vt8500_port *vt8500_port =
+                       container_of(port, struct vt8500_port, uart);
+
+       vt8500_port->ier = 0;
+
+       /* disable interrupts and FIFOs */
+       vt8500_write(&vt8500_port->uart, 0, VT8500_URIER);
+       vt8500_write(&vt8500_port->uart, 0x880, VT8500_URFCR);
+       free_irq(port->irq, port);
+}
+
+static void vt8500_set_termios(struct uart_port *port,
+                              struct ktermios *termios,
+                              struct ktermios *old)
+{
+       struct vt8500_port *vt8500_port =
+                       container_of(port, struct vt8500_port, uart);
+       unsigned long flags;
+       unsigned int baud, lcr;
+       unsigned int loops = 1000;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* calculate and set baud rate */
+       baud = uart_get_baud_rate(port, termios, old, 900, 921600);
+       baud = vt8500_set_baud_rate(port, baud);
+       if (tty_termios_baud_rate(termios))
+               tty_termios_encode_baud_rate(termios, baud, baud);
+
+       /* calculate parity */
+       lcr = vt8500_read(&vt8500_port->uart, VT8500_URLCR);
+       lcr &= ~((1 << 5) | (1 << 4));
+       if (termios->c_cflag & PARENB) {
+               lcr |= (1 << 4);
+               termios->c_cflag &= ~CMSPAR;
+               if (termios->c_cflag & PARODD)
+                       lcr |= (1 << 5);
+       }
+
+       /* calculate bits per char */
+       lcr &= ~(1 << 2);
+       switch (termios->c_cflag & CSIZE) {
+       case CS7:
+               break;
+       case CS8:
+       default:
+               lcr |= (1 << 2);
+               termios->c_cflag &= ~CSIZE;
+               termios->c_cflag |= CS8;
+               break;
+       }
+
+       /* calculate stop bits */
+       lcr &= ~(1 << 3);
+       if (termios->c_cflag & CSTOPB)
+               lcr |= (1 << 3);
+
+       /* set parity, bits per char, and stop bit */
+       vt8500_write(&vt8500_port->uart, lcr, VT8500_URLCR);
+
+       /* Configure status bits to ignore based on termio flags. */
+       port->read_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->read_status_mask = FER | PER;
+
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       /* Reset FIFOs */
+       vt8500_write(&vt8500_port->uart, 0x88c, VT8500_URFCR);
+       while ((vt8500_read(&vt8500_port->uart, VT8500_URFCR) & 0xc)
+                                                       && --loops)
+               cpu_relax();
+
+       /* Every possible FIFO-related interrupt */
+       vt8500_port->ier = RX_FIFO_INTS | TX_FIFO_INTS;
+
+       /*
+        * CTS flow control
+        */
+       if (UART_ENABLE_MS(&vt8500_port->uart, termios->c_cflag))
+               vt8500_port->ier |= TCTS;
+
+       vt8500_write(&vt8500_port->uart, 0x881, VT8500_URFCR);
+       vt8500_write(&vt8500_port->uart, vt8500_port->ier, VT8500_URIER);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *vt8500_type(struct uart_port *port)
+{
+       struct vt8500_port *vt8500_port =
+                       container_of(port, struct vt8500_port, uart);
+       return vt8500_port->name;
+}
+
+static void vt8500_release_port(struct uart_port *port)
+{
+}
+
+static int vt8500_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static void vt8500_config_port(struct uart_port *port, int flags)
+{
+       port->type = PORT_VT8500;
+}
+
+static int vt8500_verify_port(struct uart_port *port,
+                             struct serial_struct *ser)
+{
+       if (unlikely(ser->type != PORT_UNKNOWN && ser->type != PORT_VT8500))
+               return -EINVAL;
+       if (unlikely(port->irq != ser->irq))
+               return -EINVAL;
+       return 0;
+}
+
+static struct vt8500_port *vt8500_uart_ports[4];
+static struct uart_driver vt8500_uart_driver;
+
+#ifdef CONFIG_SERIAL_VT8500_CONSOLE
+
+static inline void wait_for_xmitr(struct uart_port *port)
+{
+       unsigned int status, tmout = 10000;
+
+       /* Wait up to 10ms for the character(s) to be sent. */
+       do {
+               status = vt8500_read(port, VT8500_URFIDX);
+
+               if (--tmout == 0)
+                       break;
+               udelay(1);
+       } while (status & 0x10);
+}
+
+static void vt8500_console_putchar(struct uart_port *port, int c)
+{
+       wait_for_xmitr(port);
+       writeb(c, port->membase + VT8500_TXFIFO);
+}
+
+static void vt8500_console_write(struct console *co, const char *s,
+                             unsigned int count)
+{
+       struct vt8500_port *vt8500_port = vt8500_uart_ports[co->index];
+       unsigned long ier;
+
+       BUG_ON(co->index < 0 || co->index >= vt8500_uart_driver.nr);
+
+       ier = vt8500_read(&vt8500_port->uart, VT8500_URIER);
+       vt8500_write(&vt8500_port->uart, VT8500_URIER, 0);
+
+       uart_console_write(&vt8500_port->uart, s, count,
+                          vt8500_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and switch back to FIFO
+        */
+       wait_for_xmitr(&vt8500_port->uart);
+       vt8500_write(&vt8500_port->uart, VT8500_URIER, ier);
+}
+
+static int __init vt8500_console_setup(struct console *co, char *options)
+{
+       struct vt8500_port *vt8500_port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (unlikely(co->index >= vt8500_uart_driver.nr || co->index < 0))
+               return -ENXIO;
+
+       vt8500_port = vt8500_uart_ports[co->index];
+
+       if (!vt8500_port)
+               return -ENODEV;
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(&vt8500_port->uart,
+                                co, baud, parity, bits, flow);
+}
+
+static struct console vt8500_console = {
+       .name = "ttyWMT",
+       .write = vt8500_console_write,
+       .device = uart_console_device,
+       .setup = vt8500_console_setup,
+       .flags = CON_PRINTBUFFER,
+       .index = -1,
+       .data = &vt8500_uart_driver,
+};
+
+#define VT8500_CONSOLE (&vt8500_console)
+
+#else
+#define VT8500_CONSOLE NULL
+#endif
+
+static struct uart_ops vt8500_uart_pops = {
+       .tx_empty       = vt8500_tx_empty,
+       .set_mctrl      = vt8500_set_mctrl,
+       .get_mctrl      = vt8500_get_mctrl,
+       .stop_tx        = vt8500_stop_tx,
+       .start_tx       = vt8500_start_tx,
+       .stop_rx        = vt8500_stop_rx,
+       .enable_ms      = vt8500_enable_ms,
+       .break_ctl      = vt8500_break_ctl,
+       .startup        = vt8500_startup,
+       .shutdown       = vt8500_shutdown,
+       .set_termios    = vt8500_set_termios,
+       .type           = vt8500_type,
+       .release_port   = vt8500_release_port,
+       .request_port   = vt8500_request_port,
+       .config_port    = vt8500_config_port,
+       .verify_port    = vt8500_verify_port,
+};
+
+static struct uart_driver vt8500_uart_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "vt8500_serial",
+       .dev_name       = "ttyWMT",
+       .nr             = 6,
+       .cons           = VT8500_CONSOLE,
+};
+
+static int __init vt8500_serial_probe(struct platform_device *pdev)
+{
+       struct vt8500_port *vt8500_port;
+       struct resource *mmres, *irqres;
+       int ret;
+
+       mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!mmres || !irqres)
+               return -ENODEV;
+
+       vt8500_port = kzalloc(sizeof(struct vt8500_port), GFP_KERNEL);
+       if (!vt8500_port)
+               return -ENOMEM;
+
+       vt8500_port->uart.type = PORT_VT8500;
+       vt8500_port->uart.iotype = UPIO_MEM;
+       vt8500_port->uart.mapbase = mmres->start;
+       vt8500_port->uart.irq = irqres->start;
+       vt8500_port->uart.fifosize = 16;
+       vt8500_port->uart.ops = &vt8500_uart_pops;
+       vt8500_port->uart.line = pdev->id;
+       vt8500_port->uart.dev = &pdev->dev;
+       vt8500_port->uart.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
+       vt8500_port->uart.uartclk = 24000000;
+
+       snprintf(vt8500_port->name, sizeof(vt8500_port->name),
+                "VT8500 UART%d", pdev->id);
+
+       vt8500_port->uart.membase = ioremap(mmres->start,
+                                           mmres->end - mmres->start + 1);
+       if (!vt8500_port->uart.membase) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       vt8500_uart_ports[pdev->id] = vt8500_port;
+
+       uart_add_one_port(&vt8500_uart_driver, &vt8500_port->uart);
+
+       platform_set_drvdata(pdev, vt8500_port);
+
+       return 0;
+
+err:
+       kfree(vt8500_port);
+       return ret;
+}
+
+static int __devexit vt8500_serial_remove(struct platform_device *pdev)
+{
+       struct vt8500_port *vt8500_port = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+       uart_remove_one_port(&vt8500_uart_driver, &vt8500_port->uart);
+       kfree(vt8500_port);
+
+       return 0;
+}
+
+static struct platform_driver vt8500_platform_driver = {
+       .probe  = vt8500_serial_probe,
+       .remove = vt8500_serial_remove,
+       .driver = {
+               .name = "vt8500_serial",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init vt8500_serial_init(void)
+{
+       int ret;
+
+       ret = uart_register_driver(&vt8500_uart_driver);
+       if (unlikely(ret))
+               return ret;
+
+       ret = platform_driver_register(&vt8500_platform_driver);
+
+       if (unlikely(ret))
+               uart_unregister_driver(&vt8500_uart_driver);
+
+       return ret;
+}
+
+static void __exit vt8500_serial_exit(void)
+{
+#ifdef CONFIG_SERIAL_VT8500_CONSOLE
+       unregister_console(&vt8500_console);
+#endif
+       platform_driver_unregister(&vt8500_platform_driver);
+       uart_unregister_driver(&vt8500_uart_driver);
+}
+
+module_init(vt8500_serial_init);
+module_exit(vt8500_serial_exit);
+
+MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>");
+MODULE_DESCRIPTION("Driver for vt8500 serial device");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/zs.c b/drivers/tty/serial/zs.c
new file mode 100644 (file)
index 0000000..1a7fd3e
--- /dev/null
@@ -0,0 +1,1304 @@
+/*
+ * zs.c: Serial port driver for IOASIC DECstations.
+ *
+ * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
+ * Derived from drivers/macintosh/macserial.c by Harald Koerfgen.
+ *
+ * DECstation changes
+ * Copyright (C) 1998-2000 Harald Koerfgen
+ * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007  Maciej W. Rozycki
+ *
+ * For the rest of the code the original Copyright applies:
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *
+ *
+ * Note: for IOASIC systems the wiring is as follows:
+ *
+ * mouse/keyboard:
+ * DIN-7 MJ-4  signal        SCC
+ * 2     1     TxD       <-  A.TxD
+ * 3     4     RxD       ->  A.RxD
+ *
+ * EIA-232/EIA-423:
+ * DB-25 MMJ-6 signal        SCC
+ * 2     2     TxD       <-  B.TxD
+ * 3     5     RxD       ->  B.RxD
+ * 4           RTS       <- ~A.RTS
+ * 5           CTS       -> ~B.CTS
+ * 6     6     DSR       -> ~A.SYNC
+ * 8           CD        -> ~B.DCD
+ * 12          DSRS(DCE) -> ~A.CTS  (*)
+ * 15          TxC       ->  B.TxC
+ * 17          RxC       ->  B.RxC
+ * 20    1     DTR       <- ~A.DTR
+ * 22          RI        -> ~A.DCD
+ * 23          DSRS(DTE) <- ~B.RTS
+ *
+ * (*) EIA-232 defines the signal at this pin to be SCD, while DSRS(DCE)
+ *     is shared with DSRS(DTE) at pin 23.
+ *
+ * As you can immediately notice the wiring of the RTS, DTR and DSR signals
+ * is a bit odd.  This makes the handling of port B unnecessarily
+ * complicated and prevents the use of some automatic modes of operation.
+ */
+
+#if defined(CONFIG_SERIAL_ZS_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/bug.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/irqflags.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/spinlock.h>
+#include <linux/sysrq.h>
+#include <linux/tty.h>
+#include <linux/types.h>
+
+#include <asm/atomic.h>
+#include <asm/system.h>
+
+#include <asm/dec/interrupts.h>
+#include <asm/dec/ioasic_addrs.h>
+#include <asm/dec/system.h>
+
+#include "zs.h"
+
+
+MODULE_AUTHOR("Maciej W. Rozycki <macro@linux-mips.org>");
+MODULE_DESCRIPTION("DECstation Z85C30 serial driver");
+MODULE_LICENSE("GPL");
+
+
+static char zs_name[] __initdata = "DECstation Z85C30 serial driver version ";
+static char zs_version[] __initdata = "0.10";
+
+/*
+ * It would be nice to dynamically allocate everything that
+ * depends on ZS_NUM_SCCS, so we could support any number of
+ * Z85C30s, but for now...
+ */
+#define ZS_NUM_SCCS    2               /* Max # of ZS chips supported.  */
+#define ZS_NUM_CHAN    2               /* 2 channels per chip.  */
+#define ZS_CHAN_A      0               /* Index of the channel A.  */
+#define ZS_CHAN_B      1               /* Index of the channel B.  */
+#define ZS_CHAN_IO_SIZE 8              /* IOMEM space size.  */
+#define ZS_CHAN_IO_STRIDE 4            /* Register alignment.  */
+#define ZS_CHAN_IO_OFFSET 1            /* The SCC resides on the high byte
+                                          of the 16-bit IOBUS.  */
+#define ZS_CLOCK        7372800        /* Z85C30 PCLK input clock rate.  */
+
+#define to_zport(uport) container_of(uport, struct zs_port, port)
+
+struct zs_parms {
+       resource_size_t scc[ZS_NUM_SCCS];
+       int irq[ZS_NUM_SCCS];
+};
+
+static struct zs_scc zs_sccs[ZS_NUM_SCCS];
+
+static u8 zs_init_regs[ZS_NUM_REGS] __initdata = {
+       0,                              /* write 0 */
+       PAR_SPEC,                       /* write 1 */
+       0,                              /* write 2 */
+       0,                              /* write 3 */
+       X16CLK | SB1,                   /* write 4 */
+       0,                              /* write 5 */
+       0, 0, 0,                        /* write 6, 7, 8 */
+       MIE | DLC | NV,                 /* write 9 */
+       NRZ,                            /* write 10 */
+       TCBR | RCBR,                    /* write 11 */
+       0, 0,                           /* BRG time constant, write 12 + 13 */
+       BRSRC | BRENABL,                /* write 14 */
+       0,                              /* write 15 */
+};
+
+/*
+ * Debugging.
+ */
+#undef ZS_DEBUG_REGS
+
+
+/*
+ * Reading and writing Z85C30 registers.
+ */
+static void recovery_delay(void)
+{
+       udelay(2);
+}
+
+static u8 read_zsreg(struct zs_port *zport, int reg)
+{
+       void __iomem *control = zport->port.membase + ZS_CHAN_IO_OFFSET;
+       u8 retval;
+
+       if (reg != 0) {
+               writeb(reg & 0xf, control);
+               fast_iob();
+               recovery_delay();
+       }
+       retval = readb(control);
+       recovery_delay();
+       return retval;
+}
+
+static void write_zsreg(struct zs_port *zport, int reg, u8 value)
+{
+       void __iomem *control = zport->port.membase + ZS_CHAN_IO_OFFSET;
+
+       if (reg != 0) {
+               writeb(reg & 0xf, control);
+               fast_iob(); recovery_delay();
+       }
+       writeb(value, control);
+       fast_iob();
+       recovery_delay();
+       return;
+}
+
+static u8 read_zsdata(struct zs_port *zport)
+{
+       void __iomem *data = zport->port.membase +
+                            ZS_CHAN_IO_STRIDE + ZS_CHAN_IO_OFFSET;
+       u8 retval;
+
+       retval = readb(data);
+       recovery_delay();
+       return retval;
+}
+
+static void write_zsdata(struct zs_port *zport, u8 value)
+{
+       void __iomem *data = zport->port.membase +
+                            ZS_CHAN_IO_STRIDE + ZS_CHAN_IO_OFFSET;
+
+       writeb(value, data);
+       fast_iob();
+       recovery_delay();
+       return;
+}
+
+#ifdef ZS_DEBUG_REGS
+void zs_dump(void)
+{
+       struct zs_port *zport;
+       int i, j;
+
+       for (i = 0; i < ZS_NUM_SCCS * ZS_NUM_CHAN; i++) {
+               zport = &zs_sccs[i / ZS_NUM_CHAN].zport[i % ZS_NUM_CHAN];
+
+               if (!zport->scc)
+                       continue;
+
+               for (j = 0; j < 16; j++)
+                       printk("W%-2d = 0x%02x\t", j, zport->regs[j]);
+               printk("\n");
+               for (j = 0; j < 16; j++)
+                       printk("R%-2d = 0x%02x\t", j, read_zsreg(zport, j));
+               printk("\n\n");
+       }
+}
+#endif
+
+
+static void zs_spin_lock_cond_irq(spinlock_t *lock, int irq)
+{
+       if (irq)
+               spin_lock_irq(lock);
+       else
+               spin_lock(lock);
+}
+
+static void zs_spin_unlock_cond_irq(spinlock_t *lock, int irq)
+{
+       if (irq)
+               spin_unlock_irq(lock);
+       else
+               spin_unlock(lock);
+}
+
+static int zs_receive_drain(struct zs_port *zport)
+{
+       int loops = 10000;
+
+       while ((read_zsreg(zport, R0) & Rx_CH_AV) && --loops)
+               read_zsdata(zport);
+       return loops;
+}
+
+static int zs_transmit_drain(struct zs_port *zport, int irq)
+{
+       struct zs_scc *scc = zport->scc;
+       int loops = 10000;
+
+       while (!(read_zsreg(zport, R0) & Tx_BUF_EMP) && --loops) {
+               zs_spin_unlock_cond_irq(&scc->zlock, irq);
+               udelay(2);
+               zs_spin_lock_cond_irq(&scc->zlock, irq);
+       }
+       return loops;
+}
+
+static int zs_line_drain(struct zs_port *zport, int irq)
+{
+       struct zs_scc *scc = zport->scc;
+       int loops = 10000;
+
+       while (!(read_zsreg(zport, R1) & ALL_SNT) && --loops) {
+               zs_spin_unlock_cond_irq(&scc->zlock, irq);
+               udelay(2);
+               zs_spin_lock_cond_irq(&scc->zlock, irq);
+       }
+       return loops;
+}
+
+
+static void load_zsregs(struct zs_port *zport, u8 *regs, int irq)
+{
+       /* Let the current transmission finish.  */
+       zs_line_drain(zport, irq);
+       /* Load 'em up.  */
+       write_zsreg(zport, R3, regs[3] & ~RxENABLE);
+       write_zsreg(zport, R5, regs[5] & ~TxENAB);
+       write_zsreg(zport, R4, regs[4]);
+       write_zsreg(zport, R9, regs[9]);
+       write_zsreg(zport, R1, regs[1]);
+       write_zsreg(zport, R2, regs[2]);
+       write_zsreg(zport, R10, regs[10]);
+       write_zsreg(zport, R14, regs[14] & ~BRENABL);
+       write_zsreg(zport, R11, regs[11]);
+       write_zsreg(zport, R12, regs[12]);
+       write_zsreg(zport, R13, regs[13]);
+       write_zsreg(zport, R14, regs[14]);
+       write_zsreg(zport, R15, regs[15]);
+       if (regs[3] & RxENABLE)
+               write_zsreg(zport, R3, regs[3]);
+       if (regs[5] & TxENAB)
+               write_zsreg(zport, R5, regs[5]);
+       return;
+}
+
+
+/*
+ * Status handling routines.
+ */
+
+/*
+ * zs_tx_empty() -- get the transmitter empty status
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ *         is emptied.  On bus types like RS485, the transmitter must
+ *         release the bus after transmitting.  This must be done when
+ *         the transmit shift register is empty, not be done when the
+ *         transmit holding register is empty.  This functionality
+ *         allows an RS485 driver to be written in user space.
+ */
+static unsigned int zs_tx_empty(struct uart_port *uport)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       unsigned long flags;
+       u8 status;
+
+       spin_lock_irqsave(&scc->zlock, flags);
+       status = read_zsreg(zport, R1);
+       spin_unlock_irqrestore(&scc->zlock, flags);
+
+       return status & ALL_SNT ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int zs_raw_get_ab_mctrl(struct zs_port *zport_a,
+                                       struct zs_port *zport_b)
+{
+       u8 status_a, status_b;
+       unsigned int mctrl;
+
+       status_a = read_zsreg(zport_a, R0);
+       status_b = read_zsreg(zport_b, R0);
+
+       mctrl = ((status_b & CTS) ? TIOCM_CTS : 0) |
+               ((status_b & DCD) ? TIOCM_CAR : 0) |
+               ((status_a & DCD) ? TIOCM_RNG : 0) |
+               ((status_a & SYNC_HUNT) ? TIOCM_DSR : 0);
+
+       return mctrl;
+}
+
+static unsigned int zs_raw_get_mctrl(struct zs_port *zport)
+{
+       struct zs_port *zport_a = &zport->scc->zport[ZS_CHAN_A];
+
+       return zport != zport_a ? zs_raw_get_ab_mctrl(zport_a, zport) : 0;
+}
+
+static unsigned int zs_raw_xor_mctrl(struct zs_port *zport)
+{
+       struct zs_port *zport_a = &zport->scc->zport[ZS_CHAN_A];
+       unsigned int mmask, mctrl, delta;
+       u8 mask_a, mask_b;
+
+       if (zport == zport_a)
+               return 0;
+
+       mask_a = zport_a->regs[15];
+       mask_b = zport->regs[15];
+
+       mmask = ((mask_b & CTSIE) ? TIOCM_CTS : 0) |
+               ((mask_b & DCDIE) ? TIOCM_CAR : 0) |
+               ((mask_a & DCDIE) ? TIOCM_RNG : 0) |
+               ((mask_a & SYNCIE) ? TIOCM_DSR : 0);
+
+       mctrl = zport->mctrl;
+       if (mmask) {
+               mctrl &= ~mmask;
+               mctrl |= zs_raw_get_ab_mctrl(zport_a, zport) & mmask;
+       }
+
+       delta = mctrl ^ zport->mctrl;
+       if (delta)
+               zport->mctrl = mctrl;
+
+       return delta;
+}
+
+static unsigned int zs_get_mctrl(struct uart_port *uport)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       unsigned int mctrl;
+
+       spin_lock(&scc->zlock);
+       mctrl = zs_raw_get_mctrl(zport);
+       spin_unlock(&scc->zlock);
+
+       return mctrl;
+}
+
+static void zs_set_mctrl(struct uart_port *uport, unsigned int mctrl)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+       u8 oldloop, newloop;
+
+       spin_lock(&scc->zlock);
+       if (zport != zport_a) {
+               if (mctrl & TIOCM_DTR)
+                       zport_a->regs[5] |= DTR;
+               else
+                       zport_a->regs[5] &= ~DTR;
+               if (mctrl & TIOCM_RTS)
+                       zport_a->regs[5] |= RTS;
+               else
+                       zport_a->regs[5] &= ~RTS;
+               write_zsreg(zport_a, R5, zport_a->regs[5]);
+       }
+
+       /* Rarely modified, so don't poke at hardware unless necessary. */
+       oldloop = zport->regs[14];
+       newloop = oldloop;
+       if (mctrl & TIOCM_LOOP)
+               newloop |= LOOPBAK;
+       else
+               newloop &= ~LOOPBAK;
+       if (newloop != oldloop) {
+               zport->regs[14] = newloop;
+               write_zsreg(zport, R14, zport->regs[14]);
+       }
+       spin_unlock(&scc->zlock);
+}
+
+static void zs_raw_stop_tx(struct zs_port *zport)
+{
+       write_zsreg(zport, R0, RES_Tx_P);
+       zport->tx_stopped = 1;
+}
+
+static void zs_stop_tx(struct uart_port *uport)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+
+       spin_lock(&scc->zlock);
+       zs_raw_stop_tx(zport);
+       spin_unlock(&scc->zlock);
+}
+
+static void zs_raw_transmit_chars(struct zs_port *);
+
+static void zs_start_tx(struct uart_port *uport)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+
+       spin_lock(&scc->zlock);
+       if (zport->tx_stopped) {
+               zs_transmit_drain(zport, 0);
+               zport->tx_stopped = 0;
+               zs_raw_transmit_chars(zport);
+       }
+       spin_unlock(&scc->zlock);
+}
+
+static void zs_stop_rx(struct uart_port *uport)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+
+       spin_lock(&scc->zlock);
+       zport->regs[15] &= ~BRKIE;
+       zport->regs[1] &= ~(RxINT_MASK | TxINT_ENAB);
+       zport->regs[1] |= RxINT_DISAB;
+
+       if (zport != zport_a) {
+               /* A-side DCD tracks RI and SYNC tracks DSR.  */
+               zport_a->regs[15] &= ~(DCDIE | SYNCIE);
+               write_zsreg(zport_a, R15, zport_a->regs[15]);
+               if (!(zport_a->regs[15] & BRKIE)) {
+                       zport_a->regs[1] &= ~EXT_INT_ENAB;
+                       write_zsreg(zport_a, R1, zport_a->regs[1]);
+               }
+
+               /* This-side DCD tracks DCD and CTS tracks CTS.  */
+               zport->regs[15] &= ~(DCDIE | CTSIE);
+               zport->regs[1] &= ~EXT_INT_ENAB;
+       } else {
+               /* DCD tracks RI and SYNC tracks DSR for the B side.  */
+               if (!(zport->regs[15] & (DCDIE | SYNCIE)))
+                       zport->regs[1] &= ~EXT_INT_ENAB;
+       }
+
+       write_zsreg(zport, R15, zport->regs[15]);
+       write_zsreg(zport, R1, zport->regs[1]);
+       spin_unlock(&scc->zlock);
+}
+
+static void zs_enable_ms(struct uart_port *uport)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+
+       if (zport == zport_a)
+               return;
+
+       spin_lock(&scc->zlock);
+
+       /* Clear Ext interrupts if not being handled already.  */
+       if (!(zport_a->regs[1] & EXT_INT_ENAB))
+               write_zsreg(zport_a, R0, RES_EXT_INT);
+
+       /* A-side DCD tracks RI and SYNC tracks DSR.  */
+       zport_a->regs[1] |= EXT_INT_ENAB;
+       zport_a->regs[15] |= DCDIE | SYNCIE;
+
+       /* This-side DCD tracks DCD and CTS tracks CTS.  */
+       zport->regs[15] |= DCDIE | CTSIE;
+
+       zs_raw_xor_mctrl(zport);
+
+       write_zsreg(zport_a, R1, zport_a->regs[1]);
+       write_zsreg(zport_a, R15, zport_a->regs[15]);
+       write_zsreg(zport, R15, zport->regs[15]);
+       spin_unlock(&scc->zlock);
+}
+
+static void zs_break_ctl(struct uart_port *uport, int break_state)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&scc->zlock, flags);
+       if (break_state == -1)
+               zport->regs[5] |= SND_BRK;
+       else
+               zport->regs[5] &= ~SND_BRK;
+       write_zsreg(zport, R5, zport->regs[5]);
+       spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+
+/*
+ * Interrupt handling routines.
+ */
+#define Rx_BRK 0x0100                  /* BREAK event software flag.  */
+#define Rx_SYS 0x0200                  /* SysRq event software flag.  */
+
+static void zs_receive_chars(struct zs_port *zport)
+{
+       struct uart_port *uport = &zport->port;
+       struct zs_scc *scc = zport->scc;
+       struct uart_icount *icount;
+       unsigned int avail, status, ch, flag;
+       int count;
+
+       for (count = 16; count; count--) {
+               spin_lock(&scc->zlock);
+               avail = read_zsreg(zport, R0) & Rx_CH_AV;
+               spin_unlock(&scc->zlock);
+               if (!avail)
+                       break;
+
+               spin_lock(&scc->zlock);
+               status = read_zsreg(zport, R1) & (Rx_OVR | FRM_ERR | PAR_ERR);
+               ch = read_zsdata(zport);
+               spin_unlock(&scc->zlock);
+
+               flag = TTY_NORMAL;
+
+               icount = &uport->icount;
+               icount->rx++;
+
+               /* Handle the null char got when BREAK is removed.  */
+               if (!ch)
+                       status |= zport->tty_break;
+               if (unlikely(status &
+                            (Rx_OVR | FRM_ERR | PAR_ERR | Rx_SYS | Rx_BRK))) {
+                       zport->tty_break = 0;
+
+                       /* Reset the error indication.  */
+                       if (status & (Rx_OVR | FRM_ERR | PAR_ERR)) {
+                               spin_lock(&scc->zlock);
+                               write_zsreg(zport, R0, ERR_RES);
+                               spin_unlock(&scc->zlock);
+                       }
+
+                       if (status & (Rx_SYS | Rx_BRK)) {
+                               icount->brk++;
+                               /* SysRq discards the null char.  */
+                               if (status & Rx_SYS)
+                                       continue;
+                       } else if (status & FRM_ERR)
+                               icount->frame++;
+                       else if (status & PAR_ERR)
+                               icount->parity++;
+                       if (status & Rx_OVR)
+                               icount->overrun++;
+
+                       status &= uport->read_status_mask;
+                       if (status & Rx_BRK)
+                               flag = TTY_BREAK;
+                       else if (status & FRM_ERR)
+                               flag = TTY_FRAME;
+                       else if (status & PAR_ERR)
+                               flag = TTY_PARITY;
+               }
+
+               if (uart_handle_sysrq_char(uport, ch))
+                       continue;
+
+               uart_insert_char(uport, status, Rx_OVR, ch, flag);
+       }
+
+       tty_flip_buffer_push(uport->state->port.tty);
+}
+
+static void zs_raw_transmit_chars(struct zs_port *zport)
+{
+       struct circ_buf *xmit = &zport->port.state->xmit;
+
+       /* XON/XOFF chars.  */
+       if (zport->port.x_char) {
+               write_zsdata(zport, zport->port.x_char);
+               zport->port.icount.tx++;
+               zport->port.x_char = 0;
+               return;
+       }
+
+       /* If nothing to do or stopped or hardware stopped.  */
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&zport->port)) {
+               zs_raw_stop_tx(zport);
+               return;
+       }
+
+       /* Send char.  */
+       write_zsdata(zport, xmit->buf[xmit->tail]);
+       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+       zport->port.icount.tx++;
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&zport->port);
+
+       /* Are we are done?  */
+       if (uart_circ_empty(xmit))
+               zs_raw_stop_tx(zport);
+}
+
+static void zs_transmit_chars(struct zs_port *zport)
+{
+       struct zs_scc *scc = zport->scc;
+
+       spin_lock(&scc->zlock);
+       zs_raw_transmit_chars(zport);
+       spin_unlock(&scc->zlock);
+}
+
+static void zs_status_handle(struct zs_port *zport, struct zs_port *zport_a)
+{
+       struct uart_port *uport = &zport->port;
+       struct zs_scc *scc = zport->scc;
+       unsigned int delta;
+       u8 status, brk;
+
+       spin_lock(&scc->zlock);
+
+       /* Get status from Read Register 0.  */
+       status = read_zsreg(zport, R0);
+
+       if (zport->regs[15] & BRKIE) {
+               brk = status & BRK_ABRT;
+               if (brk && !zport->brk) {
+                       spin_unlock(&scc->zlock);
+                       if (uart_handle_break(uport))
+                               zport->tty_break = Rx_SYS;
+                       else
+                               zport->tty_break = Rx_BRK;
+                       spin_lock(&scc->zlock);
+               }
+               zport->brk = brk;
+       }
+
+       if (zport != zport_a) {
+               delta = zs_raw_xor_mctrl(zport);
+               spin_unlock(&scc->zlock);
+
+               if (delta & TIOCM_CTS)
+                       uart_handle_cts_change(uport,
+                                              zport->mctrl & TIOCM_CTS);
+               if (delta & TIOCM_CAR)
+                       uart_handle_dcd_change(uport,
+                                              zport->mctrl & TIOCM_CAR);
+               if (delta & TIOCM_RNG)
+                       uport->icount.dsr++;
+               if (delta & TIOCM_DSR)
+                       uport->icount.rng++;
+
+               if (delta)
+                       wake_up_interruptible(&uport->state->port.delta_msr_wait);
+
+               spin_lock(&scc->zlock);
+       }
+
+       /* Clear the status condition...  */
+       write_zsreg(zport, R0, RES_EXT_INT);
+
+       spin_unlock(&scc->zlock);
+}
+
+/*
+ * This is the Z85C30 driver's generic interrupt routine.
+ */
+static irqreturn_t zs_interrupt(int irq, void *dev_id)
+{
+       struct zs_scc *scc = dev_id;
+       struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+       struct zs_port *zport_b = &scc->zport[ZS_CHAN_B];
+       irqreturn_t status = IRQ_NONE;
+       u8 zs_intreg;
+       int count;
+
+       /*
+        * NOTE: The read register 3, which holds the irq status,
+        *       does so for both channels on each chip.  Although
+        *       the status value itself must be read from the A
+        *       channel and is only valid when read from channel A.
+        *       Yes... broken hardware...
+        */
+       for (count = 16; count; count--) {
+               spin_lock(&scc->zlock);
+               zs_intreg = read_zsreg(zport_a, R3);
+               spin_unlock(&scc->zlock);
+               if (!zs_intreg)
+                       break;
+
+               /*
+                * We do not like losing characters, so we prioritise
+                * interrupt sources a little bit differently than
+                * the SCC would, was it allowed to.
+                */
+               if (zs_intreg & CHBRxIP)
+                       zs_receive_chars(zport_b);
+               if (zs_intreg & CHARxIP)
+                       zs_receive_chars(zport_a);
+               if (zs_intreg & CHBEXT)
+                       zs_status_handle(zport_b, zport_a);
+               if (zs_intreg & CHAEXT)
+                       zs_status_handle(zport_a, zport_a);
+               if (zs_intreg & CHBTxIP)
+                       zs_transmit_chars(zport_b);
+               if (zs_intreg & CHATxIP)
+                       zs_transmit_chars(zport_a);
+
+               status = IRQ_HANDLED;
+       }
+
+       return status;
+}
+
+
+/*
+ * Finally, routines used to initialize the serial port.
+ */
+static int zs_startup(struct uart_port *uport)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       unsigned long flags;
+       int irq_guard;
+       int ret;
+
+       irq_guard = atomic_add_return(1, &scc->irq_guard);
+       if (irq_guard == 1) {
+               ret = request_irq(zport->port.irq, zs_interrupt,
+                                 IRQF_SHARED, "scc", scc);
+               if (ret) {
+                       atomic_add(-1, &scc->irq_guard);
+                       printk(KERN_ERR "zs: can't get irq %d\n",
+                              zport->port.irq);
+                       return ret;
+               }
+       }
+
+       spin_lock_irqsave(&scc->zlock, flags);
+
+       /* Clear the receive FIFO.  */
+       zs_receive_drain(zport);
+
+       /* Clear the interrupt registers.  */
+       write_zsreg(zport, R0, ERR_RES);
+       write_zsreg(zport, R0, RES_Tx_P);
+       /* But Ext only if not being handled already.  */
+       if (!(zport->regs[1] & EXT_INT_ENAB))
+               write_zsreg(zport, R0, RES_EXT_INT);
+
+       /* Finally, enable sequencing and interrupts.  */
+       zport->regs[1] &= ~RxINT_MASK;
+       zport->regs[1] |= RxINT_ALL | TxINT_ENAB | EXT_INT_ENAB;
+       zport->regs[3] |= RxENABLE;
+       zport->regs[15] |= BRKIE;
+       write_zsreg(zport, R1, zport->regs[1]);
+       write_zsreg(zport, R3, zport->regs[3]);
+       write_zsreg(zport, R5, zport->regs[5]);
+       write_zsreg(zport, R15, zport->regs[15]);
+
+       /* Record the current state of RR0.  */
+       zport->mctrl = zs_raw_get_mctrl(zport);
+       zport->brk = read_zsreg(zport, R0) & BRK_ABRT;
+
+       zport->tx_stopped = 1;
+
+       spin_unlock_irqrestore(&scc->zlock, flags);
+
+       return 0;
+}
+
+static void zs_shutdown(struct uart_port *uport)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       unsigned long flags;
+       int irq_guard;
+
+       spin_lock_irqsave(&scc->zlock, flags);
+
+       zport->regs[3] &= ~RxENABLE;
+       write_zsreg(zport, R5, zport->regs[5]);
+       write_zsreg(zport, R3, zport->regs[3]);
+
+       spin_unlock_irqrestore(&scc->zlock, flags);
+
+       irq_guard = atomic_add_return(-1, &scc->irq_guard);
+       if (!irq_guard)
+               free_irq(zport->port.irq, scc);
+}
+
+
+static void zs_reset(struct zs_port *zport)
+{
+       struct zs_scc *scc = zport->scc;
+       int irq;
+       unsigned long flags;
+
+       spin_lock_irqsave(&scc->zlock, flags);
+       irq = !irqs_disabled_flags(flags);
+       if (!scc->initialised) {
+               /* Reset the pointer first, just in case...  */
+               read_zsreg(zport, R0);
+               /* And let the current transmission finish.  */
+               zs_line_drain(zport, irq);
+               write_zsreg(zport, R9, FHWRES);
+               udelay(10);
+               write_zsreg(zport, R9, 0);
+               scc->initialised = 1;
+       }
+       load_zsregs(zport, zport->regs, irq);
+       spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+static void zs_set_termios(struct uart_port *uport, struct ktermios *termios,
+                          struct ktermios *old_termios)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+       int irq;
+       unsigned int baud, brg;
+       unsigned long flags;
+
+       spin_lock_irqsave(&scc->zlock, flags);
+       irq = !irqs_disabled_flags(flags);
+
+       /* Byte size.  */
+       zport->regs[3] &= ~RxNBITS_MASK;
+       zport->regs[5] &= ~TxNBITS_MASK;
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               zport->regs[3] |= Rx5;
+               zport->regs[5] |= Tx5;
+               break;
+       case CS6:
+               zport->regs[3] |= Rx6;
+               zport->regs[5] |= Tx6;
+               break;
+       case CS7:
+               zport->regs[3] |= Rx7;
+               zport->regs[5] |= Tx7;
+               break;
+       case CS8:
+       default:
+               zport->regs[3] |= Rx8;
+               zport->regs[5] |= Tx8;
+               break;
+       }
+
+       /* Parity and stop bits.  */
+       zport->regs[4] &= ~(XCLK_MASK | SB_MASK | PAR_ENA | PAR_EVEN);
+       if (termios->c_cflag & CSTOPB)
+               zport->regs[4] |= SB2;
+       else
+               zport->regs[4] |= SB1;
+       if (termios->c_cflag & PARENB)
+               zport->regs[4] |= PAR_ENA;
+       if (!(termios->c_cflag & PARODD))
+               zport->regs[4] |= PAR_EVEN;
+       switch (zport->clk_mode) {
+       case 64:
+               zport->regs[4] |= X64CLK;
+               break;
+       case 32:
+               zport->regs[4] |= X32CLK;
+               break;
+       case 16:
+               zport->regs[4] |= X16CLK;
+               break;
+       case 1:
+               zport->regs[4] |= X1CLK;
+               break;
+       default:
+               BUG();
+       }
+
+       baud = uart_get_baud_rate(uport, termios, old_termios, 0,
+                                 uport->uartclk / zport->clk_mode / 4);
+
+       brg = ZS_BPS_TO_BRG(baud, uport->uartclk / zport->clk_mode);
+       zport->regs[12] = brg & 0xff;
+       zport->regs[13] = (brg >> 8) & 0xff;
+
+       uart_update_timeout(uport, termios->c_cflag, baud);
+
+       uport->read_status_mask = Rx_OVR;
+       if (termios->c_iflag & INPCK)
+               uport->read_status_mask |= FRM_ERR | PAR_ERR;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               uport->read_status_mask |= Rx_BRK;
+
+       uport->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               uport->ignore_status_mask |= FRM_ERR | PAR_ERR;
+       if (termios->c_iflag & IGNBRK) {
+               uport->ignore_status_mask |= Rx_BRK;
+               if (termios->c_iflag & IGNPAR)
+                       uport->ignore_status_mask |= Rx_OVR;
+       }
+
+       if (termios->c_cflag & CREAD)
+               zport->regs[3] |= RxENABLE;
+       else
+               zport->regs[3] &= ~RxENABLE;
+
+       if (zport != zport_a) {
+               if (!(termios->c_cflag & CLOCAL)) {
+                       zport->regs[15] |= DCDIE;
+               } else
+                       zport->regs[15] &= ~DCDIE;
+               if (termios->c_cflag & CRTSCTS) {
+                       zport->regs[15] |= CTSIE;
+               } else
+                       zport->regs[15] &= ~CTSIE;
+               zs_raw_xor_mctrl(zport);
+       }
+
+       /* Load up the new values.  */
+       load_zsregs(zport, zport->regs, irq);
+
+       spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+/*
+ * Hack alert!
+ * Required solely so that the initial PROM-based console
+ * works undisturbed in parallel with this one.
+ */
+static void zs_pm(struct uart_port *uport, unsigned int state,
+                 unsigned int oldstate)
+{
+       struct zs_port *zport = to_zport(uport);
+
+       if (state < 3)
+               zport->regs[5] |= TxENAB;
+       else
+               zport->regs[5] &= ~TxENAB;
+       write_zsreg(zport, R5, zport->regs[5]);
+}
+
+
+static const char *zs_type(struct uart_port *uport)
+{
+       return "Z85C30 SCC";
+}
+
+static void zs_release_port(struct uart_port *uport)
+{
+       iounmap(uport->membase);
+       uport->membase = 0;
+       release_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE);
+}
+
+static int zs_map_port(struct uart_port *uport)
+{
+       if (!uport->membase)
+               uport->membase = ioremap_nocache(uport->mapbase,
+                                                ZS_CHAN_IO_SIZE);
+       if (!uport->membase) {
+               printk(KERN_ERR "zs: Cannot map MMIO\n");
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static int zs_request_port(struct uart_port *uport)
+{
+       int ret;
+
+       if (!request_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE, "scc")) {
+               printk(KERN_ERR "zs: Unable to reserve MMIO resource\n");
+               return -EBUSY;
+       }
+       ret = zs_map_port(uport);
+       if (ret) {
+               release_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE);
+               return ret;
+       }
+       return 0;
+}
+
+static void zs_config_port(struct uart_port *uport, int flags)
+{
+       struct zs_port *zport = to_zport(uport);
+
+       if (flags & UART_CONFIG_TYPE) {
+               if (zs_request_port(uport))
+                       return;
+
+               uport->type = PORT_ZS;
+
+               zs_reset(zport);
+       }
+}
+
+static int zs_verify_port(struct uart_port *uport, struct serial_struct *ser)
+{
+       struct zs_port *zport = to_zport(uport);
+       int ret = 0;
+
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_ZS)
+               ret = -EINVAL;
+       if (ser->irq != uport->irq)
+               ret = -EINVAL;
+       if (ser->baud_base != uport->uartclk / zport->clk_mode / 4)
+               ret = -EINVAL;
+       return ret;
+}
+
+
+static struct uart_ops zs_ops = {
+       .tx_empty       = zs_tx_empty,
+       .set_mctrl      = zs_set_mctrl,
+       .get_mctrl      = zs_get_mctrl,
+       .stop_tx        = zs_stop_tx,
+       .start_tx       = zs_start_tx,
+       .stop_rx        = zs_stop_rx,
+       .enable_ms      = zs_enable_ms,
+       .break_ctl      = zs_break_ctl,
+       .startup        = zs_startup,
+       .shutdown       = zs_shutdown,
+       .set_termios    = zs_set_termios,
+       .pm             = zs_pm,
+       .type           = zs_type,
+       .release_port   = zs_release_port,
+       .request_port   = zs_request_port,
+       .config_port    = zs_config_port,
+       .verify_port    = zs_verify_port,
+};
+
+/*
+ * Initialize Z85C30 port structures.
+ */
+static int __init zs_probe_sccs(void)
+{
+       static int probed;
+       struct zs_parms zs_parms;
+       int chip, side, irq;
+       int n_chips = 0;
+       int i;
+
+       if (probed)
+               return 0;
+
+       irq = dec_interrupt[DEC_IRQ_SCC0];
+       if (irq >= 0) {
+               zs_parms.scc[n_chips] = IOASIC_SCC0;
+               zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC0];
+               n_chips++;
+       }
+       irq = dec_interrupt[DEC_IRQ_SCC1];
+       if (irq >= 0) {
+               zs_parms.scc[n_chips] = IOASIC_SCC1;
+               zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC1];
+               n_chips++;
+       }
+       if (!n_chips)
+               return -ENXIO;
+
+       probed = 1;
+
+       for (chip = 0; chip < n_chips; chip++) {
+               spin_lock_init(&zs_sccs[chip].zlock);
+               for (side = 0; side < ZS_NUM_CHAN; side++) {
+                       struct zs_port *zport = &zs_sccs[chip].zport[side];
+                       struct uart_port *uport = &zport->port;
+
+                       zport->scc      = &zs_sccs[chip];
+                       zport->clk_mode = 16;
+
+                       uport->irq      = zs_parms.irq[chip];
+                       uport->uartclk  = ZS_CLOCK;
+                       uport->fifosize = 1;
+                       uport->iotype   = UPIO_MEM;
+                       uport->flags    = UPF_BOOT_AUTOCONF;
+                       uport->ops      = &zs_ops;
+                       uport->line     = chip * ZS_NUM_CHAN + side;
+                       uport->mapbase  = dec_kn_slot_base +
+                                         zs_parms.scc[chip] +
+                                         (side ^ ZS_CHAN_B) * ZS_CHAN_IO_SIZE;
+
+                       for (i = 0; i < ZS_NUM_REGS; i++)
+                               zport->regs[i] = zs_init_regs[i];
+               }
+       }
+
+       return 0;
+}
+
+
+#ifdef CONFIG_SERIAL_ZS_CONSOLE
+static void zs_console_putchar(struct uart_port *uport, int ch)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       int irq;
+       unsigned long flags;
+
+       spin_lock_irqsave(&scc->zlock, flags);
+       irq = !irqs_disabled_flags(flags);
+       if (zs_transmit_drain(zport, irq))
+               write_zsdata(zport, ch);
+       spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+/*
+ * Print a string to the serial port trying not to disturb
+ * any possible real use of the port...
+ */
+static void zs_console_write(struct console *co, const char *s,
+                            unsigned int count)
+{
+       int chip = co->index / ZS_NUM_CHAN, side = co->index % ZS_NUM_CHAN;
+       struct zs_port *zport = &zs_sccs[chip].zport[side];
+       struct zs_scc *scc = zport->scc;
+       unsigned long flags;
+       u8 txint, txenb;
+       int irq;
+
+       /* Disable transmit interrupts and enable the transmitter. */
+       spin_lock_irqsave(&scc->zlock, flags);
+       txint = zport->regs[1];
+       txenb = zport->regs[5];
+       if (txint & TxINT_ENAB) {
+               zport->regs[1] = txint & ~TxINT_ENAB;
+               write_zsreg(zport, R1, zport->regs[1]);
+       }
+       if (!(txenb & TxENAB)) {
+               zport->regs[5] = txenb | TxENAB;
+               write_zsreg(zport, R5, zport->regs[5]);
+       }
+       spin_unlock_irqrestore(&scc->zlock, flags);
+
+       uart_console_write(&zport->port, s, count, zs_console_putchar);
+
+       /* Restore transmit interrupts and the transmitter enable. */
+       spin_lock_irqsave(&scc->zlock, flags);
+       irq = !irqs_disabled_flags(flags);
+       zs_line_drain(zport, irq);
+       if (!(txenb & TxENAB)) {
+               zport->regs[5] &= ~TxENAB;
+               write_zsreg(zport, R5, zport->regs[5]);
+       }
+       if (txint & TxINT_ENAB) {
+               zport->regs[1] |= TxINT_ENAB;
+               write_zsreg(zport, R1, zport->regs[1]);
+       }
+       spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+/*
+ * Setup serial console baud/bits/parity.  We do two things here:
+ * - construct a cflag setting for the first uart_open()
+ * - initialise the serial port
+ * Return non-zero if we didn't find a serial port.
+ */
+static int __init zs_console_setup(struct console *co, char *options)
+{
+       int chip = co->index / ZS_NUM_CHAN, side = co->index % ZS_NUM_CHAN;
+       struct zs_port *zport = &zs_sccs[chip].zport[side];
+       struct uart_port *uport = &zport->port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+       int ret;
+
+       ret = zs_map_port(uport);
+       if (ret)
+               return ret;
+
+       zs_reset(zport);
+       zs_pm(uport, 0, -1);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       return uart_set_options(uport, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver zs_reg;
+static struct console zs_console = {
+       .name   = "ttyS",
+       .write  = zs_console_write,
+       .device = uart_console_device,
+       .setup  = zs_console_setup,
+       .flags  = CON_PRINTBUFFER,
+       .index  = -1,
+       .data   = &zs_reg,
+};
+
+/*
+ *     Register console.
+ */
+static int __init zs_serial_console_init(void)
+{
+       int ret;
+
+       ret = zs_probe_sccs();
+       if (ret)
+               return ret;
+       register_console(&zs_console);
+
+       return 0;
+}
+
+console_initcall(zs_serial_console_init);
+
+#define SERIAL_ZS_CONSOLE      &zs_console
+#else
+#define SERIAL_ZS_CONSOLE      NULL
+#endif /* CONFIG_SERIAL_ZS_CONSOLE */
+
+static struct uart_driver zs_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "serial",
+       .dev_name               = "ttyS",
+       .major                  = TTY_MAJOR,
+       .minor                  = 64,
+       .nr                     = ZS_NUM_SCCS * ZS_NUM_CHAN,
+       .cons                   = SERIAL_ZS_CONSOLE,
+};
+
+/* zs_init inits the driver. */
+static int __init zs_init(void)
+{
+       int i, ret;
+
+       pr_info("%s%s\n", zs_name, zs_version);
+
+       /* Find out how many Z85C30 SCCs we have.  */
+       ret = zs_probe_sccs();
+       if (ret)
+               return ret;
+
+       ret = uart_register_driver(&zs_reg);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < ZS_NUM_SCCS * ZS_NUM_CHAN; i++) {
+               struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN];
+               struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN];
+               struct uart_port *uport = &zport->port;
+
+               if (zport->scc)
+                       uart_add_one_port(&zs_reg, uport);
+       }
+
+       return 0;
+}
+
+static void __exit zs_exit(void)
+{
+       int i;
+
+       for (i = ZS_NUM_SCCS * ZS_NUM_CHAN - 1; i >= 0; i--) {
+               struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN];
+               struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN];
+               struct uart_port *uport = &zport->port;
+
+               if (zport->scc)
+                       uart_remove_one_port(&zs_reg, uport);
+       }
+
+       uart_unregister_driver(&zs_reg);
+}
+
+module_init(zs_init);
+module_exit(zs_exit);
diff --git a/drivers/tty/serial/zs.h b/drivers/tty/serial/zs.h
new file mode 100644 (file)
index 0000000..aa921b5
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * zs.h: Definitions for the DECstation Z85C30 serial driver.
+ *
+ * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
+ * Adapted from drivers/macintosh/macserial.h by Harald Koerfgen.
+ *
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 2004, 2005, 2007  Maciej W. Rozycki
+ */
+#ifndef _SERIAL_ZS_H
+#define _SERIAL_ZS_H
+
+#ifdef __KERNEL__
+
+#define ZS_NUM_REGS 16
+
+/*
+ * This is our internal structure for each serial port's state.
+ */
+struct zs_port {
+       struct zs_scc   *scc;                   /* Containing SCC.  */
+       struct uart_port port;                  /* Underlying UART.  */
+
+       int             clk_mode;               /* May be 1, 16, 32, or 64.  */
+
+       unsigned int    tty_break;              /* Set on BREAK condition.  */
+       int             tx_stopped;             /* Output is suspended.  */
+
+       unsigned int    mctrl;                  /* State of modem lines.  */
+       u8              brk;                    /* BREAK state from RR0.  */
+
+       u8              regs[ZS_NUM_REGS];      /* Channel write registers.  */
+};
+
+/*
+ * Per-SCC state for locking and the interrupt handler.
+ */
+struct zs_scc {
+       struct zs_port  zport[2];
+       spinlock_t      zlock;
+       atomic_t        irq_guard;
+       int             initialised;
+};
+
+#endif /* __KERNEL__ */
+
+/*
+ * Conversion routines to/from brg time constants from/to bits per second.
+ */
+#define ZS_BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define ZS_BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+/*
+ * The Zilog register set.
+ */
+
+/* Write Register 0 (Command) */
+#define R0             0       /* Register selects */
+#define R1             1
+#define R2             2
+#define R3             3
+#define R4             4
+#define R5             5
+#define R6             6
+#define R7             7
+#define R8             8
+#define R9             9
+#define R10            10
+#define R11            11
+#define R12            12
+#define R13            13
+#define R14            14
+#define R15            15
+
+#define NULLCODE       0       /* Null Code */
+#define POINT_HIGH     0x8     /* Select upper half of registers */
+#define RES_EXT_INT    0x10    /* Reset Ext. Status Interrupts */
+#define SEND_ABORT     0x18    /* HDLC Abort */
+#define RES_RxINT_FC   0x20    /* Reset RxINT on First Character */
+#define RES_Tx_P       0x28    /* Reset TxINT Pending */
+#define ERR_RES                0x30    /* Error Reset */
+#define RES_H_IUS      0x38    /* Reset highest IUS */
+
+#define RES_Rx_CRC     0x40    /* Reset Rx CRC Checker */
+#define RES_Tx_CRC     0x80    /* Reset Tx CRC Checker */
+#define RES_EOM_L      0xC0    /* Reset EOM latch */
+
+/* Write Register 1 (Tx/Rx/Ext Int Enable and WAIT/DMA Commands) */
+#define EXT_INT_ENAB   0x1     /* Ext Int Enable */
+#define TxINT_ENAB     0x2     /* Tx Int Enable */
+#define PAR_SPEC       0x4     /* Parity is special condition */
+
+#define RxINT_DISAB    0       /* Rx Int Disable */
+#define RxINT_FCERR    0x8     /* Rx Int on First Character Only or Error */
+#define RxINT_ALL      0x10    /* Int on all Rx Characters or error */
+#define RxINT_ERR      0x18    /* Int on error only */
+#define RxINT_MASK     0x18
+
+#define WT_RDY_RT      0x20    /* Wait/Ready on R/T */
+#define WT_FN_RDYFN    0x40    /* Wait/FN/Ready FN */
+#define WT_RDY_ENAB    0x80    /* Wait/Ready Enable */
+
+/* Write Register 2 (Interrupt Vector) */
+
+/* Write Register 3 (Receive Parameters and Control) */
+#define RxENABLE       0x1     /* Rx Enable */
+#define SYNC_L_INH     0x2     /* Sync Character Load Inhibit */
+#define ADD_SM         0x4     /* Address Search Mode (SDLC) */
+#define RxCRC_ENAB     0x8     /* Rx CRC Enable */
+#define ENT_HM         0x10    /* Enter Hunt Mode */
+#define AUTO_ENAB      0x20    /* Auto Enables */
+#define Rx5            0x0     /* Rx 5 Bits/Character */
+#define Rx7            0x40    /* Rx 7 Bits/Character */
+#define Rx6            0x80    /* Rx 6 Bits/Character */
+#define Rx8            0xc0    /* Rx 8 Bits/Character */
+#define RxNBITS_MASK   0xc0
+
+/* Write Register 4 (Transmit/Receive Miscellaneous Parameters and Modes) */
+#define PAR_ENA                0x1     /* Parity Enable */
+#define PAR_EVEN       0x2     /* Parity Even/Odd* */
+
+#define SYNC_ENAB      0       /* Sync Modes Enable */
+#define SB1            0x4     /* 1 stop bit/char */
+#define SB15           0x8     /* 1.5 stop bits/char */
+#define SB2            0xc     /* 2 stop bits/char */
+#define SB_MASK                0xc
+
+#define MONSYNC                0       /* 8 Bit Sync character */
+#define BISYNC         0x10    /* 16 bit sync character */
+#define SDLC           0x20    /* SDLC Mode (01111110 Sync Flag) */
+#define EXTSYNC                0x30    /* External Sync Mode */
+
+#define X1CLK          0x0     /* x1 clock mode */
+#define X16CLK         0x40    /* x16 clock mode */
+#define X32CLK         0x80    /* x32 clock mode */
+#define X64CLK         0xc0    /* x64 clock mode */
+#define XCLK_MASK      0xc0
+
+/* Write Register 5 (Transmit Parameters and Controls) */
+#define TxCRC_ENAB     0x1     /* Tx CRC Enable */
+#define RTS            0x2     /* RTS */
+#define SDLC_CRC       0x4     /* SDLC/CRC-16 */
+#define TxENAB         0x8     /* Tx Enable */
+#define SND_BRK                0x10    /* Send Break */
+#define Tx5            0x0     /* Tx 5 bits (or less)/character */
+#define Tx7            0x20    /* Tx 7 bits/character */
+#define Tx6            0x40    /* Tx 6 bits/character */
+#define Tx8            0x60    /* Tx 8 bits/character */
+#define TxNBITS_MASK   0x60
+#define DTR            0x80    /* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 8 (Transmit Buffer) */
+
+/* Write Register 9 (Master Interrupt Control) */
+#define VIS            1       /* Vector Includes Status */
+#define NV             2       /* No Vector */
+#define DLC            4       /* Disable Lower Chain */
+#define MIE            8       /* Master Interrupt Enable */
+#define STATHI         0x10    /* Status high */
+#define SOFTACK                0x20    /* Software Interrupt Acknowledge */
+#define NORESET                0       /* No reset on write to R9 */
+#define CHRB           0x40    /* Reset channel B */
+#define CHRA           0x80    /* Reset channel A */
+#define FHWRES         0xc0    /* Force hardware reset */
+
+/* Write Register 10 (Miscellaneous Transmitter/Receiver Control Bits) */
+#define BIT6           1       /* 6 bit/8bit sync */
+#define LOOPMODE       2       /* SDLC Loop mode */
+#define ABUNDER                4       /* Abort/flag on SDLC xmit underrun */
+#define MARKIDLE       8       /* Mark/flag on idle */
+#define GAOP           0x10    /* Go active on poll */
+#define NRZ            0       /* NRZ mode */
+#define NRZI           0x20    /* NRZI mode */
+#define FM1            0x40    /* FM1 (transition = 1) */
+#define FM0            0x60    /* FM0 (transition = 0) */
+#define CRCPS          0x80    /* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode Control) */
+#define TRxCXT         0       /* TRxC = Xtal output */
+#define TRxCTC         1       /* TRxC = Transmit clock */
+#define TRxCBR         2       /* TRxC = BR Generator Output */
+#define TRxCDP         3       /* TRxC = DPLL output */
+#define TRxCOI         4       /* TRxC O/I */
+#define TCRTxCP                0       /* Transmit clock = RTxC pin */
+#define TCTRxCP                8       /* Transmit clock = TRxC pin */
+#define TCBR           0x10    /* Transmit clock = BR Generator output */
+#define TCDPLL         0x18    /* Transmit clock = DPLL output */
+#define RCRTxCP                0       /* Receive clock = RTxC pin */
+#define RCTRxCP                0x20    /* Receive clock = TRxC pin */
+#define RCBR           0x40    /* Receive clock = BR Generator output */
+#define RCDPLL         0x60    /* Receive clock = DPLL output */
+#define RTxCX          0x80    /* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (Lower Byte of Baud Rate Generator Time Constant) */
+
+/* Write Register 13 (Upper Byte of Baud Rate Generator Time Constant) */
+
+/* Write Register 14 (Miscellaneous Control Bits) */
+#define BRENABL                1       /* Baud rate generator enable */
+#define BRSRC          2       /* Baud rate generator source */
+#define DTRREQ         4       /* DTR/Request function */
+#define AUTOECHO       8       /* Auto Echo */
+#define LOOPBAK                0x10    /* Local loopback */
+#define SEARCH         0x20    /* Enter search mode */
+#define RMC            0x40    /* Reset missing clock */
+#define DISDPLL                0x60    /* Disable DPLL */
+#define SSBR           0x80    /* Set DPLL source = BR generator */
+#define SSRTxC         0xa0    /* Set DPLL source = RTxC */
+#define SFMM           0xc0    /* Set FM mode */
+#define SNRZI          0xe0    /* Set NRZI mode */
+
+/* Write Register 15 (External/Status Interrupt Control) */
+#define WR7P_EN                1       /* WR7 Prime SDLC Feature Enable */
+#define ZCIE           2       /* Zero count IE */
+#define DCDIE          8       /* DCD IE */
+#define SYNCIE         0x10    /* Sync/hunt IE */
+#define CTSIE          0x20    /* CTS IE */
+#define TxUIE          0x40    /* Tx Underrun/EOM IE */
+#define BRKIE          0x80    /* Break/Abort IE */
+
+
+/* Read Register 0 (Transmit/Receive Buffer Status and External Status) */
+#define Rx_CH_AV       0x1     /* Rx Character Available */
+#define ZCOUNT         0x2     /* Zero count */
+#define Tx_BUF_EMP     0x4     /* Tx Buffer empty */
+#define DCD            0x8     /* DCD */
+#define SYNC_HUNT      0x10    /* Sync/hunt */
+#define CTS            0x20    /* CTS */
+#define TxEOM          0x40    /* Tx underrun */
+#define BRK_ABRT       0x80    /* Break/Abort */
+
+/* Read Register 1 (Special Receive Condition Status) */
+#define ALL_SNT                0x1     /* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define RES3           0x8     /* 0/3 */
+#define RES4           0x4     /* 0/4 */
+#define RES5           0xc     /* 0/5 */
+#define RES6           0x2     /* 0/6 */
+#define RES7           0xa     /* 0/7 */
+#define RES8           0x6     /* 0/8 */
+#define RES18          0xe     /* 1/8 */
+#define RES28          0x0     /* 2/8 */
+/* Special Rx Condition Interrupts */
+#define PAR_ERR                0x10    /* Parity Error */
+#define Rx_OVR         0x20    /* Rx Overrun Error */
+#define FRM_ERR                0x40    /* CRC/Framing Error */
+#define END_FR         0x80    /* End of Frame (SDLC) */
+
+/* Read Register 2 (Interrupt Vector (WR2) -- channel A).  */
+
+/* Read Register 2 (Modified Interrupt Vector -- channel B).  */
+
+/* Read Register 3 (Interrupt Pending Bits -- channel A only).  */
+#define CHBEXT         0x1     /* Channel B Ext/Stat IP */
+#define CHBTxIP                0x2     /* Channel B Tx IP */
+#define CHBRxIP                0x4     /* Channel B Rx IP */
+#define CHAEXT         0x8     /* Channel A Ext/Stat IP */
+#define CHATxIP                0x10    /* Channel A Tx IP */
+#define CHARxIP                0x20    /* Channel A Rx IP */
+
+/* Read Register 6 (SDLC FIFO Status and Byte Count LSB) */
+
+/* Read Register 7 (SDLC FIFO Status and Byte Count MSB) */
+
+/* Read Register 8 (Receive Data) */
+
+/* Read Register 10 (Miscellaneous Status Bits) */
+#define ONLOOP         2       /* On loop */
+#define LOOPSEND       0x10    /* Loop sending */
+#define CLK2MIS                0x40    /* Two clocks missing */
+#define CLK1MIS                0x80    /* One clock missing */
+
+/* Read Register 12 (Lower Byte of Baud Rate Generator Constant (WR12)) */
+
+/* Read Register 13 (Upper Byte of Baud Rate Generator Constant (WR13) */
+
+/* Read Register 15 (External/Status Interrupt Control (WR15)) */
+
+#endif /* _SERIAL_ZS_H */
This page took 2.426096 seconds and 5 git commands to generate.